/* Crafter®.Graphics Copyright (C) 2026 Catcrafts® Catcrafts.net This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3.0 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ module; #ifdef CRAFTER_GRAPHICS_WINDOW_WAYLAND #include #endif export module Crafter.Graphics:Keys; import std; import :Types; // Compile-time translation from the abstract `CrafterKeys` enum to the raw // platform key code that the runtime actually stores and compares. The whole // point: bindings, events, and InputField never carry the abstract enum at // runtime — they carry the raw integer the platform delivers. `Key(...)` is // `consteval` so every call from source folds to an immediate operand; user // code stays cross-platform (`Key(CrafterKeys::Space)`) without any `#ifdef` // at the call site. // // Domain of the returned KeyCode: // Win32: bits 0..7 = PS/2 set-1 scancode byte. Bit 8 = extended-key flag // (the 0xE0-prefixed variants — RightCtrl, RightAlt, the keypad's // Enter and /, the cursor cluster's arrows/Home/End/etc., the // Windows keys). At runtime, WndProc OR-s in 0x100 when lParam // bit 24 is set, so a saved binding for "RightCtrl" (0x11D) survives // round-trip with the actual hardware event. // Wayland/Linux: kernel input-event-codes (KEY_*) directly. The +8 X11 // offset is stripped at the wl_keyboard.key boundary so the // runtime values match the table here. // // Keys with no clean scancode encoding (Pause, some keys without standard // physical position) return 0. 0 is documented as "unmapped"; binding to it // will never match a real keypress. export namespace Crafter { using KeyCode = std::uint32_t; consteval KeyCode Key(CrafterKeys k) { #ifdef CRAFTER_GRAPHICS_WINDOW_WIN32 // PS/2 set-1 scancodes. Extended keys carry 0x100 so the runtime // path can disambiguate by OR-ing in 0x100 when lParam bit 24 is set. switch (k) { // Alphabetic case CrafterKeys::A: return 0x1E; case CrafterKeys::B: return 0x30; case CrafterKeys::C: return 0x2E; case CrafterKeys::D: return 0x20; case CrafterKeys::E: return 0x12; case CrafterKeys::F: return 0x21; case CrafterKeys::G: return 0x22; case CrafterKeys::H: return 0x23; case CrafterKeys::I: return 0x17; case CrafterKeys::J: return 0x24; case CrafterKeys::K: return 0x25; case CrafterKeys::L: return 0x26; case CrafterKeys::M: return 0x32; case CrafterKeys::N: return 0x31; case CrafterKeys::O: return 0x18; case CrafterKeys::P: return 0x19; case CrafterKeys::Q: return 0x10; case CrafterKeys::R: return 0x13; case CrafterKeys::S: return 0x1F; case CrafterKeys::T: return 0x14; case CrafterKeys::U: return 0x16; case CrafterKeys::V: return 0x2F; case CrafterKeys::W: return 0x11; case CrafterKeys::X: return 0x2D; case CrafterKeys::Y: return 0x15; case CrafterKeys::Z: return 0x2C; // Numeric (top row) case CrafterKeys::_1: return 0x02; case CrafterKeys::_2: return 0x03; case CrafterKeys::_3: return 0x04; case CrafterKeys::_4: return 0x05; case CrafterKeys::_5: return 0x06; case CrafterKeys::_6: return 0x07; case CrafterKeys::_7: return 0x08; case CrafterKeys::_8: return 0x09; case CrafterKeys::_9: return 0x0A; case CrafterKeys::_0: return 0x0B; // Function keys case CrafterKeys::F1: return 0x3B; case CrafterKeys::F2: return 0x3C; case CrafterKeys::F3: return 0x3D; case CrafterKeys::F4: return 0x3E; case CrafterKeys::F5: return 0x3F; case CrafterKeys::F6: return 0x40; case CrafterKeys::F7: return 0x41; case CrafterKeys::F8: return 0x42; case CrafterKeys::F9: return 0x43; case CrafterKeys::F10: return 0x44; case CrafterKeys::F11: return 0x57; case CrafterKeys::F12: return 0x58; // Control keys case CrafterKeys::Escape: return 0x01; case CrafterKeys::Tab: return 0x0F; case CrafterKeys::Enter: return 0x1C; case CrafterKeys::Space: return 0x39; case CrafterKeys::Backspace: return 0x0E; case CrafterKeys::Delete: return 0x153; // extended case CrafterKeys::Insert: return 0x152; // extended case CrafterKeys::Home: return 0x147; // extended case CrafterKeys::End: return 0x14F; // extended case CrafterKeys::PageUp: return 0x149; // extended case CrafterKeys::PageDown: return 0x151; // extended case CrafterKeys::CapsLock: return 0x3A; case CrafterKeys::NumLock: return 0x45; case CrafterKeys::ScrollLock: return 0x46; // Modifiers case CrafterKeys::LeftShift: return 0x2A; case CrafterKeys::RightShift: return 0x36; case CrafterKeys::LeftCtrl: return 0x1D; case CrafterKeys::RightCtrl: return 0x11D; // extended case CrafterKeys::LeftAlt: return 0x38; case CrafterKeys::RightAlt: return 0x138; // extended case CrafterKeys::LeftSuper: return 0x15B; // extended case CrafterKeys::RightSuper: return 0x15C; // extended // Arrows (all extended on Win32 — the cursor cluster, not the keypad) case CrafterKeys::Up: return 0x148; case CrafterKeys::Down: return 0x150; case CrafterKeys::Left: return 0x14B; case CrafterKeys::Right: return 0x14D; // Keypad case CrafterKeys::keypad_0: return 0x52; case CrafterKeys::keypad_1: return 0x4F; case CrafterKeys::keypad_2: return 0x50; case CrafterKeys::keypad_3: return 0x51; case CrafterKeys::keypad_4: return 0x4B; case CrafterKeys::keypad_5: return 0x4C; case CrafterKeys::keypad_6: return 0x4D; case CrafterKeys::keypad_7: return 0x47; case CrafterKeys::keypad_8: return 0x48; case CrafterKeys::keypad_9: return 0x49; case CrafterKeys::keypad_enter: return 0x11C; // extended case CrafterKeys::keypad_plus: return 0x4E; case CrafterKeys::keypad_minus: return 0x4A; case CrafterKeys::keypad_multiply: return 0x37; case CrafterKeys::keypad_divide: return 0x135; // extended case CrafterKeys::keypad_decimal: return 0x53; // Punctuation case CrafterKeys::grave: return 0x29; case CrafterKeys::minus: return 0x0C; case CrafterKeys::equal: return 0x0D; case CrafterKeys::bracket_left: return 0x1A; case CrafterKeys::bracket_right: return 0x1B; case CrafterKeys::backslash: return 0x2B; case CrafterKeys::semicolon: return 0x27; case CrafterKeys::quote: return 0x28; case CrafterKeys::comma: return 0x33; case CrafterKeys::period: return 0x34; case CrafterKeys::slash: return 0x35; case CrafterKeys::print_screen: return 0x137; // extended case CrafterKeys::pause: return 0; // unmapped — multi-byte sequence case CrafterKeys::menu: return 0x15D; // extended (App key) // Multimedia / browser / launch keys (all extended on Win32) case CrafterKeys::volume_up: return 0x130; case CrafterKeys::volume_down: return 0x12E; case CrafterKeys::volume_mute: return 0x120; case CrafterKeys::media_play: return 0x122; case CrafterKeys::media_stop: return 0x124; case CrafterKeys::media_prev: return 0x110; case CrafterKeys::media_next: return 0x119; case CrafterKeys::browser_back: return 0x16A; case CrafterKeys::browser_forward: return 0x169; case CrafterKeys::browser_refresh: return 0x167; case CrafterKeys::browser_stop: return 0x168; case CrafterKeys::browser_search: return 0x165; case CrafterKeys::browser_home: return 0x132; case CrafterKeys::launch_mail: return 0x16C; case CrafterKeys::launch_calculator: return 0x121; case CrafterKeys::launch_media_player: return 0x16D; case CrafterKeys::CrafterKeysMax: return 0; } #endif #ifdef CRAFTER_GRAPHICS_WINDOW_WAYLAND // Linux kernel input-event-codes. The Wayland keyboard handler strips // the +8 X11 offset before delivery so these match wl_keyboard.key // values directly. switch (k) { // Alphabetic case CrafterKeys::A: return KEY_A; case CrafterKeys::B: return KEY_B; case CrafterKeys::C: return KEY_C; case CrafterKeys::D: return KEY_D; case CrafterKeys::E: return KEY_E; case CrafterKeys::F: return KEY_F; case CrafterKeys::G: return KEY_G; case CrafterKeys::H: return KEY_H; case CrafterKeys::I: return KEY_I; case CrafterKeys::J: return KEY_J; case CrafterKeys::K: return KEY_K; case CrafterKeys::L: return KEY_L; case CrafterKeys::M: return KEY_M; case CrafterKeys::N: return KEY_N; case CrafterKeys::O: return KEY_O; case CrafterKeys::P: return KEY_P; case CrafterKeys::Q: return KEY_Q; case CrafterKeys::R: return KEY_R; case CrafterKeys::S: return KEY_S; case CrafterKeys::T: return KEY_T; case CrafterKeys::U: return KEY_U; case CrafterKeys::V: return KEY_V; case CrafterKeys::W: return KEY_W; case CrafterKeys::X: return KEY_X; case CrafterKeys::Y: return KEY_Y; case CrafterKeys::Z: return KEY_Z; // Numeric case CrafterKeys::_0: return KEY_0; case CrafterKeys::_1: return KEY_1; case CrafterKeys::_2: return KEY_2; case CrafterKeys::_3: return KEY_3; case CrafterKeys::_4: return KEY_4; case CrafterKeys::_5: return KEY_5; case CrafterKeys::_6: return KEY_6; case CrafterKeys::_7: return KEY_7; case CrafterKeys::_8: return KEY_8; case CrafterKeys::_9: return KEY_9; // Function keys case CrafterKeys::F1: return KEY_F1; case CrafterKeys::F2: return KEY_F2; case CrafterKeys::F3: return KEY_F3; case CrafterKeys::F4: return KEY_F4; case CrafterKeys::F5: return KEY_F5; case CrafterKeys::F6: return KEY_F6; case CrafterKeys::F7: return KEY_F7; case CrafterKeys::F8: return KEY_F8; case CrafterKeys::F9: return KEY_F9; case CrafterKeys::F10: return KEY_F10; case CrafterKeys::F11: return KEY_F11; case CrafterKeys::F12: return KEY_F12; // Control keys case CrafterKeys::Escape: return KEY_ESC; case CrafterKeys::Tab: return KEY_TAB; case CrafterKeys::Enter: return KEY_ENTER; case CrafterKeys::Space: return KEY_SPACE; case CrafterKeys::Backspace: return KEY_BACKSPACE; case CrafterKeys::Delete: return KEY_DELETE; case CrafterKeys::Insert: return KEY_INSERT; case CrafterKeys::Home: return KEY_HOME; case CrafterKeys::End: return KEY_END; case CrafterKeys::PageUp: return KEY_PAGEUP; case CrafterKeys::PageDown: return KEY_PAGEDOWN; case CrafterKeys::CapsLock: return KEY_CAPSLOCK; case CrafterKeys::NumLock: return KEY_NUMLOCK; case CrafterKeys::ScrollLock: return KEY_SCROLLLOCK; // Modifiers case CrafterKeys::LeftShift: return KEY_LEFTSHIFT; case CrafterKeys::RightShift: return KEY_RIGHTSHIFT; case CrafterKeys::LeftCtrl: return KEY_LEFTCTRL; case CrafterKeys::RightCtrl: return KEY_RIGHTCTRL; case CrafterKeys::LeftAlt: return KEY_LEFTALT; case CrafterKeys::RightAlt: return KEY_RIGHTALT; case CrafterKeys::LeftSuper: return KEY_LEFTMETA; case CrafterKeys::RightSuper: return KEY_RIGHTMETA; // Arrows case CrafterKeys::Up: return KEY_UP; case CrafterKeys::Down: return KEY_DOWN; case CrafterKeys::Left: return KEY_LEFT; case CrafterKeys::Right: return KEY_RIGHT; // Keypad case CrafterKeys::keypad_0: return KEY_KP0; case CrafterKeys::keypad_1: return KEY_KP1; case CrafterKeys::keypad_2: return KEY_KP2; case CrafterKeys::keypad_3: return KEY_KP3; case CrafterKeys::keypad_4: return KEY_KP4; case CrafterKeys::keypad_5: return KEY_KP5; case CrafterKeys::keypad_6: return KEY_KP6; case CrafterKeys::keypad_7: return KEY_KP7; case CrafterKeys::keypad_8: return KEY_KP8; case CrafterKeys::keypad_9: return KEY_KP9; case CrafterKeys::keypad_enter: return KEY_KPENTER; case CrafterKeys::keypad_plus: return KEY_KPPLUS; case CrafterKeys::keypad_minus: return KEY_KPMINUS; case CrafterKeys::keypad_multiply: return KEY_KPASTERISK; case CrafterKeys::keypad_divide: return KEY_KPSLASH; case CrafterKeys::keypad_decimal: return KEY_KPDOT; // Punctuation case CrafterKeys::grave: return KEY_GRAVE; case CrafterKeys::minus: return KEY_MINUS; case CrafterKeys::equal: return KEY_EQUAL; case CrafterKeys::bracket_left: return KEY_LEFTBRACE; case CrafterKeys::bracket_right: return KEY_RIGHTBRACE; case CrafterKeys::backslash: return KEY_BACKSLASH; case CrafterKeys::semicolon: return KEY_SEMICOLON; case CrafterKeys::quote: return KEY_APOSTROPHE; case CrafterKeys::comma: return KEY_COMMA; case CrafterKeys::period: return KEY_DOT; case CrafterKeys::slash: return KEY_SLASH; case CrafterKeys::print_screen: return KEY_SYSRQ; case CrafterKeys::pause: return KEY_PAUSE; case CrafterKeys::menu: return KEY_COMPOSE; // Multimedia / browser / launch keys case CrafterKeys::volume_up: return KEY_VOLUMEUP; case CrafterKeys::volume_down: return KEY_VOLUMEDOWN; case CrafterKeys::volume_mute: return KEY_MUTE; case CrafterKeys::media_play: return KEY_PLAYPAUSE; case CrafterKeys::media_stop: return KEY_STOPCD; case CrafterKeys::media_prev: return KEY_PREVIOUSSONG; case CrafterKeys::media_next: return KEY_NEXTSONG; case CrafterKeys::browser_back: return KEY_BACK; case CrafterKeys::browser_forward: return KEY_FORWARD; case CrafterKeys::browser_refresh: return KEY_REFRESH; case CrafterKeys::browser_stop: return KEY_STOP; case CrafterKeys::browser_search: return KEY_SEARCH; case CrafterKeys::browser_home: return KEY_HOMEPAGE; case CrafterKeys::launch_mail: return KEY_MAIL; case CrafterKeys::launch_calculator: return KEY_CALC; case CrafterKeys::launch_media_player: return KEY_MEDIA; case CrafterKeys::CrafterKeysMax: return 0; } #endif return 0; } }