remote/browser/KeyEventProcessing.cpp (519 lines of code) (raw):

#include "include/cef_base.h" #if defined(OS_MAC) #include <Carbon/Carbon.h> #endif #if defined(OS_LINUX) #define XK_3270 // for XK_3270_BackTab #include <X11/XF86keysym.h> #include <X11/keysym.h> #endif namespace { // // Constants from KeyEvent.java // NOTE: wasn't modified last xx years and it seems that we can // just copy them (jcef reads them from class via JNI) // // TODO: write key-event tests for various keys // const int JAVA_KEY_FIRST = 400; const int JAVA_KEY_TYPED = JAVA_KEY_FIRST; const int JAVA_KEY_PRESSED = 1 + JAVA_KEY_FIRST; // Event.KEY_PRESS const int JAVA_KEY_RELEASED = 2 + JAVA_KEY_FIRST; // Event.KEY_RELEASE const int JAVA_VK_ENTER = '\n'; const int JAVA_VK_BACK_SPACE = '\b'; const int JAVA_VK_TAB = '\t'; const int JAVA_VK_CANCEL = 0x03; const int JAVA_VK_CLEAR = 0x0C; const int JAVA_VK_SHIFT = 0x10; const int JAVA_VK_CONTROL = 0x11; const int JAVA_VK_ALT = 0x12; const int JAVA_VK_PAUSE = 0x13; const int JAVA_VK_CAPS_LOCK = 0x14; const int JAVA_VK_ESCAPE = 0x1B; const int JAVA_VK_SPACE = 0x20; const int JAVA_VK_PAGE_UP = 0x21; const int JAVA_VK_PAGE_DOWN = 0x22; const int JAVA_VK_END = 0x23; const int JAVA_VK_HOME = 0x24; const int JAVA_VK_LEFT = 0x25; const int JAVA_VK_UP = 0x26; const int JAVA_VK_RIGHT = 0x27; const int JAVA_VK_DOWN = 0x28; const int JAVA_VK_COMMA = 0x2C; const int JAVA_VK_MINUS = 0x2D; const int JAVA_VK_PERIOD = 0x2E; const int JAVA_VK_SLASH = 0x2F; const int JAVA_VK_0 = 0x30; const int JAVA_VK_1 = 0x31; const int JAVA_VK_2 = 0x32; const int JAVA_VK_3 = 0x33; const int JAVA_VK_4 = 0x34; const int JAVA_VK_5 = 0x35; const int JAVA_VK_6 = 0x36; const int JAVA_VK_7 = 0x37; const int JAVA_VK_8 = 0x38; const int JAVA_VK_9 = 0x39; const int JAVA_VK_SEMICOLON = 0x3B; const int JAVA_VK_EQUALS = 0x3D; const int JAVA_VK_A = 0x41; const int JAVA_VK_B = 0x42; const int JAVA_VK_C = 0x43; const int JAVA_VK_D = 0x44; const int JAVA_VK_E = 0x45; const int JAVA_VK_F = 0x46; const int JAVA_VK_G = 0x47; const int JAVA_VK_H = 0x48; const int JAVA_VK_I = 0x49; const int JAVA_VK_J = 0x4A; const int JAVA_VK_K = 0x4B; const int JAVA_VK_L = 0x4C; const int JAVA_VK_M = 0x4D; const int JAVA_VK_N = 0x4E; const int JAVA_VK_O = 0x4F; const int JAVA_VK_P = 0x50; const int JAVA_VK_Q = 0x51; const int JAVA_VK_R = 0x52; const int JAVA_VK_S = 0x53; const int JAVA_VK_T = 0x54; const int JAVA_VK_U = 0x55; const int JAVA_VK_V = 0x56; const int JAVA_VK_W = 0x57; const int JAVA_VK_X = 0x58; const int JAVA_VK_Y = 0x59; const int JAVA_VK_Z = 0x5A; const int JAVA_VK_OPEN_BRACKET = 0x5B; const int JAVA_VK_BACK_SLASH = 0x5C; const int JAVA_VK_CLOSE_BRACKET = 0x5D; const int JAVA_VK_NUMPAD0 = 0x60; const int JAVA_VK_NUMPAD1 = 0x61; const int JAVA_VK_NUMPAD2 = 0x62; const int JAVA_VK_NUMPAD3 = 0x63; const int JAVA_VK_NUMPAD4 = 0x64; const int JAVA_VK_NUMPAD5 = 0x65; const int JAVA_VK_NUMPAD6 = 0x66; const int JAVA_VK_NUMPAD7 = 0x67; const int JAVA_VK_NUMPAD8 = 0x68; const int JAVA_VK_NUMPAD9 = 0x69; const int JAVA_VK_MULTIPLY = 0x6A; const int JAVA_VK_ADD = 0x6B; const int JAVA_VK_SEPARATER = 0x6C; const int JAVA_VK_SEPARATOR = JAVA_VK_SEPARATER; const int JAVA_VK_SUBTRACT = 0x6D; const int JAVA_VK_DECIMAL = 0x6E; const int JAVA_VK_DIVIDE = 0x6F; const int JAVA_VK_DELETE = 0x7F; const int JAVA_VK_NUM_LOCK = 0x90; const int JAVA_VK_SCROLL_LOCK = 0x91; const int JAVA_VK_F1 = 0x70; const int JAVA_VK_F2 = 0x71; const int JAVA_VK_F3 = 0x72; const int JAVA_VK_F4 = 0x73; const int JAVA_VK_F5 = 0x74; const int JAVA_VK_F6 = 0x75; const int JAVA_VK_F7 = 0x76; const int JAVA_VK_F8 = 0x77; const int JAVA_VK_F9 = 0x78; const int JAVA_VK_F10 = 0x79; const int JAVA_VK_F11 = 0x7A; const int JAVA_VK_F12 = 0x7B; const int JAVA_VK_F13 = 0xF000; const int JAVA_VK_F14 = 0xF001; const int JAVA_VK_F15 = 0xF002; const int JAVA_VK_F16 = 0xF003; const int JAVA_VK_F17 = 0xF004; const int JAVA_VK_F18 = 0xF005; const int JAVA_VK_F19 = 0xF006; const int JAVA_VK_F20 = 0xF007; const int JAVA_VK_F21 = 0xF008; const int JAVA_VK_F22 = 0xF009; const int JAVA_VK_F23 = 0xF00A; const int JAVA_VK_F24 = 0xF00B; const int JAVA_VK_PRINTSCREEN = 0x9A; const int JAVA_VK_INSERT = 0x9B; const int JAVA_VK_HELP = 0x9C; const int JAVA_VK_META = 0x9D; const int JAVA_VK_BACK_QUOTE = 0xC0; const int JAVA_VK_QUOTE = 0xDE; const int JAVA_VK_KP_UP = 0xE0; const int JAVA_VK_KP_DOWN = 0xE1; const int JAVA_VK_KP_LEFT = 0xE2; const int JAVA_VK_KP_RIGHT = 0xE3; const int JAVA_VK_DEAD_GRAVE = 0x80; const int JAVA_VK_DEAD_ACUTE = 0x81; const int JAVA_VK_DEAD_CIRCUMFLEX = 0x82; const int JAVA_VK_DEAD_TILDE = 0x83; const int JAVA_VK_DEAD_MACRON = 0x84; const int JAVA_VK_DEAD_BREVE = 0x85; const int JAVA_VK_DEAD_ABOVEDOT = 0x86; const int JAVA_VK_DEAD_DIAERESIS = 0x87; const int JAVA_VK_DEAD_ABOVERING = 0x88; const int JAVA_VK_DEAD_DOUBLEACUTE = 0x89; const int JAVA_VK_DEAD_CARON = 0x8a; const int JAVA_VK_DEAD_CEDILLA = 0x8b; const int JAVA_VK_DEAD_OGONEK = 0x8c; const int JAVA_VK_DEAD_IOTA = 0x8d; const int JAVA_VK_DEAD_VOICED_SOUND = 0x8e; const int JAVA_VK_DEAD_SEMIVOICED_SOUND = 0x8f; const int JAVA_VK_AMPERSAND = 0x96; const int JAVA_VK_ASTERISK = 0x97; const int JAVA_VK_QUOTEDBL = 0x98; const int JAVA_VK_LESS = 0x99; const int JAVA_VK_GREATER = 0xa0; const int JAVA_VK_BRACELEFT = 0xa1; const int JAVA_VK_BRACERIGHT = 0xa2; const int JAVA_VK_AT = 0x0200; const int JAVA_VK_COLON = 0x0201; const int JAVA_VK_CIRCUMFLEX = 0x0202; const int JAVA_VK_DOLLAR = 0x0203; const int JAVA_VK_EURO_SIGN = 0x0204; const int JAVA_VK_EXCLAMATION_MARK = 0x0205; const int JAVA_VK_INVERTED_EXCLAMATION_MARK = 0x0206; const int JAVA_VK_LEFT_PARENTHESIS = 0x0207; const int JAVA_VK_NUMBER_SIGN = 0x0208; const int JAVA_VK_PLUS = 0x0209; const int JAVA_VK_RIGHT_PARENTHESIS = 0x020A; const int JAVA_VK_UNDERSCORE = 0x020B; const int JAVA_VK_WINDOWS = 0x020C; const int JAVA_VK_CONTEXT_MENU = 0x020D; const int JAVA_VK_FINAL = 0x0018; const int JAVA_VK_CONVERT = 0x001C; const int JAVA_VK_NONCONVERT = 0x001D; const int JAVA_VK_ACCEPT = 0x001E; const int JAVA_VK_MODECHANGE = 0x001F; const int JAVA_VK_KANA = 0x0015; const int JAVA_VK_KANJI = 0x0019; const int JAVA_VK_ALPHANUMERIC = 0x00F0; const int JAVA_VK_KATAKANA = 0x00F1; const int JAVA_VK_HIRAGANA = 0x00F2; const int JAVA_VK_FULL_WIDTH = 0x00F3; const int JAVA_VK_HALF_WIDTH = 0x00F4; const int JAVA_VK_ROMAN_CHARACTERS = 0x00F5; const int JAVA_VK_ALL_CANDIDATES = 0x0100; const int JAVA_VK_PREVIOUS_CANDIDATE = 0x0101; const int JAVA_VK_CODE_INPUT = 0x0102; const int JAVA_VK_JAPANESE_KATAKANA = 0x0103; const int JAVA_VK_JAPANESE_HIRAGANA = 0x0104; const int JAVA_VK_JAPANESE_ROMAN = 0x0105; const int JAVA_VK_KANA_LOCK = 0x0106; const int JAVA_VK_INPUT_METHOD_ON_OFF = 0x0107; const int JAVA_VK_CUT = 0xFFD1; const int JAVA_VK_COPY = 0xFFCD; const int JAVA_VK_PASTE = 0xFFCF; const int JAVA_VK_UNDO = 0xFFCB; const int JAVA_VK_AGAIN = 0xFFC9; const int JAVA_VK_FIND = 0xFFD0; const int JAVA_VK_PROPS = 0xFFCA; const int JAVA_VK_STOP = 0xFFC8; const int JAVA_VK_COMPOSE = 0xFF20; const int JAVA_VK_ALT_GRAPH = 0xFF7E; const int JAVA_VK_BEGIN = 0xFF58; const int JAVA_VK_UNDEFINED = 0x0; const int JAVA_KEY_LOCATION_UNKNOWN = 0; const int JAVA_KEY_LOCATION_STANDARD = 1; const int JAVA_KEY_LOCATION_LEFT = 2; const int JAVA_KEY_LOCATION_RIGHT = 3; const int JAVA_KEY_LOCATION_NUMPAD = 4; // // Constants from InputEvent.java // const int SHIFT_DOWN_MASK = 1 << 6; const int CTRL_DOWN_MASK = 1 << 7; const int META_DOWN_MASK = 1 << 8; const int ALT_DOWN_MASK = 1 << 9; const int BUTTON1_DOWN_MASK = 1 << 10; const int BUTTON2_DOWN_MASK = 1 << 11; const int BUTTON3_DOWN_MASK = 1 << 12; const int ALT_GRAPH_DOWN_MASK = 1 << 13; // // NOTE: next code is modified copy-paste of code from CefBrowser_N.cpp (see SendKeyEvent) // #if defined(OS_MAC) // A convenient array for getting symbol characters on the number keys. const char kShiftCharsForNumberKeys[] = ")!@#$%^&*("; // Convert an ANSI character to a Mac key code. int GetMacKeyCodeFromChar(int key_char) { switch (key_char) { case ' ': return kVK_Space; case '\n': return kVK_Return; case '0': case ')': return kVK_ANSI_0; case '1': case '!': return kVK_ANSI_1; case '2': case '@': return kVK_ANSI_2; case '3': case '#': return kVK_ANSI_3; case '4': case '$': return kVK_ANSI_4; case '5': case '%': return kVK_ANSI_5; case '6': case '^': return kVK_ANSI_6; case '7': case '&': return kVK_ANSI_7; case '8': case '*': return kVK_ANSI_8; case '9': case '(': return kVK_ANSI_9; case 'a': case 'A': return kVK_ANSI_A; case 'b': case 'B': return kVK_ANSI_B; case 'c': case 'C': return kVK_ANSI_C; case 'd': case 'D': return kVK_ANSI_D; case 'e': case 'E': return kVK_ANSI_E; case 'f': case 'F': return kVK_ANSI_F; case 'g': case 'G': return kVK_ANSI_G; case 'h': case 'H': return kVK_ANSI_H; case 'i': case 'I': return kVK_ANSI_I; case 'j': case 'J': return kVK_ANSI_J; case 'k': case 'K': return kVK_ANSI_K; case 'l': case 'L': return kVK_ANSI_L; case 'm': case 'M': return kVK_ANSI_M; case 'n': case 'N': return kVK_ANSI_N; case 'o': case 'O': return kVK_ANSI_O; case 'p': case 'P': return kVK_ANSI_P; case 'q': case 'Q': return kVK_ANSI_Q; case 'r': case 'R': return kVK_ANSI_R; case 's': case 'S': return kVK_ANSI_S; case 't': case 'T': return kVK_ANSI_T; case 'u': case 'U': return kVK_ANSI_U; case 'v': case 'V': return kVK_ANSI_V; case 'w': case 'W': return kVK_ANSI_W; case 'x': case 'X': return kVK_ANSI_X; case 'y': case 'Y': return kVK_ANSI_Y; case 'z': case 'Z': return kVK_ANSI_Z; // U.S. Specific mappings. Mileage may vary. case ';': case ':': return kVK_ANSI_Semicolon; case '=': case '+': return kVK_ANSI_Equal; case ',': case '<': return kVK_ANSI_Comma; case '-': case '_': return kVK_ANSI_Minus; case '.': case '>': return kVK_ANSI_Period; case '/': case '?': return kVK_ANSI_Slash; case '`': case '~': return kVK_ANSI_Grave; case '[': case '{': return kVK_ANSI_LeftBracket; case '\\': case '|': return kVK_ANSI_Backslash; case ']': case '}': return kVK_ANSI_RightBracket; case '\'': case '"': return kVK_ANSI_Quote; } return -1; } #endif // defined(OS_MAC) } // anon namespace int GetCefModifiers(int modifiers) { int cef_modifiers = 0; if (modifiers & (ALT_DOWN_MASK)) cef_modifiers |= EVENTFLAG_ALT_DOWN; if (modifiers & (BUTTON1_DOWN_MASK)) cef_modifiers |= EVENTFLAG_LEFT_MOUSE_BUTTON; if (modifiers & (BUTTON2_DOWN_MASK)) cef_modifiers |= EVENTFLAG_MIDDLE_MOUSE_BUTTON; if (modifiers & (BUTTON3_DOWN_MASK)) cef_modifiers |= EVENTFLAG_RIGHT_MOUSE_BUTTON; if (modifiers & (CTRL_DOWN_MASK)) cef_modifiers |= EVENTFLAG_CONTROL_DOWN; if (modifiers & (META_DOWN_MASK)) cef_modifiers |= EVENTFLAG_COMMAND_DOWN; if (modifiers & (SHIFT_DOWN_MASK)) cef_modifiers |= EVENTFLAG_SHIFT_DOWN; return cef_modifiers; } void processKeyEvent( CefKeyEvent & cef_event, int event_type, // event.getID() int modifiers, // event.getModifiersEx() char16_t key_char, // event.getKeyChar() long scanCode, // event.scancode, windows only int key_code // event.getKeyCode() ) { cef_event.modifiers = GetCefModifiers(modifiers); #if defined(OS_WIN) BYTE VkCode = LOBYTE(MapVirtualKey(scanCode, MAPVK_VSC_TO_VK)); cef_event.native_key_code = (scanCode << 16) | // key scan code 1; // key repeat count #elif defined(OS_LINUX) || defined(OS_MAC) #if defined(OS_LINUX) // cef_event.native_key_code = JavaKeyCode2X11(env, &cls, key_code); // KeyboardCode windows_key_code = // KeyboardCodeFromXKeysym(cef_event.native_key_code); // cef_event.windows // GetWindowsKeyCodeWithoutLocation(windows_key_code); if (cef_event.modifiers & EVENTFLAG_ALT_DOWN) cef_event.is_system_key = true; // if (windows_key_code == JAVA_VKEY_RETURN) { // // We need to treat the enter key as a key press of character \r. This // // is apparently just how webkit handles it and what it expects. // cef_event.unmodified_character = '\r'; // } else { // cef_event.unmodified_character = key_char != '\n' ? key_char : '\r'; // } // If ctrl key is pressed down, then control character shall be input. // if (cef_event.modifiers & EVENTFLAG_CONTROL_DOWN) { // cef_event.character = GetControlCharacter( // windows_key_code, cef_event.modifiers & EVENTFLAG_SHIFT_DOWN); // } else { // cef_event.character = cef_event.unmodified_character; // } #elif defined(OS_MAC) if (key_code == (JAVA_VK_BACK_SPACE)) { cef_event.native_key_code = kVK_Delete; cef_event.unmodified_character = kBackspaceCharCode; } else if (key_code == (JAVA_VK_DELETE)) { cef_event.native_key_code = kVK_ForwardDelete; cef_event.unmodified_character = kDeleteCharCode; } else if (key_code == (JAVA_VK_DOWN)) { cef_event.native_key_code = kVK_DownArrow; cef_event.unmodified_character = /* NSDownArrowFunctionKey */ 0xF701; } else if (key_code == (JAVA_VK_ENTER)) { cef_event.native_key_code = kVK_Return; cef_event.unmodified_character = kReturnCharCode; } else if (key_code == (JAVA_VK_ESCAPE)) { cef_event.native_key_code = kVK_Escape; cef_event.unmodified_character = kEscapeCharCode; } else if (key_code == (JAVA_VK_LEFT)) { cef_event.native_key_code = kVK_LeftArrow; cef_event.unmodified_character = /* NSLeftArrowFunctionKey */ 0xF702; } else if (key_code == (JAVA_VK_RIGHT)) { cef_event.native_key_code = kVK_RightArrow; cef_event.unmodified_character = /* NSRightArrowFunctionKey */ 0xF703; } else if (key_code == (JAVA_VK_TAB)) { cef_event.native_key_code = kVK_Tab; cef_event.unmodified_character = kTabCharCode; } else if (key_code == (JAVA_VK_UP)) { cef_event.native_key_code = kVK_UpArrow; cef_event.unmodified_character = /* NSUpArrowFunctionKey */ 0xF700; } else { cef_event.native_key_code = GetMacKeyCodeFromChar(key_char); if (cef_event.native_key_code == -1) cef_event.native_key_code = 0; if (cef_event.native_key_code == kVK_Return) { cef_event.unmodified_character = kReturnCharCode; } else { cef_event.unmodified_character = key_char; } } cef_event.character = cef_event.unmodified_character; // Fill in |character| according to flags. if (cef_event.modifiers & EVENTFLAG_SHIFT_DOWN) { if (key_char >= '0' && key_char <= '9') { cef_event.character = kShiftCharsForNumberKeys[key_char - '0']; } else if (key_char >= 'A' && key_char <= 'Z') { cef_event.character = 'A' + (key_char - 'A'); } else { switch (cef_event.native_key_code) { case kVK_ANSI_Grave: cef_event.character = '~'; break; case kVK_ANSI_Minus: cef_event.character = '_'; break; case kVK_ANSI_Equal: cef_event.character = '+'; break; case kVK_ANSI_LeftBracket: cef_event.character = '{'; break; case kVK_ANSI_RightBracket: cef_event.character = '}'; break; case kVK_ANSI_Backslash: cef_event.character = '|'; break; case kVK_ANSI_Semicolon: cef_event.character = ':'; break; case kVK_ANSI_Quote: cef_event.character = '\"'; break; case kVK_ANSI_Comma: cef_event.character = '<'; break; case kVK_ANSI_Period: cef_event.character = '>'; break; case kVK_ANSI_Slash: cef_event.character = '?'; break; default: break; } } } // Control characters. if (cef_event.modifiers & EVENTFLAG_CONTROL_DOWN) { if (key_char >= 'A' && key_char <= 'Z') cef_event.character = 1 + key_char - 'A'; else if (cef_event.native_key_code == kVK_ANSI_LeftBracket) cef_event.character = 27; else if (cef_event.native_key_code == kVK_ANSI_Backslash) cef_event.character = 28; else if (cef_event.native_key_code == kVK_ANSI_RightBracket) cef_event.character = 29; } #endif // defined(OS_MAC) #endif // defined(OS_LINUX) || defined(OS_MAC) if (event_type == (JAVA_KEY_PRESSED)) { #if defined(OS_WIN) cef_event.windows_key_code = VkCode; #endif cef_event.type = KEYEVENT_RAWKEYDOWN; } else if (event_type == (JAVA_KEY_RELEASED)) { #if defined(OS_WIN) cef_event.windows_key_code = VkCode; // bits 30 and 31 should always be 1 for WM_KEYUP cef_event.native_key_code |= 0xC0000000; #endif cef_event.type = KEYEVENT_KEYUP; } else if (event_type == (JAVA_KEY_TYPED)) { #if defined(OS_WIN) cef_event.windows_key_code = key_char == '\n' ? '\r' : key_char; #endif cef_event.type = KEYEVENT_CHAR; } }