diff --git a/glfw/src/Window.zig b/glfw/src/Window.zig index 1d211702..45124b70 100644 --- a/glfw/src/Window.zig +++ b/glfw/src/Window.zig @@ -10,6 +10,7 @@ const getError = @import("errors.zig").getError; const Image = @import("Image.zig"); const Monitor = @import("Monitor.zig"); const Cursor = @import("Cursor.zig"); +const Key = @import("key.zig").Key; const Window = @This(); @@ -1405,8 +1406,8 @@ pub inline fn setInputMode(self: Window, mode: isize, value: anytype) Error!void /// @thread_safety This function must only be called from the main thread. /// /// see also: input_key -pub inline fn getKey(self: Window, key: isize) Error!bool { - const state = c.glfwGetKey(self.handle, @intCast(c_int, key)); +pub inline fn getKey(self: Window, key: Key) Error!bool { + const state = c.glfwGetKey(self.handle, @enumToInt(key)); try getError(); return state == c.GLFW_PRESS; } @@ -2608,7 +2609,7 @@ test "getKey" { }; defer window.destroy(); - _ = try window.getKey(glfw.key.escape); + _ = try window.getKey(glfw.Key.escape); } test "getMouseButton" { diff --git a/glfw/src/key.zig b/glfw/src/key.zig index f76172c2..80c70f85 100644 --- a/glfw/src/key.zig +++ b/glfw/src/key.zig @@ -20,224 +20,231 @@ const cc = @import("c.zig").c; const Error = @import("errors.zig").Error; const getError = @import("errors.zig").getError; -/// The unknown key -pub const unknown = cc.GLFW_KEY_UNKNOWN; +/// enum containing all glfw keys +pub const Key = enum(c_int) { + /// The unknown key + unknown = cc.GLFW_KEY_UNKNOWN, -/// Printable keys -pub const space = cc.GLFW_KEY_SPACE; -pub const apostrophe = cc.GLFW_KEY_APOSTROPHE; -pub const comma = cc.GLFW_KEY_COMMA; -pub const minus = cc.GLFW_KEY_MINUS; -pub const period = cc.GLFW_KEY_PERIOD; -pub const slash = cc.GLFW_KEY_SLASH; -pub const zero = cc.GLFW_KEY_0; -pub const one = cc.GLFW_KEY_1; -pub const two = cc.GLFW_KEY_2; -pub const three = cc.GLFW_KEY_3; -pub const four = cc.GLFW_KEY_4; -pub const five = cc.GLFW_KEY_5; -pub const six = cc.GLFW_KEY_6; -pub const seven = cc.GLFW_KEY_7; -pub const eight = cc.GLFW_KEY_8; -pub const nine = cc.GLFW_KEY_9; -pub const semicolon = cc.GLFW_KEY_SEMICOLON; -pub const equal = cc.GLFW_KEY_EQUAL; -pub const a = cc.GLFW_KEY_A; -pub const b = cc.GLFW_KEY_B; -pub const c = cc.GLFW_KEY_C; -pub const d = cc.GLFW_KEY_D; -pub const e = cc.GLFW_KEY_E; -pub const f = cc.GLFW_KEY_F; -pub const g = cc.GLFW_KEY_G; -pub const h = cc.GLFW_KEY_H; -pub const i = cc.GLFW_KEY_I; -pub const j = cc.GLFW_KEY_J; -pub const k = cc.GLFW_KEY_K; -pub const l = cc.GLFW_KEY_L; -pub const m = cc.GLFW_KEY_M; -pub const n = cc.GLFW_KEY_N; -pub const o = cc.GLFW_KEY_O; -pub const p = cc.GLFW_KEY_P; -pub const q = cc.GLFW_KEY_Q; -pub const r = cc.GLFW_KEY_R; -pub const s = cc.GLFW_KEY_S; -pub const t = cc.GLFW_KEY_T; -pub const u = cc.GLFW_KEY_U; -pub const v = cc.GLFW_KEY_V; -pub const w = cc.GLFW_KEY_W; -pub const x = cc.GLFW_KEY_X; -pub const y = cc.GLFW_KEY_Y; -pub const z = cc.GLFW_KEY_Z; -pub const left_bracket = cc.GLFW_KEY_LEFT_BRACKET; -pub const backslash = cc.GLFW_KEY_BACKSLASH; -pub const right_bracket = cc.GLFW_KEY_RIGHT_BRACKET; -pub const grave_accent = cc.GLFW_KEY_GRAVE_ACCENT; -pub const world_1 = cc.GLFW_KEY_WORLD_1; // non-US #1 -pub const world_2 = cc.GLFW_KEY_WORLD_2; // non-US #2 + /// Printable keys + space = cc.GLFW_KEY_SPACE, + apostrophe = cc.GLFW_KEY_APOSTROPHE, + comma = cc.GLFW_KEY_COMMA, + minus = cc.GLFW_KEY_MINUS, + period = cc.GLFW_KEY_PERIOD, + slash = cc.GLFW_KEY_SLASH, + zero = cc.GLFW_KEY_0, + one = cc.GLFW_KEY_1, + two = cc.GLFW_KEY_2, + three = cc.GLFW_KEY_3, + four = cc.GLFW_KEY_4, + five = cc.GLFW_KEY_5, + six = cc.GLFW_KEY_6, + seven = cc.GLFW_KEY_7, + eight = cc.GLFW_KEY_8, + nine = cc.GLFW_KEY_9, + semicolon = cc.GLFW_KEY_SEMICOLON, + equal = cc.GLFW_KEY_EQUAL, + a = cc.GLFW_KEY_A, + b = cc.GLFW_KEY_B, + c = cc.GLFW_KEY_C, + d = cc.GLFW_KEY_D, + e = cc.GLFW_KEY_E, + f = cc.GLFW_KEY_F, + g = cc.GLFW_KEY_G, + h = cc.GLFW_KEY_H, + i = cc.GLFW_KEY_I, + j = cc.GLFW_KEY_J, + k = cc.GLFW_KEY_K, + l = cc.GLFW_KEY_L, + m = cc.GLFW_KEY_M, + n = cc.GLFW_KEY_N, + o = cc.GLFW_KEY_O, + p = cc.GLFW_KEY_P, + q = cc.GLFW_KEY_Q, + r = cc.GLFW_KEY_R, + s = cc.GLFW_KEY_S, + t = cc.GLFW_KEY_T, + u = cc.GLFW_KEY_U, + v = cc.GLFW_KEY_V, + w = cc.GLFW_KEY_W, + x = cc.GLFW_KEY_X, + y = cc.GLFW_KEY_Y, + z = cc.GLFW_KEY_Z, + left_bracket = cc.GLFW_KEY_LEFT_BRACKET, + backslash = cc.GLFW_KEY_BACKSLASH, + right_bracket = cc.GLFW_KEY_RIGHT_BRACKET, + grave_accent = cc.GLFW_KEY_GRAVE_ACCENT, + world_1 = cc.GLFW_KEY_WORLD_1, // non-US #1 + world_2 = cc.GLFW_KEY_WORLD_2, // non-US #2 -/// Function keys -pub const escape = cc.GLFW_KEY_ESCAPE; -pub const enter = cc.GLFW_KEY_ENTER; -pub const tab = cc.GLFW_KEY_TAB; -pub const backspace = cc.GLFW_KEY_BACKSPACE; -pub const insert = cc.GLFW_KEY_INSERT; -pub const delete = cc.GLFW_KEY_DELETE; -pub const right = cc.GLFW_KEY_RIGHT; -pub const left = cc.GLFW_KEY_LEFT; -pub const down = cc.GLFW_KEY_DOWN; -pub const up = cc.GLFW_KEY_UP; -pub const page_up = cc.GLFW_KEY_PAGE_UP; -pub const page_down = cc.GLFW_KEY_PAGE_DOWN; -pub const home = cc.GLFW_KEY_HOME; -pub const end = cc.GLFW_KEY_END; -pub const caps_lock = cc.GLFW_KEY_CAPS_LOCK; -pub const scroll_lock = cc.GLFW_KEY_SCROLL_LOCK; -pub const num_lock = cc.GLFW_KEY_NUM_LOCK; -pub const print_screen = cc.GLFW_KEY_PRINT_SCREEN; -pub const pause = cc.GLFW_KEY_PAUSE; -pub const F1 = cc.GLFW_KEY_F1; -pub const F2 = cc.GLFW_KEY_F2; -pub const F3 = cc.GLFW_KEY_F3; -pub const F4 = cc.GLFW_KEY_F4; -pub const F5 = cc.GLFW_KEY_F5; -pub const F6 = cc.GLFW_KEY_F6; -pub const F7 = cc.GLFW_KEY_F7; -pub const F8 = cc.GLFW_KEY_F8; -pub const F9 = cc.GLFW_KEY_F9; -pub const F10 = cc.GLFW_KEY_F10; -pub const F11 = cc.GLFW_KEY_F11; -pub const F12 = cc.GLFW_KEY_F12; -pub const F13 = cc.GLFW_KEY_F13; -pub const F14 = cc.GLFW_KEY_F14; -pub const F15 = cc.GLFW_KEY_F15; -pub const F16 = cc.GLFW_KEY_F16; -pub const F17 = cc.GLFW_KEY_F17; -pub const F18 = cc.GLFW_KEY_F18; -pub const F19 = cc.GLFW_KEY_F19; -pub const F20 = cc.GLFW_KEY_F20; -pub const F21 = cc.GLFW_KEY_F21; -pub const F22 = cc.GLFW_KEY_F22; -pub const F23 = cc.GLFW_KEY_F23; -pub const F24 = cc.GLFW_KEY_F24; -pub const F25 = cc.GLFW_KEY_F25; -pub const kp_0 = cc.GLFW_KEY_KP_0; -pub const kp_1 = cc.GLFW_KEY_KP_1; -pub const kp_2 = cc.GLFW_KEY_KP_2; -pub const kp_3 = cc.GLFW_KEY_KP_3; -pub const kp_4 = cc.GLFW_KEY_KP_4; -pub const kp_5 = cc.GLFW_KEY_KP_5; -pub const kp_6 = cc.GLFW_KEY_KP_6; -pub const kp_7 = cc.GLFW_KEY_KP_7; -pub const kp_8 = cc.GLFW_KEY_KP_8; -pub const kp_9 = cc.GLFW_KEY_KP_9; -pub const kp_decimal = cc.GLFW_KEY_KP_DECIMAL; -pub const kp_divide = cc.GLFW_KEY_KP_DIVIDE; -pub const kp_multiply = cc.GLFW_KEY_KP_MULTIPLY; -pub const kp_subtract = cc.GLFW_KEY_KP_SUBTRACT; -pub const kp_add = cc.GLFW_KEY_KP_ADD; -pub const kp_enter = cc.GLFW_KEY_KP_ENTER; -pub const kp_equal = cc.GLFW_KEY_KP_EQUAL; -pub const left_shift = cc.GLFW_KEY_LEFT_SHIFT; -pub const left_control = cc.GLFW_KEY_LEFT_CONTROL; -pub const left_alt = cc.GLFW_KEY_LEFT_ALT; -pub const left_super = cc.GLFW_KEY_LEFT_SUPER; -pub const right_shift = cc.GLFW_KEY_RIGHT_SHIFT; -pub const right_control = cc.GLFW_KEY_RIGHT_CONTROL; -pub const right_alt = cc.GLFW_KEY_RIGHT_ALT; -pub const right_super = cc.GLFW_KEY_RIGHT_SUPER; -pub const menu = cc.GLFW_KEY_MENU; + // Function keys + escape = cc.GLFW_KEY_ESCAPE, + enter = cc.GLFW_KEY_ENTER, + tab = cc.GLFW_KEY_TAB, + backspace = cc.GLFW_KEY_BACKSPACE, + insert = cc.GLFW_KEY_INSERT, + delete = cc.GLFW_KEY_DELETE, + right = cc.GLFW_KEY_RIGHT, + left = cc.GLFW_KEY_LEFT, + down = cc.GLFW_KEY_DOWN, + up = cc.GLFW_KEY_UP, + page_up = cc.GLFW_KEY_PAGE_UP, + page_down = cc.GLFW_KEY_PAGE_DOWN, + home = cc.GLFW_KEY_HOME, + end = cc.GLFW_KEY_END, + caps_lock = cc.GLFW_KEY_CAPS_LOCK, + scroll_lock = cc.GLFW_KEY_SCROLL_LOCK, + num_lock = cc.GLFW_KEY_NUM_LOCK, + print_screen = cc.GLFW_KEY_PRINT_SCREEN, + pause = cc.GLFW_KEY_PAUSE, + F1 = cc.GLFW_KEY_F1, + F2 = cc.GLFW_KEY_F2, + F3 = cc.GLFW_KEY_F3, + F4 = cc.GLFW_KEY_F4, + F5 = cc.GLFW_KEY_F5, + F6 = cc.GLFW_KEY_F6, + F7 = cc.GLFW_KEY_F7, + F8 = cc.GLFW_KEY_F8, + F9 = cc.GLFW_KEY_F9, + F10 = cc.GLFW_KEY_F10, + F11 = cc.GLFW_KEY_F11, + F12 = cc.GLFW_KEY_F12, + F13 = cc.GLFW_KEY_F13, + F14 = cc.GLFW_KEY_F14, + F15 = cc.GLFW_KEY_F15, + F16 = cc.GLFW_KEY_F16, + F17 = cc.GLFW_KEY_F17, + F18 = cc.GLFW_KEY_F18, + F19 = cc.GLFW_KEY_F19, + F20 = cc.GLFW_KEY_F20, + F21 = cc.GLFW_KEY_F21, + F22 = cc.GLFW_KEY_F22, + F23 = cc.GLFW_KEY_F23, + F24 = cc.GLFW_KEY_F24, + F25 = cc.GLFW_KEY_F25, + kp_0 = cc.GLFW_KEY_KP_0, + kp_1 = cc.GLFW_KEY_KP_1, + kp_2 = cc.GLFW_KEY_KP_2, + kp_3 = cc.GLFW_KEY_KP_3, + kp_4 = cc.GLFW_KEY_KP_4, + kp_5 = cc.GLFW_KEY_KP_5, + kp_6 = cc.GLFW_KEY_KP_6, + kp_7 = cc.GLFW_KEY_KP_7, + kp_8 = cc.GLFW_KEY_KP_8, + kp_9 = cc.GLFW_KEY_KP_9, + kp_decimal = cc.GLFW_KEY_KP_DECIMAL, + kp_divide = cc.GLFW_KEY_KP_DIVIDE, + kp_multiply = cc.GLFW_KEY_KP_MULTIPLY, + kp_subtract = cc.GLFW_KEY_KP_SUBTRACT, + kp_add = cc.GLFW_KEY_KP_ADD, + kp_enter = cc.GLFW_KEY_KP_ENTER, + kp_equal = cc.GLFW_KEY_KP_EQUAL, + left_shift = cc.GLFW_KEY_LEFT_SHIFT, + left_control = cc.GLFW_KEY_LEFT_CONTROL, + left_alt = cc.GLFW_KEY_LEFT_ALT, + left_super = cc.GLFW_KEY_LEFT_SUPER, + right_shift = cc.GLFW_KEY_RIGHT_SHIFT, + right_control = cc.GLFW_KEY_RIGHT_CONTROL, + right_alt = cc.GLFW_KEY_RIGHT_ALT, + right_super = cc.GLFW_KEY_RIGHT_SUPER, + menu = cc.GLFW_KEY_MENU, -pub const last = cc.GLFW_KEY_LAST; + pub inline fn last() Key { + return @intToEnum(Key, cc.GLFW_KEY_LAST); + } -/// Returns the layout-specific name of the specified printable key. -/// -/// This function returns the name of the specified printable key, encoded as UTF-8. This is -/// typically the character that key would produce without any modifier keys, intended for -/// displaying key bindings to the user. For dead keys, it is typically the diacritic it would add -/// to a character. -/// -/// __Do not use this function__ for text input (see input_char). You will break text input for many -/// languages even if it happens to work for yours. -/// -/// If the key is `glfw.key.unknown`, the scancode is used to identify the key, otherwise the -/// scancode is ignored. If you specify a non-printable key, or `glfw.key.unknown` and a scancode -/// that maps to a non-printable key, this function returns null but does not emit an error. -/// -/// This behavior allows you to always pass in the arguments in the key callback (see input_key) -/// without modification. -/// -/// The printable keys are: -/// -/// - `glfw.key.apostrophe` -/// - `glfw.key.comma` -/// - `glfw.key.minus` -/// - `glfw.key.period` -/// - `glfw.key.slash` -/// - `glfw.key.semicolon` -/// - `glfw.key.equal` -/// - `glfw.key.left_bracket` -/// - `glfw.key.right_bracket` -/// - `glfw.key.backslash` -/// - `glfw.key.world_1` -/// - `glfw.key.world_2` -/// - `glfw.key.0` to `glfw.key.9` -/// - `glfw.key.a` to `glfw.key.z` -/// - `glfw.key.kp_0` to `glfw.key.kp_9` -/// - `glfw.key.kp_decimal` -/// - `glfw.key.kp_divide` -/// - `glfw.key.kp_multiply` -/// - `glfw.key.kp_subtract` -/// - `glfw.key.kp_add` -/// - `glfw.key.kp_equal` -/// -/// Names for printable keys depend on keyboard layout, while names for non-printable keys are the -/// same across layouts but depend on the application language and should be localized along with -/// other user interface text. -/// -/// @param[in] key The key to query, or `glfw.key.unknown`. -/// @param[in] scancode The scancode of the key to query. -/// @return The UTF-8 encoded, layout-specific name of the key, or null. -/// -/// Possible errors include glfw.Error.NotInitialized and glfw.Error.PlatformError. -/// -/// The contents of the returned string may change when a keyboard layout change event is received. -/// -/// @pointer_lifetime The returned string is allocated and freed by GLFW. You should not free it -/// yourself. It is valid until the library is terminated. -/// -/// @thread_safety This function must only be called from the main thread. -/// -/// see also: input_key_name -pub inline fn getName(key: isize, scancode: isize) Error![*c]const u8 { - const name = cc.glfwGetKeyName(@intCast(c_int, key), @intCast(c_int, scancode)); - try getError(); - return name; -} + + /// Returns the layout-specific name of the specified printable key. + /// + /// This function returns the name of the specified printable key, encoded as UTF-8. This is + /// typically the character that key would produce without any modifier keys, intended for + /// displaying key bindings to the user. For dead keys, it is typically the diacritic it would add + /// to a character. + /// + /// __Do not use this function__ for text input (see input_char). You will break text input for many + /// languages even if it happens to work for yours. + /// + /// If the key is `glfw.key.unknown`, the scancode is used to identify the key, otherwise the + /// scancode is ignored. If you specify a non-printable key, or `glfw.key.unknown` and a scancode + /// that maps to a non-printable key, this function returns null but does not emit an error. + /// + /// This behavior allows you to always pass in the arguments in the key callback (see input_key) + /// without modification. + /// + /// The printable keys are: + /// + /// - `glfw.Key.apostrophe` + /// - `glfw.Key.comma` + /// - `glfw.Key.minus` + /// - `glfw.Key.period` + /// - `glfw.Key.slash` + /// - `glfw.Key.semicolon` + /// - `glfw.Key.equal` + /// - `glfw.Key.left_bracket` + /// - `glfw.Key.right_bracket` + /// - `glfw.Key.backslash` + /// - `glfw.Key.world_1` + /// - `glfw.Key.world_2` + /// - `glfw.Key.0` to `glfw.key.9` + /// - `glfw.Key.a` to `glfw.key.z` + /// - `glfw.Key.kp_0` to `glfw.key.kp_9` + /// - `glfw.Key.kp_decimal` + /// - `glfw.Key.kp_divide` + /// - `glfw.Key.kp_multiply` + /// - `glfw.Key.kp_subtract` + /// - `glfw.Key.kp_add` + /// - `glfw.Key.kp_equal` + /// + /// Names for printable keys depend on keyboard layout, while names for non-printable keys are the + /// same across layouts but depend on the application language and should be localized along with + /// other user interface text. + /// + /// @param[in] key The key to query, or `glfw.key.unknown`. + /// @param[in] scancode The scancode of the key to query. + /// @return The UTF-8 encoded, layout-specific name of the key, or null. + /// + /// Possible errors include glfw.Error.NotInitialized and glfw.Error.PlatformError. + /// + /// The contents of the returned string may change when a keyboard layout change event is received. + /// + /// @pointer_lifetime The returned string is allocated and freed by GLFW. You should not free it + /// yourself. It is valid until the library is terminated. + /// + /// @thread_safety This function must only be called from the main thread. + /// + /// see also: input_key_name + pub inline fn getName(self: Key, scancode: isize) Error![*c]const u8 { + const name = cc.glfwGetKeyName(@enumToInt(self), @intCast(c_int, scancode)); + try getError(); + return name; + } + + /// Returns the platform-specific scancode of the specified key. + /// + /// This function returns the platform-specific scancode of the specified key. + /// + /// If the key is `glfw.key.UNKNOWN` or does not exist on the keyboard this method will return `-1`. + /// + /// @param[in] key Any named key (see keys). + /// @return The platform-specific scancode for the key. + /// + /// Possible errors include glfw.Error.NotInitialized, glfw.Error.InvalidEnum and glfw.Error.PlatformError. + /// + /// @thread_safety This function may be called from any thread. + pub inline fn getScancode(self: Key) Error!isize { + const scancode = cc.glfwGetKeyScancode(@enumToInt(self)); + try getError(); + return scancode; + } +}; -/// Returns the platform-specific scancode of the specified key. -/// -/// This function returns the platform-specific scancode of the specified key. -/// -/// If the key is `glfw.key.UNKNOWN` or does not exist on the keyboard this method will return `-1`. -/// -/// @param[in] key Any named key (see keys). -/// @return The platform-specific scancode for the key. -/// -/// Possible errors include glfw.Error.NotInitialized, glfw.Error.InvalidEnum and glfw.Error.PlatformError. -/// -/// @thread_safety This function may be called from any thread. -pub inline fn getScancode(key: isize) Error!isize { - const scancode = cc.glfwGetKeyScancode(@intCast(c_int, key)); - try getError(); - return scancode; -} test "getName" { - const glfw = @import("main.zig"); + const glfw = @import("main.zig"); try glfw.init(); defer glfw.terminate(); - _ = glfw.key.getName(glfw.key.a, 0) catch |err| std.debug.print("failed to get key name, not supported? error={}\n", .{err}); + _ = glfw.Key.a.getName(0) catch |err| std.debug.print("failed to get key name, not supported? error={}\n", .{err}); } test "getScancode" { @@ -245,5 +252,5 @@ test "getScancode" { try glfw.init(); defer glfw.terminate(); - _ = glfw.key.getScancode(glfw.key.a) catch |err| std.debug.print("failed to get key scancode, not supported? error={}\n", .{err}); + _ = glfw.Key.a.getScancode() catch |err| std.debug.print("failed to get key scancode, not supported? error={}\n", .{err}); } diff --git a/glfw/src/main.zig b/glfw/src/main.zig index dde1324f..8f5c3c0a 100644 --- a/glfw/src/main.zig +++ b/glfw/src/main.zig @@ -3,6 +3,8 @@ const testing = std.testing; const c = @import("c.zig").c; +const key = @import("key.zig"); + pub usingnamespace @import("consts.zig"); pub const Error = @import("errors.zig").Error; const getError = @import("errors.zig").getError; @@ -14,7 +16,6 @@ pub const GammaRamp = @import("GammaRamp.zig"); pub const hat = @import("hat.zig"); pub const Image = @import("Image.zig"); pub const Joystick = @import("Joystick.zig"); -pub const key = @import("key.zig"); pub const mod = @import("mod.zig"); pub const Monitor = @import("Monitor.zig"); pub const mouse_button = @import("mouse_button.zig"); @@ -22,6 +23,7 @@ pub const version = @import("version.zig"); pub const VideoMode = @import("VideoMode.zig"); pub const Window = @import("Window.zig"); pub const Cursor = @import("Cursor.zig"); +pub const Key = key.Key; pub usingnamespace @import("clipboard.zig"); pub usingnamespace @import("opengl.zig"); diff --git a/glfw/src/mod.zig b/glfw/src/mod.zig index c72b27a2..8d230327 100644 --- a/glfw/src/mod.zig +++ b/glfw/src/mod.zig @@ -4,20 +4,165 @@ const c = @import("c.zig").c; -/// If this bit is set one or more Shift keys were held down. -pub const shift = c.GLFW_MOD_SHIFT; +// must be in sync with https://www.glfw.org/docs/3.3/group__mods.html +/// A bitmask of all key modifiers +pub const Mods = packed struct { + shift: bool align(@alignOf(c_int)) = false, + control: bool = false, + alt: bool = false, + super: bool = false, + caps_lock: bool = false, + num_lock: bool = false, -/// If this bit is set one or more Control keys were held down. -pub const control = c.GLFW_MOD_CONTROL; + inline fn verifyIntType(comptime IntType: type) void { + comptime { + switch (@typeInfo(IntType)) { + .Int => {}, + else => @compileError("Int was not of int type"), + } + } + } -/// If this bit is set one or more Alt keys were held down. -pub const alt = c.GLFW_MOD_ALT; + pub inline fn toInt(comptime IntType: type, self: Mods) IntType { + verifyIntType(IntType); + return @bitCast(IntType, self); + } -/// If this bit is set one or more Super keys were held down. -pub const super = c.GLFW_MOD_SUPER; + pub inline fn fromInt(flags: anytype) Mods { + verifyIntType(@TypeOf(flags)); + return @bitCast(Mods, flags); + } +}; -/// If this bit is set the Caps Lock key is enabled and the glfw.lock_key_mods input mode is set. -pub const caps_lock = c.GLFW_MOD_CAPS_LOCK; +/// Hold all glfw values as is +pub const RawMods = struct { + /// If this bit is set one or more Shift keys were held down. + pub const shift = c.GLFW_MOD_SHIFT; -/// If this bit is set the Num Lock key is enabled and the glfw.lock_key_mods input mode is set. -pub const num_lock = c.GLFW_MOD_NUM_LOCK; + /// If this bit is set one or more Control keys were held down. + pub const control = c.GLFW_MOD_CONTROL; + + /// If this bit is set one or more Alt keys were held down. + pub const alt = c.GLFW_MOD_ALT; + + /// If this bit is set one or more Super keys were held down. + pub const super = c.GLFW_MOD_SUPER; + + /// If this bit is set the Caps Lock key is enabled and the glfw.lock_key_mods input mode is set. + pub const caps_lock = c.GLFW_MOD_CAPS_LOCK; + + /// If this bit is set the Num Lock key is enabled and the glfw.lock_key_mods input mode is set. + pub const num_lock = c.GLFW_MOD_NUM_LOCK; +}; + + +test "shift int to bitmask" { + const std = @import("std"); + + const int_mod = RawMods.shift; + const mod = Mods.fromInt(int_mod); + + std.testing.expect(mod.shift == true); + std.testing.expect(mod.control == false); + std.testing.expect(mod.alt == false); + std.testing.expect(mod.super == false); + std.testing.expect(mod.caps_lock == false); + std.testing.expect(mod.num_lock == false); +} + +test "shift int and alt to bitmask" { + const std = @import("std"); + + const int_mod = RawMods.shift | RawMods.alt; + const mod = Mods.fromInt(int_mod); + + std.testing.expect(mod.shift == true); + std.testing.expect(mod.control == false); + std.testing.expect(mod.alt == true); + std.testing.expect(mod.super == false); + std.testing.expect(mod.caps_lock == false); + std.testing.expect(mod.num_lock == false); +} + +test "super int to bitmask" { + const std = @import("std"); + + const int_mod = RawMods.super; + const mod = Mods.fromInt(int_mod); + + std.testing.expect(mod.shift == false); + std.testing.expect(mod.control == false); + std.testing.expect(mod.alt == false); + std.testing.expect(mod.super == true); + std.testing.expect(mod.caps_lock == false); + std.testing.expect(mod.num_lock == false); +} + +test "num lock int to bitmask" { + const std = @import("std"); + + const int_mod = RawMods.num_lock; + const mod = Mods.fromInt(int_mod); + + std.testing.expect(mod.shift == false); + std.testing.expect(mod.control == false); + std.testing.expect(mod.alt == false); + std.testing.expect(mod.super == false); + std.testing.expect(mod.caps_lock == false); + std.testing.expect(mod.num_lock == true); +} + + +test "all int to bitmask" { + const std = @import("std"); + + const int_mod = RawMods.shift | RawMods.control | + RawMods.alt | RawMods.super | + RawMods.caps_lock | RawMods.num_lock; + const mod = Mods.fromInt(int_mod); + + std.testing.expect(mod.shift == true); + std.testing.expect(mod.control == true); + std.testing.expect(mod.alt == true); + std.testing.expect(mod.super == true); + std.testing.expect(mod.caps_lock == true); + std.testing.expect(mod.num_lock == true); +} + +test "shift bitmask to int" { + const std = @import("std"); + + const mod = Mods{ .shift = true }; + const int_mod = mod.toInt(c_int); + + std.testing.expectEqual(int_mod, RawMods.shift); +} + +test "shift and alt bitmask to int" { + const std = @import("std"); + + const mod = Mods{ .shift = true, .alt = true }; + const int_mod = mod.toInt(c_int); + + std.testing.expectEqual(int_mod, RawMods.shift | RawMods.alt); +} + +test "all bitmask to int" { + const std = @import("std"); + + const mod = Mods{ + .shift = true, + .control = true, + .alt = true, + .super = true, + .caps_lock = true, + .num_lock = true, + }; + const int_mod = mod.toInt(c_int); + + const expected = RawMods.shift | RawMods.control | + RawMods.alt | RawMods.super | + RawMods.caps_lock | RawMods.num_lock; + + std.testing.expectEqual(int_mod, expected); +}