summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Cargo.lock1
-rw-r--r--glfw/Cargo.toml1
-rw-r--r--glfw/src/util.rs31
-rw-r--r--glfw/src/window.rs346
4 files changed, 248 insertions, 131 deletions
diff --git a/Cargo.lock b/Cargo.lock
index a14cfe5..d0f7732 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -204,6 +204,7 @@ name = "glfw"
version = "0.1.0"
dependencies = [
"bindgen",
+ "bitflags 2.4.0",
"libc",
"thiserror",
]
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();
+ }
+}