// Copyright (c) 2015 GitHub, Inc. // Use of this source code is governed by the MIT license that can be // found in the LICENSE file. #include #include "base/containers/fixed_flat_map.h" #include "base/strings/string_util.h" #include "shell/common/keyboard_util.h" #include "third_party/blink/public/common/input/web_input_event.h" #include "ui/events/event_constants.h" namespace electron { namespace { using CodeAndShiftedChar = std::pair>; // TODO: Why does making this constexpr fail CodeAndShiftedChar KeyboardCodeFromKeyIdentifier(const std::string_view str) { #if BUILDFLAG(IS_MAC) constexpr auto CommandOrControl = ui::VKEY_COMMAND; #else constexpr auto CommandOrControl = ui::VKEY_CONTROL; #endif constexpr auto Lookup = base::MakeFixedFlatMap({ {"alt", {ui::VKEY_MENU, {}}}, {"altgr", {ui::VKEY_ALTGR, {}}}, {"backspace", {ui::VKEY_BACK, {}}}, {"capslock", {ui::VKEY_CAPITAL, {}}}, {"cmd", {ui::VKEY_COMMAND, {}}}, {"cmdorctrl", {CommandOrControl, {}}}, {"command", {ui::VKEY_COMMAND, {}}}, {"commandorcontrol", {CommandOrControl, {}}}, {"control", {ui::VKEY_CONTROL, {}}}, {"ctrl", {ui::VKEY_CONTROL, {}}}, {"delete", {ui::VKEY_DELETE, {}}}, {"down", {ui::VKEY_DOWN, {}}}, {"end", {ui::VKEY_END, {}}}, {"enter", {ui::VKEY_RETURN, {}}}, {"esc", {ui::VKEY_ESCAPE, {}}}, {"escape", {ui::VKEY_ESCAPE, {}}}, {"f1", {ui::VKEY_F1, {}}}, {"f10", {ui::VKEY_F10, {}}}, {"f11", {ui::VKEY_F11, {}}}, {"f12", {ui::VKEY_F12, {}}}, {"f13", {ui::VKEY_F13, {}}}, {"f14", {ui::VKEY_F14, {}}}, {"f15", {ui::VKEY_F15, {}}}, {"f16", {ui::VKEY_F16, {}}}, {"f17", {ui::VKEY_F17, {}}}, {"f18", {ui::VKEY_F18, {}}}, {"f19", {ui::VKEY_F19, {}}}, {"f2", {ui::VKEY_F2, {}}}, {"f20", {ui::VKEY_F20, {}}}, {"f21", {ui::VKEY_F21, {}}}, {"f22", {ui::VKEY_F22, {}}}, {"f23", {ui::VKEY_F23, {}}}, {"f24", {ui::VKEY_F24, {}}}, {"f3", {ui::VKEY_F3, {}}}, {"f4", {ui::VKEY_F4, {}}}, {"f5", {ui::VKEY_F5, {}}}, {"f6", {ui::VKEY_F6, {}}}, {"f7", {ui::VKEY_F7, {}}}, {"f8", {ui::VKEY_F8, {}}}, {"f9", {ui::VKEY_F9, {}}}, {"home", {ui::VKEY_HOME, {}}}, {"insert", {ui::VKEY_INSERT, {}}}, {"left", {ui::VKEY_LEFT, {}}}, {"medianexttrack", {ui::VKEY_MEDIA_NEXT_TRACK, {}}}, {"mediaplaypause", {ui::VKEY_MEDIA_PLAY_PAUSE, {}}}, {"mediaprevioustrack", {ui::VKEY_MEDIA_PREV_TRACK, {}}}, {"mediastop", {ui::VKEY_MEDIA_STOP, {}}}, {"meta", {ui::VKEY_COMMAND, {}}}, {"num0", {ui::VKEY_NUMPAD0, {}}}, {"num1", {ui::VKEY_NUMPAD1, {}}}, {"num2", {ui::VKEY_NUMPAD2, {}}}, {"num3", {ui::VKEY_NUMPAD3, {}}}, {"num4", {ui::VKEY_NUMPAD4, {}}}, {"num5", {ui::VKEY_NUMPAD5, {}}}, {"num6", {ui::VKEY_NUMPAD6, {}}}, {"num7", {ui::VKEY_NUMPAD7, {}}}, {"num8", {ui::VKEY_NUMPAD8, {}}}, {"num9", {ui::VKEY_NUMPAD9, {}}}, {"numadd", {ui::VKEY_ADD, {}}}, {"numdec", {ui::VKEY_DECIMAL, {}}}, {"numdiv", {ui::VKEY_DIVIDE, {}}}, {"numlock", {ui::VKEY_NUMLOCK, {}}}, {"nummult", {ui::VKEY_MULTIPLY, {}}}, {"numsub", {ui::VKEY_SUBTRACT, {}}}, {"option", {ui::VKEY_MENU, {}}}, {"pagedown", {ui::VKEY_NEXT, {}}}, {"pageup", {ui::VKEY_PRIOR, {}}}, {"plus", {ui::VKEY_OEM_PLUS, '+'}}, {"printscreen", {ui::VKEY_SNAPSHOT, {}}}, {"return", {ui::VKEY_RETURN, {}}}, {"right", {ui::VKEY_RIGHT, {}}}, {"scrolllock", {ui::VKEY_SCROLL, {}}}, {"shift", {ui::VKEY_SHIFT, {}}}, {"space", {ui::VKEY_SPACE, {}}}, {"super", {ui::VKEY_COMMAND, {}}}, {"tab", {ui::VKEY_TAB, {}}}, {"up", {ui::VKEY_UP, {}}}, {"volumedown", {ui::VKEY_VOLUME_DOWN, {}}}, {"volumemute", {ui::VKEY_VOLUME_MUTE, {}}}, {"volumeup", {ui::VKEY_VOLUME_UP, {}}}, }); if (auto* const iter = Lookup.find(str); iter != Lookup.end()) return iter->second; return {ui::VKEY_UNKNOWN, {}}; } constexpr CodeAndShiftedChar KeyboardCodeFromCharCode(char16_t c) { switch (c) { case ' ': return {ui::VKEY_SPACE, {}}; case '!': return {ui::VKEY_1, '!'}; case '"': return {ui::VKEY_OEM_7, '"'}; case '#': return {ui::VKEY_3, '#'}; case '$': return {ui::VKEY_4, '$'}; case '%': return {ui::VKEY_5, '%'}; case '&': return {ui::VKEY_7, '&'}; case '(': return {ui::VKEY_9, '('}; case ')': return {ui::VKEY_0, ')'}; case '*': return {ui::VKEY_8, '*'}; case '+': return {ui::VKEY_OEM_PLUS, '+'}; case ',': return {ui::VKEY_OEM_COMMA, {}}; case '-': return {ui::VKEY_OEM_MINUS, {}}; case '.': return {ui::VKEY_OEM_PERIOD, {}}; case '/': return {ui::VKEY_OEM_2, {}}; case '0': return {ui::VKEY_0, {}}; case '1': return {ui::VKEY_1, {}}; case '2': return {ui::VKEY_2, {}}; case '3': return {ui::VKEY_3, {}}; case '4': return {ui::VKEY_4, {}}; case '5': return {ui::VKEY_5, {}}; case '6': return {ui::VKEY_6, {}}; case '7': return {ui::VKEY_7, {}}; case '8': return {ui::VKEY_8, {}}; case '9': return {ui::VKEY_9, {}}; case ':': return {ui::VKEY_OEM_1, ':'}; case ';': return {ui::VKEY_OEM_1, {}}; case '<': return {ui::VKEY_OEM_COMMA, '<'}; case '=': return {ui::VKEY_OEM_PLUS, {}}; case '>': return {ui::VKEY_OEM_PERIOD, '>'}; case '?': return {ui::VKEY_OEM_2, '?'}; case '@': return {ui::VKEY_2, '@'}; case '[': return {ui::VKEY_OEM_4, {}}; case '\'': return {ui::VKEY_OEM_7, {}}; case '\\': return {ui::VKEY_OEM_5, {}}; case ']': return {ui::VKEY_OEM_6, {}}; case '^': return {ui::VKEY_6, '^'}; case '_': return {ui::VKEY_OEM_MINUS, '_'}; case '`': return {ui::VKEY_OEM_3, {}}; case 'a': return {ui::VKEY_A, {}}; case 'b': return {ui::VKEY_B, {}}; case 'c': return {ui::VKEY_C, {}}; case 'd': return {ui::VKEY_D, {}}; case 'e': return {ui::VKEY_E, {}}; case 'f': return {ui::VKEY_F, {}}; case 'g': return {ui::VKEY_G, {}}; case 'h': return {ui::VKEY_H, {}}; case 'i': return {ui::VKEY_I, {}}; case 'j': return {ui::VKEY_J, {}}; case 'k': return {ui::VKEY_K, {}}; case 'l': return {ui::VKEY_L, {}}; case 'm': return {ui::VKEY_M, {}}; case 'n': return {ui::VKEY_N, {}}; case 'o': return {ui::VKEY_O, {}}; case 'p': return {ui::VKEY_P, {}}; case 'q': return {ui::VKEY_Q, {}}; case 'r': return {ui::VKEY_R, {}}; case 's': return {ui::VKEY_S, {}}; case 't': return {ui::VKEY_T, {}}; case 'u': return {ui::VKEY_U, {}}; case 'v': return {ui::VKEY_V, {}}; case 'w': return {ui::VKEY_W, {}}; case 'x': return {ui::VKEY_X, {}}; case 'y': return {ui::VKEY_Y, {}}; case 'z': return {ui::VKEY_Z, {}}; case '{': return {ui::VKEY_OEM_4, '{'}; case '|': return {ui::VKEY_OEM_5, '|'}; case '}': return {ui::VKEY_OEM_6, '}'}; case '~': return {ui::VKEY_OEM_3, '~'}; case 0x08: return {ui::VKEY_BACK, {}}; case 0x09: return {ui::VKEY_TAB, {}}; case 0x0D: return {ui::VKEY_RETURN, {}}; case 0x1B: return {ui::VKEY_ESCAPE, {}}; case 0x7F: return {ui::VKEY_DELETE, {}}; default: return {ui::VKEY_UNKNOWN, {}}; } } } // namespace ui::KeyboardCode KeyboardCodeFromStr(const std::string_view str, std::optional* shifted_char) { auto const [code, shifted] = str.size() == 1 ? KeyboardCodeFromCharCode(base::ToLowerASCII(str[0])) : KeyboardCodeFromKeyIdentifier(base::ToLowerASCII(str)); if (code == ui::VKEY_UNKNOWN) LOG(WARNING) << "Invalid accelerator token: " << str; *shifted_char = shifted; return code; } } // namespace electron