/* Copyright (c) 2022 Alex Diener This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software. Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. 3. This notice may not be removed or altered from any source distribution. Alex Diener alex@ludobloom.com */ #include "shell/ShellKeyCodes.h" #include "uitoolkit/UIKeyShortcut.h" #include "utilities/IOUtilities.h" #include #include UIKeyShortcut * UIKeyShortcut_single(unsigned int keyCode, unsigned int modifiers) { UIKeyShortcut * shortcut = malloc(sizeof(*shortcut)); shortcut->keyCode = keyCode; shortcut->modifiers = modifiers; shortcut->alternateCount = 0; shortcut->alternates = NULL; return shortcut; } UIKeyShortcut * UIKeyShortcut_multiple(unsigned int keyCode, unsigned int modifiers, ...) { va_list args, argsCopy; va_start(args, modifiers); va_copy(argsCopy, args); unsigned int alternateCount = 0; while (va_arg(argsCopy, unsigned int) != 0) { va_arg(argsCopy, unsigned int); alternateCount++; } UIKeyShortcut * shortcut = malloc(sizeof(*shortcut) + sizeof(*shortcut->alternates) * alternateCount); shortcut->keyCode = keyCode; shortcut->modifiers = modifiers; shortcut->alternateCount = alternateCount; shortcut->alternates = (void *) shortcut + sizeof(*shortcut); for (unsigned int alternateIndex = 0; alternateIndex < alternateCount; alternateIndex++) { shortcut->alternates[alternateIndex].keyCode = va_arg(args, unsigned int); shortcut->alternates[alternateIndex].modifiers = va_arg(args, unsigned int); } return shortcut; } UIKeyShortcut * UIKeyShortcut_copy(UIKeyShortcut * shortcut) { if (shortcut == NULL) { return NULL; } if (shortcut->alternateCount == 0) { return UIKeyShortcut_single(shortcut->keyCode, shortcut->modifiers); } UIKeyShortcut * copy = malloc(sizeof(*copy) + sizeof(*copy->alternates) * shortcut->alternateCount); copy->keyCode = shortcut->keyCode; copy->modifiers = shortcut->modifiers; copy->alternateCount = shortcut->alternateCount; copy->alternates = (void *) copy + sizeof(*copy); for (unsigned int alternateIndex = 0; alternateIndex < shortcut->alternateCount; alternateIndex++) { copy->alternates[alternateIndex] = shortcut->alternates[alternateIndex]; } return copy; } bool UIKeyShortcut_isMatch(UIKeyShortcut * shortcut, unsigned int keyCode, unsigned int modifiers) { if (shortcut == NULL) { return false; } modifiers &= MODIFIER_SHIFT_BIT | MODIFIER_ALT_BIT | MODIFIER_CONTROL_BIT | MODIFIER_COMMAND_BIT; if (keyCode == shortcut->keyCode && modifiers == shortcut->modifiers) { return true; } for (unsigned int alternateIndex = 0; alternateIndex < shortcut->alternateCount; alternateIndex++) { if (keyCode == shortcut->alternates[alternateIndex].keyCode && modifiers == shortcut->alternates[alternateIndex].modifiers) { return true; } } return false; } static const char * getKeyCodeString(unsigned int keyCode) { switch (keyCode) { case KEY_CODE_A: return "A"; case KEY_CODE_B: return "B"; case KEY_CODE_C: return "C"; case KEY_CODE_D: return "D"; case KEY_CODE_E: return "E"; case KEY_CODE_F: return "F"; case KEY_CODE_G: return "G"; case KEY_CODE_H: return "H"; case KEY_CODE_I: return "I"; case KEY_CODE_J: return "J"; case KEY_CODE_K: return "K"; case KEY_CODE_L: return "L"; case KEY_CODE_M: return "M"; case KEY_CODE_N: return "N"; case KEY_CODE_O: return "O"; case KEY_CODE_P: return "P"; case KEY_CODE_Q: return "Q"; case KEY_CODE_R: return "R"; case KEY_CODE_S: return "S"; case KEY_CODE_T: return "T"; case KEY_CODE_U: return "U"; case KEY_CODE_V: return "V"; case KEY_CODE_W: return "W"; case KEY_CODE_X: return "X"; case KEY_CODE_Y: return "Y"; case KEY_CODE_Z: return "Z"; case KEY_CODE_1: return "1"; case KEY_CODE_2: return "2"; case KEY_CODE_3: return "3"; case KEY_CODE_4: return "4"; case KEY_CODE_5: return "5"; case KEY_CODE_6: return "6"; case KEY_CODE_7: return "7"; case KEY_CODE_8: return "8"; case KEY_CODE_9: return "9"; case KEY_CODE_0: return "0"; case KEY_CODE_ENTER: return "Enter"; case KEY_CODE_ESCAPE: return "Esc"; case KEY_CODE_BACKSPACE: return "Backspace"; case KEY_CODE_TAB: return "Tab"; case KEY_CODE_SPACE: return "Space"; case KEY_CODE_MINUS: return "-"; case KEY_CODE_EQUAL: return "="; case KEY_CODE_OPEN_BRACKET: return "["; case KEY_CODE_CLOSE_BRACKET: return "]"; case KEY_CODE_BACKSLASH: return "\\"; case KEY_CODE_SEMICOLON: return ";"; case KEY_CODE_SINGLE_QUOTE: return "'"; case KEY_CODE_BACKTICK: return "`"; case KEY_CODE_COMMA: return ","; case KEY_CODE_PERIOD: return "."; case KEY_CODE_SLASH: return "/"; case KEY_CODE_F1: return "F1"; case KEY_CODE_F2: return "F2"; case KEY_CODE_F3: return "F3"; case KEY_CODE_F4: return "F4"; case KEY_CODE_F5: return "F5"; case KEY_CODE_F6: return "F6"; case KEY_CODE_F7: return "F7"; case KEY_CODE_F8: return "F8"; case KEY_CODE_F9: return "F9"; case KEY_CODE_F10: return "F10"; case KEY_CODE_F11: return "F11"; case KEY_CODE_F12: return "F12"; case KEY_CODE_PRINT_SCREEN: return "PrintScr"; case KEY_CODE_SCROLL_LOCK: return "ScrlLock"; case KEY_CODE_PAUSE: return "Pause"; case KEY_CODE_INSERT: return "Ins"; case KEY_CODE_HOME: return "Home"; case KEY_CODE_PAGE_UP: return "PgUp"; case KEY_CODE_FORWARD_DELETE: return "Del"; case KEY_CODE_END: return "End"; case KEY_CODE_PAGE_DOWN: return "PgDn"; case KEY_CODE_RIGHT_ARROW: return "Right"; case KEY_CODE_LEFT_ARROW: return "Left"; case KEY_CODE_DOWN_ARROW: return "Down"; case KEY_CODE_UP_ARROW: return "Up"; case KEY_CODE_NUMPAD_SLASH: return "Numpad /"; case KEY_CODE_NUMPAD_ASTERISK: return "Numpad *"; case KEY_CODE_NUMPAD_MINUS: return "Numpad -"; case KEY_CODE_NUMPAD_PLUS: return "Numpad +"; case KEY_CODE_NUMPAD_ENTER: return "Numpad Enter"; case KEY_CODE_NUMPAD_1: return "Numpad 1"; case KEY_CODE_NUMPAD_2: return "Numpad 2"; case KEY_CODE_NUMPAD_3: return "Numpad 3"; case KEY_CODE_NUMPAD_4: return "Numpad 4"; case KEY_CODE_NUMPAD_5: return "Numpad 5"; case KEY_CODE_NUMPAD_6: return "Numpad 6"; case KEY_CODE_NUMPAD_7: return "Numpad 7"; case KEY_CODE_NUMPAD_8: return "Numpad 8"; case KEY_CODE_NUMPAD_9: return "Numpad 9"; case KEY_CODE_NUMPAD_0: return "Numpad 0"; case KEY_CODE_NUMPAD_PERIOD: return "Numpad ."; case KEY_CODE_NUMPAD_EQUAL: return "Numpad ="; case KEY_CODE_F13: return "F13"; case KEY_CODE_F14: return "F14"; case KEY_CODE_F15: return "F15"; } return "(unknown)"; } void UIKeyShortcut_getHumanReadableString(UIKeyShortcut * shortcut, char * outString, size_t lengthMax) { if (lengthMax == 0) { return; } outString[0] = 0; if (shortcut != NULL) { if (shortcut->modifiers & MODIFIER_COMMAND_BIT) { strncpy_safe(outString, "Cmd ", lengthMax); } if (shortcut->modifiers & MODIFIER_CONTROL_BIT) { strncat_safe(outString, "Ctrl ", lengthMax); } if (shortcut->modifiers & MODIFIER_ALT_BIT) { strncat_safe(outString, "Alt ", lengthMax); } if (shortcut->modifiers & MODIFIER_SHIFT_BIT) { strncat_safe(outString, "Shift ", lengthMax); } strncat_safe(outString, getKeyCodeString(shortcut->keyCode), lengthMax); } }