diff options
author | HampusM <hampus@hampusmat.com> | 2024-03-06 22:15:33 +0100 |
---|---|---|
committer | HampusM <hampus@hampusmat.com> | 2024-03-06 22:15:41 +0100 |
commit | 251beb34720d2e7d60ceaddc811a65f52f15bdbd (patch) | |
tree | 7342c483661d3dc2f229097a15a41532c333e3c5 /glfw | |
parent | b9668a6ba06af650eab5c77c78a487556af20a6b (diff) |
feat(glfw): add setting key callback
Diffstat (limited to 'glfw')
-rw-r--r-- | glfw/Cargo.toml | 1 | ||||
-rw-r--r-- | glfw/src/util.rs | 31 | ||||
-rw-r--r-- | glfw/src/window.rs | 346 |
3 files changed, 247 insertions, 131 deletions
diff --git a/glfw/Cargo.toml b/glfw/Cargo.toml index 110ed96..b60d245 100644 --- a/glfw/Cargo.toml +++ b/glfw/Cargo.toml @@ -9,6 +9,7 @@ opengl = [] [dependencies] libc = "0.2.148" thiserror = "1.0.49" +bitflags = "2.4.0" [build-dependencies.bindgen] version = "0.68.1" diff --git a/glfw/src/util.rs b/glfw/src/util.rs index f77aaf8..98dcb9b 100644 --- a/glfw/src/util.rs +++ b/glfw/src/util.rs @@ -8,3 +8,34 @@ pub fn is_main_thread() -> bool ttid == pid } + +macro_rules! enum_from_repr { + ( + #[repr($repr: ident)] + $(#[$attr: meta])* + $visibility: vis enum $name: ident + { + $($variant: ident = $raw: path,)* + } + ) => { + $(#[$attr])* + #[repr($repr)] + $visibility enum $name + { + $($variant = $raw,)* + } + + impl $name + { + fn from_repr(repr: $repr) -> Option<Self> + { + match repr { + $($raw => Some(Self::$variant),)* + _ => None + } + } + } + }; +} + +pub(crate) use enum_from_repr; diff --git a/glfw/src/window.rs b/glfw/src/window.rs index 4c7652c..8059cea 100644 --- a/glfw/src/window.rs +++ b/glfw/src/window.rs @@ -1,10 +1,14 @@ use std::cell::RefCell; use std::ffi::{c_int, CString}; use std::hint::unreachable_unchecked; +use std::io::{stdout, Write}; use std::panic::catch_unwind; use std::ptr::null_mut; +use bitflags::bitflags; + use crate::init::{initialize, Glfw}; +use crate::util::enum_from_repr; use crate::{get_glfw_error, Error}; #[derive(Debug)] @@ -129,6 +133,22 @@ impl Window } } + pub fn set_key_callback( + &self, + callback: impl Fn(Key, i32, KeyState, KeyModifiers) + 'static, + ) + { + KEY_CALLBACK.with_borrow_mut(|key_callback| { + *key_callback = Some(Box::new(callback)); + }); + + // SAFETY: The initialize function (called when the window is created) makes sure + // the current thread is the main thread + unsafe { + crate::ffi::glfwSetKeyCallback(self.handle, Some(key_callback)); + } + } + /// Returns the last reported state of a keyboard key. /// /// # Errors @@ -411,138 +431,156 @@ pub enum CursorMode Normal = crate::ffi::GLFW_CURSOR_NORMAL, } -#[derive(Debug, Clone, Copy)] -#[repr(i32)] -pub enum Key -{ - // Unknown = crate::ffi::GLFW_KEY_UNKNOWN, - Space = crate::ffi::GLFW_KEY_SPACE, - Apostrophe = crate::ffi::GLFW_KEY_APOSTROPHE, - Comma = crate::ffi::GLFW_KEY_COMMA, - Minus = crate::ffi::GLFW_KEY_MINUS, - Period = crate::ffi::GLFW_KEY_PERIOD, - Slash = crate::ffi::GLFW_KEY_SLASH, - Digit0 = crate::ffi::GLFW_KEY_0, - Digit1 = crate::ffi::GLFW_KEY_1, - Digit2 = crate::ffi::GLFW_KEY_2, - Digit3 = crate::ffi::GLFW_KEY_3, - Digit4 = crate::ffi::GLFW_KEY_4, - Digit5 = crate::ffi::GLFW_KEY_5, - Digit6 = crate::ffi::GLFW_KEY_6, - Digit7 = crate::ffi::GLFW_KEY_7, - Digit8 = crate::ffi::GLFW_KEY_8, - Digit9 = crate::ffi::GLFW_KEY_9, - Semicolon = crate::ffi::GLFW_KEY_SEMICOLON, - Equal = crate::ffi::GLFW_KEY_EQUAL, - A = crate::ffi::GLFW_KEY_A, - B = crate::ffi::GLFW_KEY_B, - C = crate::ffi::GLFW_KEY_C, - D = crate::ffi::GLFW_KEY_D, - E = crate::ffi::GLFW_KEY_E, - F = crate::ffi::GLFW_KEY_F, - G = crate::ffi::GLFW_KEY_G, - H = crate::ffi::GLFW_KEY_H, - I = crate::ffi::GLFW_KEY_I, - J = crate::ffi::GLFW_KEY_J, - K = crate::ffi::GLFW_KEY_K, - L = crate::ffi::GLFW_KEY_L, - M = crate::ffi::GLFW_KEY_M, - N = crate::ffi::GLFW_KEY_N, - O = crate::ffi::GLFW_KEY_O, - P = crate::ffi::GLFW_KEY_P, - Q = crate::ffi::GLFW_KEY_Q, - R = crate::ffi::GLFW_KEY_R, - S = crate::ffi::GLFW_KEY_S, - T = crate::ffi::GLFW_KEY_T, - U = crate::ffi::GLFW_KEY_U, - V = crate::ffi::GLFW_KEY_V, - W = crate::ffi::GLFW_KEY_W, - X = crate::ffi::GLFW_KEY_X, - Y = crate::ffi::GLFW_KEY_Y, - Z = crate::ffi::GLFW_KEY_Z, - LeftBracket = crate::ffi::GLFW_KEY_LEFT_BRACKET, - Backslash = crate::ffi::GLFW_KEY_BACKSLASH, - RightBracket = crate::ffi::GLFW_KEY_RIGHT_BRACKET, - GraveAccent = crate::ffi::GLFW_KEY_GRAVE_ACCENT, - World1 = crate::ffi::GLFW_KEY_WORLD_1, - World2 = crate::ffi::GLFW_KEY_WORLD_2, - Escape = crate::ffi::GLFW_KEY_ESCAPE, - Enter = crate::ffi::GLFW_KEY_ENTER, - Tab = crate::ffi::GLFW_KEY_TAB, - Backspace = crate::ffi::GLFW_KEY_BACKSPACE, - Insert = crate::ffi::GLFW_KEY_INSERT, - Delete = crate::ffi::GLFW_KEY_DELETE, - Right = crate::ffi::GLFW_KEY_RIGHT, - Left = crate::ffi::GLFW_KEY_LEFT, - Down = crate::ffi::GLFW_KEY_DOWN, - Up = crate::ffi::GLFW_KEY_UP, - PageUp = crate::ffi::GLFW_KEY_PAGE_UP, - PageDown = crate::ffi::GLFW_KEY_PAGE_DOWN, - Home = crate::ffi::GLFW_KEY_HOME, - End = crate::ffi::GLFW_KEY_END, - CapsLock = crate::ffi::GLFW_KEY_CAPS_LOCK, - ScrollLock = crate::ffi::GLFW_KEY_SCROLL_LOCK, - NumLock = crate::ffi::GLFW_KEY_NUM_LOCK, - PrintScreen = crate::ffi::GLFW_KEY_PRINT_SCREEN, - Pause = crate::ffi::GLFW_KEY_PAUSE, - F1 = crate::ffi::GLFW_KEY_F1, - F2 = crate::ffi::GLFW_KEY_F2, - F3 = crate::ffi::GLFW_KEY_F3, - F4 = crate::ffi::GLFW_KEY_F4, - F5 = crate::ffi::GLFW_KEY_F5, - F6 = crate::ffi::GLFW_KEY_F6, - F7 = crate::ffi::GLFW_KEY_F7, - F8 = crate::ffi::GLFW_KEY_F8, - F9 = crate::ffi::GLFW_KEY_F9, - F10 = crate::ffi::GLFW_KEY_F10, - F11 = crate::ffi::GLFW_KEY_F11, - F12 = crate::ffi::GLFW_KEY_F12, - F13 = crate::ffi::GLFW_KEY_F13, - F14 = crate::ffi::GLFW_KEY_F14, - F15 = crate::ffi::GLFW_KEY_F15, - F16 = crate::ffi::GLFW_KEY_F16, - F17 = crate::ffi::GLFW_KEY_F17, - F18 = crate::ffi::GLFW_KEY_F18, - F19 = crate::ffi::GLFW_KEY_F19, - F20 = crate::ffi::GLFW_KEY_F20, - F21 = crate::ffi::GLFW_KEY_F21, - F22 = crate::ffi::GLFW_KEY_F22, - F23 = crate::ffi::GLFW_KEY_F23, - F24 = crate::ffi::GLFW_KEY_F24, - F25 = crate::ffi::GLFW_KEY_F25, - Kp0 = crate::ffi::GLFW_KEY_KP_0, - Kp1 = crate::ffi::GLFW_KEY_KP_1, - Kp2 = crate::ffi::GLFW_KEY_KP_2, - Kp3 = crate::ffi::GLFW_KEY_KP_3, - Kp4 = crate::ffi::GLFW_KEY_KP_4, - Kp5 = crate::ffi::GLFW_KEY_KP_5, - Kp6 = crate::ffi::GLFW_KEY_KP_6, - Kp7 = crate::ffi::GLFW_KEY_KP_7, - Kp8 = crate::ffi::GLFW_KEY_KP_8, - Kp9 = crate::ffi::GLFW_KEY_KP_9, - KpDecimal = crate::ffi::GLFW_KEY_KP_DECIMAL, - KpDivide = crate::ffi::GLFW_KEY_KP_DIVIDE, - KpMultiply = crate::ffi::GLFW_KEY_KP_MULTIPLY, - KpSubtract = crate::ffi::GLFW_KEY_KP_SUBTRACT, - KpAdd = crate::ffi::GLFW_KEY_KP_ADD, - KpEnter = crate::ffi::GLFW_KEY_KP_ENTER, - KpEqual = crate::ffi::GLFW_KEY_KP_EQUAL, - LeftShift = crate::ffi::GLFW_KEY_LEFT_SHIFT, - LeftControl = crate::ffi::GLFW_KEY_LEFT_CONTROL, - LeftAlt = crate::ffi::GLFW_KEY_LEFT_ALT, - LeftSuper = crate::ffi::GLFW_KEY_LEFT_SUPER, - RightShift = crate::ffi::GLFW_KEY_RIGHT_SHIFT, - RightControl = crate::ffi::GLFW_KEY_RIGHT_CONTROL, - RightAlt = crate::ffi::GLFW_KEY_RIGHT_ALT, - RightSuper = crate::ffi::GLFW_KEY_RIGHT_SUPER, - Menu = crate::ffi::GLFW_KEY_MENU, -} +enum_from_repr!( + #[repr(i32)] + #[derive(Debug, Clone, Copy)] + pub enum Key + { + // Unknown = crate::ffi::GLFW_KEY_UNKNOWN, + Space = crate::ffi::GLFW_KEY_SPACE, + Apostrophe = crate::ffi::GLFW_KEY_APOSTROPHE, + Comma = crate::ffi::GLFW_KEY_COMMA, + Minus = crate::ffi::GLFW_KEY_MINUS, + Period = crate::ffi::GLFW_KEY_PERIOD, + Slash = crate::ffi::GLFW_KEY_SLASH, + Digit0 = crate::ffi::GLFW_KEY_0, + Digit1 = crate::ffi::GLFW_KEY_1, + Digit2 = crate::ffi::GLFW_KEY_2, + Digit3 = crate::ffi::GLFW_KEY_3, + Digit4 = crate::ffi::GLFW_KEY_4, + Digit5 = crate::ffi::GLFW_KEY_5, + Digit6 = crate::ffi::GLFW_KEY_6, + Digit7 = crate::ffi::GLFW_KEY_7, + Digit8 = crate::ffi::GLFW_KEY_8, + Digit9 = crate::ffi::GLFW_KEY_9, + Semicolon = crate::ffi::GLFW_KEY_SEMICOLON, + Equal = crate::ffi::GLFW_KEY_EQUAL, + A = crate::ffi::GLFW_KEY_A, + B = crate::ffi::GLFW_KEY_B, + C = crate::ffi::GLFW_KEY_C, + D = crate::ffi::GLFW_KEY_D, + E = crate::ffi::GLFW_KEY_E, + F = crate::ffi::GLFW_KEY_F, + G = crate::ffi::GLFW_KEY_G, + H = crate::ffi::GLFW_KEY_H, + I = crate::ffi::GLFW_KEY_I, + J = crate::ffi::GLFW_KEY_J, + K = crate::ffi::GLFW_KEY_K, + L = crate::ffi::GLFW_KEY_L, + M = crate::ffi::GLFW_KEY_M, + N = crate::ffi::GLFW_KEY_N, + O = crate::ffi::GLFW_KEY_O, + P = crate::ffi::GLFW_KEY_P, + Q = crate::ffi::GLFW_KEY_Q, + R = crate::ffi::GLFW_KEY_R, + S = crate::ffi::GLFW_KEY_S, + T = crate::ffi::GLFW_KEY_T, + U = crate::ffi::GLFW_KEY_U, + V = crate::ffi::GLFW_KEY_V, + W = crate::ffi::GLFW_KEY_W, + X = crate::ffi::GLFW_KEY_X, + Y = crate::ffi::GLFW_KEY_Y, + Z = crate::ffi::GLFW_KEY_Z, + LeftBracket = crate::ffi::GLFW_KEY_LEFT_BRACKET, + Backslash = crate::ffi::GLFW_KEY_BACKSLASH, + RightBracket = crate::ffi::GLFW_KEY_RIGHT_BRACKET, + GraveAccent = crate::ffi::GLFW_KEY_GRAVE_ACCENT, + World1 = crate::ffi::GLFW_KEY_WORLD_1, + World2 = crate::ffi::GLFW_KEY_WORLD_2, + Escape = crate::ffi::GLFW_KEY_ESCAPE, + Enter = crate::ffi::GLFW_KEY_ENTER, + Tab = crate::ffi::GLFW_KEY_TAB, + Backspace = crate::ffi::GLFW_KEY_BACKSPACE, + Insert = crate::ffi::GLFW_KEY_INSERT, + Delete = crate::ffi::GLFW_KEY_DELETE, + Right = crate::ffi::GLFW_KEY_RIGHT, + Left = crate::ffi::GLFW_KEY_LEFT, + Down = crate::ffi::GLFW_KEY_DOWN, + Up = crate::ffi::GLFW_KEY_UP, + PageUp = crate::ffi::GLFW_KEY_PAGE_UP, + PageDown = crate::ffi::GLFW_KEY_PAGE_DOWN, + Home = crate::ffi::GLFW_KEY_HOME, + End = crate::ffi::GLFW_KEY_END, + CapsLock = crate::ffi::GLFW_KEY_CAPS_LOCK, + ScrollLock = crate::ffi::GLFW_KEY_SCROLL_LOCK, + NumLock = crate::ffi::GLFW_KEY_NUM_LOCK, + PrintScreen = crate::ffi::GLFW_KEY_PRINT_SCREEN, + Pause = crate::ffi::GLFW_KEY_PAUSE, + F1 = crate::ffi::GLFW_KEY_F1, + F2 = crate::ffi::GLFW_KEY_F2, + F3 = crate::ffi::GLFW_KEY_F3, + F4 = crate::ffi::GLFW_KEY_F4, + F5 = crate::ffi::GLFW_KEY_F5, + F6 = crate::ffi::GLFW_KEY_F6, + F7 = crate::ffi::GLFW_KEY_F7, + F8 = crate::ffi::GLFW_KEY_F8, + F9 = crate::ffi::GLFW_KEY_F9, + F10 = crate::ffi::GLFW_KEY_F10, + F11 = crate::ffi::GLFW_KEY_F11, + F12 = crate::ffi::GLFW_KEY_F12, + F13 = crate::ffi::GLFW_KEY_F13, + F14 = crate::ffi::GLFW_KEY_F14, + F15 = crate::ffi::GLFW_KEY_F15, + F16 = crate::ffi::GLFW_KEY_F16, + F17 = crate::ffi::GLFW_KEY_F17, + F18 = crate::ffi::GLFW_KEY_F18, + F19 = crate::ffi::GLFW_KEY_F19, + F20 = crate::ffi::GLFW_KEY_F20, + F21 = crate::ffi::GLFW_KEY_F21, + F22 = crate::ffi::GLFW_KEY_F22, + F23 = crate::ffi::GLFW_KEY_F23, + F24 = crate::ffi::GLFW_KEY_F24, + F25 = crate::ffi::GLFW_KEY_F25, + Kp0 = crate::ffi::GLFW_KEY_KP_0, + Kp1 = crate::ffi::GLFW_KEY_KP_1, + Kp2 = crate::ffi::GLFW_KEY_KP_2, + Kp3 = crate::ffi::GLFW_KEY_KP_3, + Kp4 = crate::ffi::GLFW_KEY_KP_4, + Kp5 = crate::ffi::GLFW_KEY_KP_5, + Kp6 = crate::ffi::GLFW_KEY_KP_6, + Kp7 = crate::ffi::GLFW_KEY_KP_7, + Kp8 = crate::ffi::GLFW_KEY_KP_8, + Kp9 = crate::ffi::GLFW_KEY_KP_9, + KpDecimal = crate::ffi::GLFW_KEY_KP_DECIMAL, + KpDivide = crate::ffi::GLFW_KEY_KP_DIVIDE, + KpMultiply = crate::ffi::GLFW_KEY_KP_MULTIPLY, + KpSubtract = crate::ffi::GLFW_KEY_KP_SUBTRACT, + KpAdd = crate::ffi::GLFW_KEY_KP_ADD, + KpEnter = crate::ffi::GLFW_KEY_KP_ENTER, + KpEqual = crate::ffi::GLFW_KEY_KP_EQUAL, + LeftShift = crate::ffi::GLFW_KEY_LEFT_SHIFT, + LeftControl = crate::ffi::GLFW_KEY_LEFT_CONTROL, + LeftAlt = crate::ffi::GLFW_KEY_LEFT_ALT, + LeftSuper = crate::ffi::GLFW_KEY_LEFT_SUPER, + RightShift = crate::ffi::GLFW_KEY_RIGHT_SHIFT, + RightControl = crate::ffi::GLFW_KEY_RIGHT_CONTROL, + RightAlt = crate::ffi::GLFW_KEY_RIGHT_ALT, + RightSuper = crate::ffi::GLFW_KEY_RIGHT_SUPER, + Menu = crate::ffi::GLFW_KEY_MENU, + } +); -#[derive(Debug, Clone, Copy)] -pub enum KeyState -{ - Pressed, - Released, +enum_from_repr!( + #[repr(i32)] + #[derive(Debug, Clone, Copy)] + pub enum KeyState + { + Pressed = crate::ffi::GLFW_PRESS, + Released = crate::ffi::GLFW_RELEASE, + Repeat = crate::ffi::GLFW_REPEAT, + } +); + +bitflags! { + #[derive(Debug, Clone, Copy)] + pub struct KeyModifiers: i32 { + const SHIFT = crate::ffi::GLFW_MOD_SHIFT; + const CONTROL = crate::ffi::GLFW_MOD_CONTROL; + const ALT = crate::ffi::GLFW_MOD_ALT; + const SUPER = crate::ffi::GLFW_MOD_SUPER; + const CAPS_LOCK = crate::ffi::GLFW_MOD_CAPS_LOCK; + const NUM_LOCK = crate::ffi::GLFW_MOD_NUM_LOCK; + } } #[derive(Debug, Clone, Copy)] @@ -594,9 +632,11 @@ pub struct CursorPosition } type FramebufferSizeCb = Box<dyn Fn(Size)>; +type KeyCallback = Box<dyn Fn(Key, i32, KeyState, KeyModifiers)>; thread_local! { static FRAMEBUFFER_SIZE_CB: RefCell<Option<FramebufferSizeCb>> = RefCell::new(None); +static KEY_CALLBACK: RefCell<Option<KeyCallback>> = RefCell::new(None); } extern "C" fn framebuffer_size_callback( @@ -624,3 +664,47 @@ extern "C" fn framebuffer_size_callback( println!("ERROR: Panic in framebuffer size callback"); } } + +extern "C" fn key_callback( + _window: *mut crate::ffi::GLFWwindow, + key_raw: c_int, + scancode: c_int, + action_raw: c_int, + mods: c_int, +) +{ + let Some(key) = Key::from_repr(key_raw) else { + write!(stdout(), "Unknown key {key_raw}").ok(); + return; + }; + + let Some(key_state) = KeyState::from_repr(action_raw) else { + write!(stdout(), "Unknown key state {action_raw}").ok(); + return; + }; + + let Some(key_modifiers) = KeyModifiers::from_bits(mods) else { + write!( + stdout(), + "Key modifiers {action_raw} contain one or more unknown bit(s)" + ) + .ok(); + + return; + }; + + // Unwinds are catched because unwinding from Rust code into foreign code is UB. + let res = catch_unwind(|| { + KEY_CALLBACK + .try_with(|key_callback| { + if let Some(cb) = key_callback.borrow().as_deref() { + cb(key, scancode, key_state, key_modifiers); + } + }) + .ok(); + }); + + if res.is_err() { + write!(stdout(), "ERROR: Panic in key callback").ok(); + } +} |