From a347ffd2f45feb4e180dd470046436f51591bd91 Mon Sep 17 00:00:00 2001 From: David Robillard Date: Sun, 28 May 2023 00:03:46 -0400 Subject: Add support for numeric keypad and simplify keyboard handling --- include/pugl/pugl.h | 51 +++++++++++++++++++------ src/mac.m | 69 +++++++++++++++++++++------------- src/win.c | 86 ++++++++++++++++++++++++------------------ src/x11.c | 73 ++++++++++++++++++------------------ test/test_utils.h | 105 ++++++++++++++++++++++++++++++++++++++++++---------- 5 files changed, 256 insertions(+), 128 deletions(-) diff --git a/include/pugl/pugl.h b/include/pugl/pugl.h index 2df04a5..39c051e 100644 --- a/include/pugl/pugl.h +++ b/include/pugl/pugl.h @@ -358,16 +358,22 @@ typedef enum { PUGL_KEY_F10, ///< F10 PUGL_KEY_F11, ///< F11 PUGL_KEY_F12, ///< F12 + PUGL_KEY_PAGE_UP = 0xE031, ///< Page Up + PUGL_KEY_PAGE_DOWN, ///< Page Down + PUGL_KEY_END, ///< End + PUGL_KEY_HOME, ///< Home PUGL_KEY_LEFT, ///< Left PUGL_KEY_UP, ///< Up PUGL_KEY_RIGHT, ///< Right PUGL_KEY_DOWN, ///< Down - PUGL_KEY_PAGE_UP, ///< Page Up - PUGL_KEY_PAGE_DOWN, ///< Page Down - PUGL_KEY_HOME, ///< Home - PUGL_KEY_END, ///< End + PUGL_KEY_PRINT_SCREEN = 0xE041U, ///< Print Screen PUGL_KEY_INSERT, ///< Insert - PUGL_KEY_SHIFT_L, ///< Left Shift + PUGL_KEY_PAUSE, ///< Pause/Break + PUGL_KEY_MENU, ///< Menu + PUGL_KEY_NUM_LOCK, ///< Num Lock + PUGL_KEY_SCROLL_LOCK, ///< Scroll Lock + PUGL_KEY_CAPS_LOCK, ///< Caps Lock + PUGL_KEY_SHIFT_L = 0xE051U, ///< Left Shift PUGL_KEY_SHIFT_R, ///< Right Shift PUGL_KEY_CTRL_L, ///< Left Control PUGL_KEY_CTRL_R, ///< Right Control @@ -375,12 +381,35 @@ typedef enum { PUGL_KEY_ALT_R, ///< Right Alt / AltGr PUGL_KEY_SUPER_L, ///< Left Super PUGL_KEY_SUPER_R, ///< Right Super - PUGL_KEY_MENU, ///< Menu - PUGL_KEY_CAPS_LOCK, ///< Caps Lock - PUGL_KEY_SCROLL_LOCK, ///< Scroll Lock - PUGL_KEY_NUM_LOCK, ///< Num Lock - PUGL_KEY_PRINT_SCREEN, ///< Print Screen - PUGL_KEY_PAUSE ///< Pause + PUGL_KEY_PAD_0 = 0xE060U, ///< Keypad 0 + PUGL_KEY_PAD_1, ///< Keypad 1 + PUGL_KEY_PAD_2, ///< Keypad 2 + PUGL_KEY_PAD_3, ///< Keypad 3 + PUGL_KEY_PAD_4, ///< Keypad 4 + PUGL_KEY_PAD_5, ///< Keypad 5 + PUGL_KEY_PAD_6, ///< Keypad 6 + PUGL_KEY_PAD_7, ///< Keypad 7 + PUGL_KEY_PAD_8, ///< Keypad 8 + PUGL_KEY_PAD_9, ///< Keypad 9 + PUGL_KEY_PAD_ENTER, ///< Keypad Enter + PUGL_KEY_PAD_PAGE_UP = 0xE071U, ///< Keypad Page Up + PUGL_KEY_PAD_PAGE_DOWN, ///< Keypad Page Down + PUGL_KEY_PAD_END, ///< Keypad End + PUGL_KEY_PAD_HOME, ///< Keypad Home + PUGL_KEY_PAD_LEFT, ///< Keypad Left + PUGL_KEY_PAD_UP, ///< Keypad Up + PUGL_KEY_PAD_RIGHT, ///< Keypad Right + PUGL_KEY_PAD_DOWN, ///< Keypad Down + PUGL_KEY_PAD_CLEAR = 0xE09DU, ///< Keypad Clear/Begin + PUGL_KEY_PAD_INSERT, ///< Keypad Insert + PUGL_KEY_PAD_DELETE, ///< Keypad Delete + PUGL_KEY_PAD_EQUAL, ///< Keypad Equal + PUGL_KEY_PAD_MULTIPLY = 0xE0AAU, ///< Keypad Multiply + PUGL_KEY_PAD_ADD, ///< Keypad Add + PUGL_KEY_PAD_SEPARATOR, ///< Keypad Separator + PUGL_KEY_PAD_SUBTRACT, ///< Keypad Subtract + PUGL_KEY_PAD_DECIMAL, ///< Keypad Decimal + PUGL_KEY_PAD_DIVIDE, ///< Keypad Divide } PuglKey; /// Keyboard modifier flags diff --git a/src/mac.m b/src/mac.m index ce90b9a..fa5355f 100644 --- a/src/mac.m +++ b/src/mac.m @@ -379,31 +379,12 @@ keySymToSpecial(const NSEvent* const ev) { NSString* chars = [ev charactersIgnoringModifiers]; if ([chars length] == 1) { - switch ([chars characterAtIndex:0]) { - case NSF1FunctionKey: - return PUGL_KEY_F1; - case NSF2FunctionKey: - return PUGL_KEY_F2; - case NSF3FunctionKey: - return PUGL_KEY_F3; - case NSF4FunctionKey: - return PUGL_KEY_F4; - case NSF5FunctionKey: - return PUGL_KEY_F5; - case NSF6FunctionKey: - return PUGL_KEY_F6; - case NSF7FunctionKey: - return PUGL_KEY_F7; - case NSF8FunctionKey: - return PUGL_KEY_F8; - case NSF9FunctionKey: - return PUGL_KEY_F9; - case NSF10FunctionKey: - return PUGL_KEY_F10; - case NSF11FunctionKey: - return PUGL_KEY_F11; - case NSF12FunctionKey: - return PUGL_KEY_F12; + const unichar sym = [chars characterAtIndex:0]; + if (sym >= NSF1FunctionKey && sym <= NSF12FunctionKey) { + return (PuglKey)(PUGL_KEY_F1 + (sym - NSF1FunctionKey)); + } + + switch (sym) { case NSDeleteCharacter: return PUGL_KEY_BACKSPACE; case NSDeleteFunctionKey: @@ -439,6 +420,44 @@ keySymToSpecial(const NSEvent* const ev) } // SHIFT, CTRL, ALT, and SUPER are handled in [flagsChanged] } + + switch ([ev keyCode]) { + case 0x41: + return PUGL_KEY_PAD_DECIMAL; + case 0x43: + return PUGL_KEY_PAD_MULTIPLY; + case 0x45: + return PUGL_KEY_PAD_ADD; + case 0x4B: + return PUGL_KEY_PAD_DIVIDE; + case 0x4C: + return PUGL_KEY_PAD_ENTER; + case 0x4E: + return PUGL_KEY_PAD_SUBTRACT; + case 0x51: + return PUGL_KEY_PAD_EQUAL; + case 0x52: + return PUGL_KEY_PAD_0; + case 0x53: + return PUGL_KEY_PAD_1; + case 0x54: + return PUGL_KEY_PAD_2; + case 0x55: + return PUGL_KEY_PAD_3; + case 0x56: + return PUGL_KEY_PAD_4; + case 0x57: + return PUGL_KEY_PAD_5; + case 0x58: + return PUGL_KEY_PAD_6; + case 0x59: + return PUGL_KEY_PAD_7; + case 0x5B: + return PUGL_KEY_PAD_8; + case 0x5C: + return PUGL_KEY_PAD_9; + } + return (PuglKey)0; } diff --git a/src/win.c b/src/win.c index ed78baa..e020b86 100644 --- a/src/win.c +++ b/src/win.c @@ -402,43 +402,36 @@ puglFreeWorldInternals(PuglWorld* world) free(world->impl); } +static PuglKey +keyInRange(const WPARAM winSym, + const WPARAM winMin, + const WPARAM winMax, + const PuglKey puglMin) +{ + return (winSym >= winMin && winSym <= winMax) + ? (PuglKey)(puglMin + (winSym - winMin)) + : (PuglKey)0; +} + static PuglKey keySymToSpecial(const WPARAM sym, const bool ext) { + PuglKey key = (PuglKey)0; + if ((key = keyInRange(sym, VK_F1, VK_F12, PUGL_KEY_F1)) || + (key = keyInRange(sym, + VK_PRIOR, + VK_DOWN, + ext ? PUGL_KEY_PAGE_UP : PUGL_KEY_PAD_PAGE_UP)) || + (key = keyInRange(sym, VK_NUMPAD0, VK_NUMPAD9, PUGL_KEY_PAD_0)) || + (key = keyInRange(sym, VK_MULTIPLY, VK_DIVIDE, PUGL_KEY_PAD_MULTIPLY)) || + (key = keyInRange(sym, VK_LSHIFT, VK_RMENU, PUGL_KEY_SHIFT_L))) { + return key; + } + // clang-format off switch (sym) { - case VK_F1: return PUGL_KEY_F1; - case VK_F2: return PUGL_KEY_F2; - case VK_F3: return PUGL_KEY_F3; - case VK_F4: return PUGL_KEY_F4; - case VK_F5: return PUGL_KEY_F5; - case VK_F6: return PUGL_KEY_F6; - case VK_F7: return PUGL_KEY_F7; - case VK_F8: return PUGL_KEY_F8; - case VK_F9: return PUGL_KEY_F9; - case VK_F10: return PUGL_KEY_F10; - case VK_F11: return PUGL_KEY_F11; - case VK_F12: return PUGL_KEY_F12; case VK_BACK: return PUGL_KEY_BACKSPACE; - case VK_DELETE: return PUGL_KEY_DELETE; - case VK_LEFT: return PUGL_KEY_LEFT; - case VK_UP: return PUGL_KEY_UP; - case VK_RIGHT: return PUGL_KEY_RIGHT; - case VK_DOWN: return PUGL_KEY_DOWN; - case VK_PRIOR: return PUGL_KEY_PAGE_UP; - case VK_NEXT: return PUGL_KEY_PAGE_DOWN; - case VK_HOME: return PUGL_KEY_HOME; - case VK_END: return PUGL_KEY_END; - case VK_INSERT: return PUGL_KEY_INSERT; - case VK_SHIFT: return ext ? PUGL_KEY_SHIFT_L : PUGL_KEY_SHIFT_R; - case VK_LSHIFT: return PUGL_KEY_SHIFT_L; - case VK_RSHIFT: return PUGL_KEY_SHIFT_R; - case VK_CONTROL: return ext ? PUGL_KEY_CTRL_L : PUGL_KEY_CTRL_R; - case VK_LCONTROL: return PUGL_KEY_CTRL_L; - case VK_RCONTROL: return PUGL_KEY_CTRL_R; - case VK_MENU: return ext ? PUGL_KEY_ALT_L : PUGL_KEY_ALT_R; - case VK_LMENU: return PUGL_KEY_ALT_L; - case VK_RMENU: return PUGL_KEY_ALT_R; + case VK_CLEAR: return PUGL_KEY_PAD_CLEAR; case VK_LWIN: return PUGL_KEY_SUPER_L; case VK_RWIN: return PUGL_KEY_SUPER_R; case VK_CAPITAL: return PUGL_KEY_CAPS_LOCK; @@ -449,6 +442,29 @@ keySymToSpecial(const WPARAM sym, const bool ext) } // clang-format on + if (ext) { + // clang-format off + switch (sym) { + case VK_RETURN: return PUGL_KEY_PAD_ENTER; + case VK_INSERT: return PUGL_KEY_INSERT; + case VK_DELETE: return PUGL_KEY_DELETE; + case VK_SHIFT: return PUGL_KEY_SHIFT_L; + case VK_CONTROL: return PUGL_KEY_CTRL_L; + case VK_MENU: return PUGL_KEY_ALT_L; + } + // clang-format on + } else { + // clang-format off + switch (sym) { + case VK_INSERT: return PUGL_KEY_PAD_INSERT; + case VK_DELETE: return PUGL_KEY_PAD_DELETE; + case VK_SHIFT: return PUGL_KEY_SHIFT_R; + case VK_CONTROL: return PUGL_KEY_CTRL_R; + case VK_MENU: return PUGL_KEY_ALT_R; + } + // clang-format on + } + return (PuglKey)0; } @@ -561,13 +577,9 @@ initKeyEvent(PuglKeyEvent* event, event->keycode = (uint32_t)((lParam & 0xFF0000) >> 16); event->key = 0; - const PuglKey special = keySymToSpecial(vkey); + const PuglKey special = keySymToSpecial(vkey, ext); if (special) { - if (ext && (special == PUGL_KEY_CTRL_L || special == PUGL_KEY_ALT_L)) { - event->key = (uint32_t)special + 1U; // Right hand key - } else { - event->key = (uint32_t)special; - } + event->key = (uint32_t)special; } else if (!dead) { // Translate unshifted key BYTE keyboardState[256] = PUGL_INIT_STRUCT; diff --git a/src/x11.c b/src/x11.c index b389932..e1e948f 100644 --- a/src/x11.c +++ b/src/x11.c @@ -809,48 +809,49 @@ puglFreeWorldInternals(PuglWorld* const world) free(world->impl); } +static PuglKey +keyInRange(const KeySym xSym, + const KeySym xMin, + const KeySym xMax, + const PuglKey puglMin) +{ + return (xSym >= xMin && xSym <= xMax) ? (PuglKey)(puglMin + (xSym - xMin)) + : (PuglKey)0; +} + static PuglKey keySymToSpecial(const KeySym sym) { + PuglKey key = (PuglKey)0; + if ((key = keyInRange(sym, XK_F1, XK_F12, PUGL_KEY_F1)) || + (key = keyInRange(sym, XK_Page_Up, XK_End, PUGL_KEY_PAGE_UP)) || + (key = keyInRange(sym, XK_Home, XK_Down, PUGL_KEY_HOME)) || + (key = keyInRange(sym, XK_Shift_L, XK_Control_R, PUGL_KEY_SHIFT_L)) || + (key = keyInRange(sym, XK_Alt_L, XK_Super_R, PUGL_KEY_ALT_L)) || + (key = keyInRange(sym, XK_KP_Home, XK_KP_Down, PUGL_KEY_PAD_HOME)) || + (key = keyInRange(sym, XK_KP_0, XK_KP_9, PUGL_KEY_PAD_0)) || + (key = keyInRange(sym, XK_KP_Begin, XK_KP_Delete, PUGL_KEY_PAD_CLEAR)) || + (key = keyInRange( + sym, XK_KP_Multiply, XK_KP_Divide, PUGL_KEY_PAD_MULTIPLY))) { + return key; + } + // clang-format off switch (sym) { - case XK_F1: return PUGL_KEY_F1; - case XK_F2: return PUGL_KEY_F2; - case XK_F3: return PUGL_KEY_F3; - case XK_F4: return PUGL_KEY_F4; - case XK_F5: return PUGL_KEY_F5; - case XK_F6: return PUGL_KEY_F6; - case XK_F7: return PUGL_KEY_F7; - case XK_F8: return PUGL_KEY_F8; - case XK_F9: return PUGL_KEY_F9; - case XK_F10: return PUGL_KEY_F10; - case XK_F11: return PUGL_KEY_F11; - case XK_F12: return PUGL_KEY_F12; - case XK_Left: return PUGL_KEY_LEFT; - case XK_Up: return PUGL_KEY_UP; - case XK_Right: return PUGL_KEY_RIGHT; - case XK_Down: return PUGL_KEY_DOWN; - case XK_Page_Up: return PUGL_KEY_PAGE_UP; - case XK_Page_Down: return PUGL_KEY_PAGE_DOWN; - case XK_Home: return PUGL_KEY_HOME; - case XK_End: return PUGL_KEY_END; + case XK_ISO_Level3_Shift: return PUGL_KEY_ALT_R; + case XK_Pause: return PUGL_KEY_PAUSE; + case XK_Scroll_Lock: return PUGL_KEY_SCROLL_LOCK; + case XK_Print: return PUGL_KEY_PRINT_SCREEN; case XK_Insert: return PUGL_KEY_INSERT; - case XK_Shift_L: return PUGL_KEY_SHIFT_L; - case XK_Shift_R: return PUGL_KEY_SHIFT_R; - case XK_Control_L: return PUGL_KEY_CTRL_L; - case XK_Control_R: return PUGL_KEY_CTRL_R; - case XK_Alt_L: return PUGL_KEY_ALT_L; - case XK_ISO_Level3_Shift: - case XK_Alt_R: return PUGL_KEY_ALT_R; - case XK_Super_L: return PUGL_KEY_SUPER_L; - case XK_Super_R: return PUGL_KEY_SUPER_R; case XK_Menu: return PUGL_KEY_MENU; - case XK_Caps_Lock: return PUGL_KEY_CAPS_LOCK; - case XK_Scroll_Lock: return PUGL_KEY_SCROLL_LOCK; case XK_Num_Lock: return PUGL_KEY_NUM_LOCK; - case XK_Print: return PUGL_KEY_PRINT_SCREEN; - case XK_Pause: return PUGL_KEY_PAUSE; - default: break; + case XK_KP_Enter: return PUGL_KEY_PAD_ENTER; + case XK_KP_Page_Up: return PUGL_KEY_PAD_PAGE_UP; + case XK_KP_Page_Down: return PUGL_KEY_PAD_PAGE_DOWN; + case XK_KP_End: return PUGL_KEY_PAD_END; + case XK_KP_Equal: return PUGL_KEY_PAD_CLEAR; + case XK_Caps_Lock: return PUGL_KEY_CAPS_LOCK; + default: break; } // clang-format on @@ -878,7 +879,9 @@ translateKey(PuglView* const view, XEvent* const xevent, PuglEvent* const event) const bool filter = XFilterEvent(xevent, None); event->key.keycode = xevent->xkey.keycode; - xevent->xkey.state = 0; + + // Mask off the shift bit to get the lowercase "main" symbol + xevent->xkey.state = xevent->xkey.state & ~(unsigned)ShiftMask; // Lookup unshifted key char ustr[8] = {0}; diff --git a/test/test_utils.h b/test/test_utils.h index 9b486d0..45df7b4 100644 --- a/test/test_utils.h +++ b/test/test_utils.h @@ -160,6 +160,15 @@ keyString(const uint32_t key) return "F11"; case PUGL_KEY_F12: return "F12"; + + case PUGL_KEY_PAGE_UP: + return "PAGE_UP"; + case PUGL_KEY_PAGE_DOWN: + return "PAGE_DOWN"; + case PUGL_KEY_END: + return "END"; + case PUGL_KEY_HOME: + return "HOME"; case PUGL_KEY_LEFT: return "LEFT"; case PUGL_KEY_UP: @@ -168,16 +177,22 @@ keyString(const uint32_t key) return "RIGHT"; case PUGL_KEY_DOWN: return "DOWN"; - case PUGL_KEY_PAGE_UP: - return "PAGE_UP"; - case PUGL_KEY_PAGE_DOWN: - return "PAGE_DOWN"; - case PUGL_KEY_HOME: - return "HOME"; - case PUGL_KEY_END: - return "END"; + + case PUGL_KEY_PRINT_SCREEN: + return "PRINT_SCREEN"; case PUGL_KEY_INSERT: return "INSERT"; + case PUGL_KEY_PAUSE: + return "PAUSE"; + case PUGL_KEY_MENU: + return "MENU"; + case PUGL_KEY_NUM_LOCK: + return "NUM_LOCK"; + case PUGL_KEY_SCROLL_LOCK: + return "SCROLL_LOCK"; + case PUGL_KEY_CAPS_LOCK: + return "CAPS_LOCK"; + case PUGL_KEY_SHIFT_L: return "SHIFT_L"; case PUGL_KEY_SHIFT_R: @@ -194,18 +209,68 @@ keyString(const uint32_t key) return "SUPER_L"; case PUGL_KEY_SUPER_R: return "SUPER_R"; - case PUGL_KEY_MENU: - return "MENU"; - case PUGL_KEY_CAPS_LOCK: - return "CAPS_LOCK"; - case PUGL_KEY_SCROLL_LOCK: - return "SCROLL_LOCK"; - case PUGL_KEY_NUM_LOCK: - return "NUM_LOCK"; - case PUGL_KEY_PRINT_SCREEN: - return "PRINT_SCREEN"; - case PUGL_KEY_PAUSE: - return "PAUSE"; + + case PUGL_KEY_PAD_0: + return "PAD_0"; + case PUGL_KEY_PAD_1: + return "PAD_1"; + case PUGL_KEY_PAD_2: + return "PAD_2"; + case PUGL_KEY_PAD_3: + return "PAD_3"; + case PUGL_KEY_PAD_4: + return "PAD_4"; + case PUGL_KEY_PAD_5: + return "PAD_5"; + case PUGL_KEY_PAD_6: + return "PAD_6"; + case PUGL_KEY_PAD_7: + return "PAD_7"; + case PUGL_KEY_PAD_8: + return "PAD_8"; + case PUGL_KEY_PAD_9: + return "PAD_9"; + case PUGL_KEY_PAD_ENTER: + return "PAD_ENTER"; + + case PUGL_KEY_PAD_PAGE_UP: + return "PAD_PAGE_UP"; + case PUGL_KEY_PAD_PAGE_DOWN: + return "PAD_PAGE_DOWN"; + case PUGL_KEY_PAD_END: + return "PAD_END"; + case PUGL_KEY_PAD_HOME: + return "PAD_HOME"; + case PUGL_KEY_PAD_LEFT: + return "PAD_LEFT"; + case PUGL_KEY_PAD_UP: + return "PAD_UP"; + case PUGL_KEY_PAD_RIGHT: + return "PAD_RIGHT"; + case PUGL_KEY_PAD_DOWN: + return "PAD_DOWN"; + + case PUGL_KEY_PAD_CLEAR: + return "PAD_CLEAR"; + case PUGL_KEY_PAD_INSERT: + return "PAD_INSERT"; + case PUGL_KEY_PAD_DELETE: + return "PAD_DELETE"; + case PUGL_KEY_PAD_EQUAL: + return "PAD_EQUAL"; + + case PUGL_KEY_PAD_MULTIPLY: + return "PAD_MULTIPLY"; + case PUGL_KEY_PAD_ADD: + return "PAD_ADD"; + case PUGL_KEY_PAD_SEPARATOR: + return "PAD_SEPARATOR"; + case PUGL_KEY_PAD_SUBTRACT: + return "PAD_SUBTRACT"; + case PUGL_KEY_PAD_DECIMAL: + return "PAD_DECIMAL"; + case PUGL_KEY_PAD_DIVIDE: + return "PAD_DIVIDE"; } return ""; -- cgit v1.2.1