author | Masayuki Nakano <masayuki@d-toybox.com> |
Fri, 16 Feb 2018 15:54:07 +0900 | |
changeset 757696 | 82127c6bae818e6b22435463163d887d68342561 |
parent 757695 | c5deee2cb9e0f488982fc4167d7c3c0a426ffa7a |
push id | 99837 |
push user | masayuki@d-toybox.com |
push date | Wed, 21 Feb 2018 05:42:40 +0000 |
reviewers | smaug |
bugs | 1036008 |
milestone | 60.0a1 |
--- a/widget/TextEvents.h +++ b/widget/TextEvents.h @@ -454,16 +454,27 @@ public: { if (mCodeNameIndex == CODE_NAME_INDEX_USE_STRING) { aCodeName = mCodeValue; return; } GetDOMCodeName(mCodeNameIndex, aCodeName); } + /** + * GetFallbackKeyCodeOfPunctuationKey() returns a DOM keyCode value for + * aCodeNameIndex. This is keyCode value of the key when active keyboard + * layout is ANSI (US), JIS or ABNT keyboard layout (the latter 2 layouts + * are used only when ANSI doesn't have the key). The result is useful + * if the key doesn't produce ASCII character with active keyboard layout + * nor with alternative ASCII capable keyboard layout. + */ + static uint32_t + GetFallbackKeyCodeOfPunctuationKey(CodeNameIndex aCodeNameIndex); + bool IsModifierKeyEvent() const { return GetModifierForKeyName(mKeyNameIndex) != MODIFIER_NONE; } /** * Get the candidates for shortcut key. *
--- a/widget/WidgetEventImpl.cpp +++ b/widget/WidgetEventImpl.cpp @@ -1178,16 +1178,52 @@ WidgetKeyboardEvent::GetCodeNameIndex(co static_cast<CodeNameIndex>(i)); } } CodeNameIndex result = CODE_NAME_INDEX_USE_STRING; sCodeNameIndexHashtable->Get(aCodeValue, &result); return result; } +/* static */ uint32_t +WidgetKeyboardEvent::GetFallbackKeyCodeOfPunctuationKey( + CodeNameIndex aCodeNameIndex) +{ + switch (aCodeNameIndex) { + case CODE_NAME_INDEX_Semicolon: // VK_OEM_1 on Windows + return dom::KeyboardEventBinding::DOM_VK_SEMICOLON; + case CODE_NAME_INDEX_Equal: // VK_OEM_PLUS on Windows + return dom::KeyboardEventBinding::DOM_VK_EQUALS; + case CODE_NAME_INDEX_Comma: // VK_OEM_COMMA on Windows + return dom::KeyboardEventBinding::DOM_VK_COMMA; + case CODE_NAME_INDEX_Minus: // VK_OEM_MINUS on Windows + return dom::KeyboardEventBinding::DOM_VK_HYPHEN_MINUS; + case CODE_NAME_INDEX_Period: // VK_OEM_PERIOD on Windows + return dom::KeyboardEventBinding::DOM_VK_PERIOD; + case CODE_NAME_INDEX_Slash: // VK_OEM_2 on Windows + return dom::KeyboardEventBinding::DOM_VK_SLASH; + case CODE_NAME_INDEX_Backquote: // VK_OEM_3 on Windows + return dom::KeyboardEventBinding::DOM_VK_BACK_QUOTE; + case CODE_NAME_INDEX_BracketLeft: // VK_OEM_4 on Windows + return dom::KeyboardEventBinding::DOM_VK_OPEN_BRACKET; + case CODE_NAME_INDEX_Backslash: // VK_OEM_5 on Windows + return dom::KeyboardEventBinding::DOM_VK_BACK_SLASH; + case CODE_NAME_INDEX_BracketRight: // VK_OEM_6 on Windows + return dom::KeyboardEventBinding::DOM_VK_CLOSE_BRACKET; + case CODE_NAME_INDEX_Quote: // VK_OEM_7 on Windows + return dom::KeyboardEventBinding::DOM_VK_QUOTE; + case CODE_NAME_INDEX_IntlBackslash: // VK_OEM_5 on Windows (ABNT, etc) + case CODE_NAME_INDEX_IntlYen: // VK_OEM_5 on Windows (JIS) + case CODE_NAME_INDEX_IntlRo: // VK_OEM_102 on Windows + return dom::KeyboardEventBinding::DOM_VK_BACK_SLASH; + default: + return 0; + } +} + /* static */ const char* WidgetKeyboardEvent::GetCommandStr(Command aCommand) { #define NS_DEFINE_COMMAND(aName, aCommandStr) , #aCommandStr #define NS_DEFINE_COMMAND_NO_EXEC_COMMAND(aName) static const char* const kCommands[] = { "" // CommandDoNothing #include "mozilla/CommandList.h"
--- a/widget/cocoa/TextInputHandler.mm +++ b/widget/cocoa/TextInputHandler.mm @@ -1405,35 +1405,44 @@ TISInputSourceWrapper::ComputeGeckoKeyCo // If the unshifed char isn't an ASCII character, use shifted char. charCode = TranslateToChar(aNativeKeyCode, modifiers | shiftKey, aKbType); keyCode = WidgetUtils::ComputeKeyCodeFromChar(charCode); if (keyCode) { return keyCode; } - // If this is ASCII capable, give up to compute it. - if (IsASCIICapable()) { - return 0; + if (!IsASCIICapable()) { + // Retry with ASCII capable keyboard layout. + TISInputSourceWrapper currentKeyboardLayout; + currentKeyboardLayout.InitByCurrentASCIICapableKeyboardLayout(); + NS_ENSURE_TRUE(mInputSource != currentKeyboardLayout.mInputSource, 0); + keyCode = currentKeyboardLayout.ComputeGeckoKeyCode(aNativeKeyCode, aKbType, + aCmdIsPressed); + // We've returned 0 for long time if keyCode isn't for an alphabet keys or + // a numeric key even in alternative ASCII capable keyboard layout because + // we decided that we should avoid setting same keyCode value to 2 or + // more keys since active keyboard layout may have a key to input the + // punctuation with different key. However, setting keyCode to 0 makes + // some web applications which are aware of neither KeyboardEvent.key nor + // KeyboardEvent.code not work with Firefox when user selects non-ASCII + // capable keyboard layout such as Russian and Thai. So, if alternative + // ASCII capable keyboard layout has keyCode value for the key, we should + // use it. In other words, this behavior does that non-ASCII capable + // keyboard layout overrides some keys' keyCode value only if the key + // produces ASCII character by itself or with Shift key. + if (keyCode) { + return keyCode; + } } - // Retry with ASCII capable keyboard layout. - TISInputSourceWrapper currentKeyboardLayout; - currentKeyboardLayout.InitByCurrentASCIICapableKeyboardLayout(); - NS_ENSURE_TRUE(mInputSource != currentKeyboardLayout.mInputSource, 0); - keyCode = currentKeyboardLayout.ComputeGeckoKeyCode(aNativeKeyCode, aKbType, - aCmdIsPressed); - - // However, if keyCode isn't for an alphabet keys or a numeric key, we should - // ignore it. For example, comma key of Thai layout is same as close-square- - // bracket key of US layout and an unicode character key of Thai layout is - // same as comma key of US layout. If we return NS_VK_COMMA for latter key, - // web application developers cannot distinguish with the former key. - return ((keyCode >= NS_VK_A && keyCode <= NS_VK_Z) || - (keyCode >= NS_VK_0 && keyCode <= NS_VK_9)) ? keyCode : 0; + // Otherwise, let's decide keyCode value from the native virtual keycode + // value on major keyboard layout. + CodeNameIndex code = ComputeGeckoCodeNameIndex(aNativeKeyCode, aKbType); + return WidgetKeyboardEvent::GetFallbackKeyCodeOfPunctuationKey(code); } // static KeyNameIndex TISInputSourceWrapper::ComputeGeckoKeyNameIndex(UInt32 aNativeKeyCode) { // NOTE: // When unsupported keys like Convert, Nonconvert of Japanese keyboard is
--- a/widget/gtk/nsGtkKeyUtils.cpp +++ b/widget/gtk/nsGtkKeyUtils.cpp @@ -790,17 +790,17 @@ KeymapWrapper::ComputeDOMKeyCode(const G if (IsBasicLatinLetterOrNumeral(unmodifiedChar)) { // If the unmodified character is an ASCII alphabet or an ASCII // numeric, it's the best hint for deciding our keyCode. return WidgetUtils::ComputeKeyCodeFromChar(unmodifiedChar); } // If the unmodified character is not an ASCII character, that means we // couldn't find the hint. We should reset it. - if (unmodifiedChar > 0x7F) { + if (!IsPrintableASCIICharacter(unmodifiedChar)) { unmodifiedChar = 0; } // Retry with shifted keycode. guint shiftState = (baseState | keymapWrapper->GetModifierMask(SHIFT)); uint32_t shiftedChar = keymapWrapper->GetCharCodeFor(aGdkKeyEvent, shiftState, aGdkKeyEvent->group); @@ -809,57 +809,91 @@ KeymapWrapper::ComputeDOMKeyCode(const G // layout. And also shifted character can be an ASCII numeric on // AZERTY keyboad layout. Then, it's a good hint for deciding our // keyCode. return WidgetUtils::ComputeKeyCodeFromChar(shiftedChar); } // If the shifted unmodified character isn't an ASCII character, we should // discard it too. - if (shiftedChar > 0x7F) { + if (!IsPrintableASCIICharacter(shiftedChar)) { shiftedChar = 0; } // If current keyboard layout isn't ASCII alphabet inputtable layout, // look for ASCII alphabet inputtable keyboard layout. If the key // inputs an ASCII alphabet or an ASCII numeric, we should use it // for deciding our keyCode. - // Note that it's important not to use alternative keyboard layout for ASCII - // alphabet inputabble keyboard layout because the keycode for the key with - // alternative keyboard layout may conflict with another key on current - // keyboard layout. + uint32_t unmodCharLatin = 0; + uint32_t shiftedCharLatin = 0; if (!keymapWrapper->IsLatinGroup(aGdkKeyEvent->group)) { gint minGroup = keymapWrapper->GetFirstLatinGroup(); if (minGroup >= 0) { - uint32_t unmodCharLatin = + unmodCharLatin = keymapWrapper->GetCharCodeFor(aGdkKeyEvent, baseState, minGroup); if (IsBasicLatinLetterOrNumeral(unmodCharLatin)) { // If the unmodified character is an ASCII alphabet or // an ASCII numeric, we should use it for the keyCode. return WidgetUtils::ComputeKeyCodeFromChar(unmodCharLatin); } - uint32_t shiftedCharLatin = + // If the unmodified character in the alternative ASCII capable + // keyboard layout isn't an ASCII character, that means we couldn't + // find the hint. We should reset it. + if (!IsPrintableASCIICharacter(unmodCharLatin)) { + unmodCharLatin = 0; + } + shiftedCharLatin = keymapWrapper->GetCharCodeFor(aGdkKeyEvent, shiftState, minGroup); if (IsBasicLatinLetterOrNumeral(shiftedCharLatin)) { // If the shifted character is an ASCII alphabet or an ASCII // numeric, we should use it for the keyCode. return WidgetUtils::ComputeKeyCodeFromChar(shiftedCharLatin); } + // If the shifted unmodified character in the alternative ASCII + // capable keyboard layout isn't an ASCII character, we should + // discard it too. + if (!IsPrintableASCIICharacter(shiftedCharLatin)) { + shiftedCharLatin = 0; + } } } - // If unmodified character is in ASCII range, use it. Otherwise, use - // shifted character. - if (!unmodifiedChar && !shiftedChar) { - return 0; + // If the key itself or with Shift state on active keyboard layout produces + // an ASCII punctuation character, we should decide keyCode value with it. + if (unmodifiedChar || shiftedChar) { + return WidgetUtils::ComputeKeyCodeFromChar( + unmodifiedChar ? unmodifiedChar : shiftedChar); } - return WidgetUtils::ComputeKeyCodeFromChar( - unmodifiedChar ? unmodifiedChar : shiftedChar); + + // If the key itself or with Shift state on alternative ASCII capable + // keyboard layout produces an ASCII punctuation character, we should + // decide keyCode value with it. Note that We've returned 0 for long + // time if keyCode isn't for an alphabet keys or a numeric key even in + // alternative ASCII capable keyboard layout because we decided that we + // should avoid setting same keyCode value to 2 or more keys since active + // keyboard layout may have a key to input the punctuation with different + // key. However, setting keyCode to 0 makes some web applications which + // are aware of neither KeyboardEvent.key nor KeyboardEvent.code not work + // with Firefox when user selects non-ASCII capable keyboard layout such + // as Russian and Thai. So, if alternative ASCII capable keyboard layout + // has keyCode value for the key, we should use it. In other words, this + // behavior means that non-ASCII capable keyboard layout overrides some + // keys' keyCode value only if the key produces ASCII character by itself + // or with Shift key. + if (unmodCharLatin || shiftedCharLatin) { + return WidgetUtils::ComputeKeyCodeFromChar( + unmodCharLatin ? unmodCharLatin : shiftedCharLatin); + } + + // Otherwise, let's decide keyCode value from the hardware_keycode + // value on major keyboard layout. + CodeNameIndex code = ComputeDOMCodeNameIndex(aGdkKeyEvent); + return WidgetKeyboardEvent::GetFallbackKeyCodeOfPunctuationKey(code); } KeyNameIndex KeymapWrapper::ComputeDOMKeyNameIndex(const GdkEventKey* aGdkKeyEvent) { switch (aGdkKeyEvent->keyval) { #define NS_NATIVE_KEY_TO_DOM_KEY_NAME_INDEX(aNativeKey, aKeyNameIndex) \
--- a/widget/gtk/nsGtkKeyUtils.h +++ b/widget/gtk/nsGtkKeyUtils.h @@ -333,16 +333,26 @@ protected: * * @param aCharCode Charcode which you want to test. * @return TRUE if aCharCode is an alphabet or a numeric * in ASCII range. Otherwise, FALSE. */ static bool IsBasicLatinLetterOrNumeral(uint32_t aCharCode); /** + * IsPrintableASCIICharacter() checks whether the aCharCode is a printable + * ASCII character. I.e., returns false if aCharCode is a control + * character even in an ASCII character. + */ + static bool IsPrintableASCIICharacter(uint32_t aCharCode) + { + return aCharCode >= 0x20 && aCharCode <= 0x7E; + } + + /** * GetGDKKeyvalWithoutModifier() returns the keyval for aGdkKeyEvent when * ignoring the modifier state except NumLock. (NumLock is a key to change * some key's meaning.) */ static guint GetGDKKeyvalWithoutModifier(const GdkEventKey *aGdkKeyEvent); /** * GetDOMKeyCodeFromKeyPairs() returns DOM keycode for aGdkKeyval if
--- a/widget/tests/test_keycodes.xul +++ b/widget/tests/test_keycodes.xul @@ -486,17 +486,17 @@ function* runKeyEventTests() "\u00b9", "KeyA", KeyboardEvent.DOM_VK_A, "\u00b9", SHOULD_DELIVER_KEYDOWN_KEYPRESS, KeyboardEvent.DOM_KEY_LOCATION_STANDARD); // German yield testKey({layout:KEYBOARD_LAYOUT_GERMAN, keyCode:MAC_VK_ANSI_A, modifiers: {}, chars:"a", unmodifiedChars:"a"}, "a", "KeyA", KeyboardEvent.DOM_VK_A, "a", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD); yield testKey({layout:KEYBOARD_LAYOUT_GERMAN, keyCode:MAC_VK_ANSI_LeftBracket, modifiers: {}, chars:"\u00fc", unmodifiedChars:"\u00fc"}, - "\u00fc", "BracketLeft", 0, "\u00fc", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD); + "\u00fc", "BracketLeft", KeyboardEvent.DOM_VK_OPEN_BRACKET, "\u00fc", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD); yield testKey({layout:KEYBOARD_LAYOUT_GERMAN, keyCode:MAC_VK_ANSI_Minus, modifiers: {}, chars:"\u00df", unmodifiedChars:"\u00df"}, "\u00df", "Minus", KeyboardEvent.DOM_VK_QUESTION_MARK, "\u00df", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD); yield testKey({layout:KEYBOARD_LAYOUT_GERMAN, keyCode:MAC_VK_ANSI_Minus, modifiers:{shiftKey:1}, chars:"?", unmodifiedChars:"?"}, "?", "Minus", KeyboardEvent.DOM_VK_QUESTION_MARK, "?", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD); // Note that Shift+SS is '?' but Cmd+Shift+SS is '/' on German layout. // Therefore, when Cmd key is pressed, the SS key's keycode is changed. @@ -2729,20 +2729,21 @@ function* runKeyEventTests() // keycode should be DOM_VK_[A-Z] of the key on the latest ASCII capable keyboard layout is for alphabet yield testKey({layout:KEYBOARD_LAYOUT_THAI, keyCode:MAC_VK_ANSI_A, modifiers:{}, chars:"\u0E1F", unmodifiedChars:"\u0E1F"}, "\u0E1F", "KeyA", KeyboardEvent.DOM_VK_A, "\u0E1F", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD); // keycode should be shifted character if unshifted character isn't an ASCII character yield testKey({layout:KEYBOARD_LAYOUT_THAI, keyCode:MAC_VK_ANSI_Quote, modifiers:{}, chars:"\u0E07", unmodifiedChars:"\u0E07"}, "\u0E07", "Quote", KeyboardEvent.DOM_VK_PERIOD, "\u0E07", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD); - // keycode should be zero if the character of the key on the latest ASCII capable keyboard layout isn't for alphabet + // keycode should be same as ANSI keyboard layout's key which causes the native virtual keycode + // if the character of the key on the latest ASCII capable keyboard layout isn't for alphabet yield testKey({layout:KEYBOARD_LAYOUT_THAI, keyCode:MAC_VK_ANSI_Period, modifiers:{}, chars:"\u0E43", unmodifiedChars:"\u0E43"}, - "\u0E43", "Period", 0, "\u0E43", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD); + "\u0E43", "Period", KeyboardEvent.DOM_VK_PERIOD, "\u0E43", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD); // keycode should be DOM_VK_[0-9] if the key on the latest ASCII capable keyboard layout is for numeric yield testKey({layout:KEYBOARD_LAYOUT_THAI, keyCode:MAC_VK_ANSI_1, modifiers:{}, chars:"\u0E45", unmodifiedChars:"\u0E45"}, "\u0E45", "Digit1", KeyboardEvent.DOM_VK_1, "\u0E45", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD); yield testKey({layout:KEYBOARD_LAYOUT_THAI, keyCode:MAC_VK_ANSI_2, modifiers:{}, chars:"/", unmodifiedChars:"/"}, "/", "Digit2", KeyboardEvent.DOM_VK_2, "/", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD); yield testKey({layout:KEYBOARD_LAYOUT_THAI, keyCode:MAC_VK_ANSI_3, @@ -4121,22 +4122,24 @@ function* runKeyEventTests() yield testKey({layout:KEYBOARD_LAYOUT_FRENCH, keyCode:WIN_VK_9, modifiers:{capsLockKey:1}, chars:"9"}, "9", "Digit9", KeyboardEvent.DOM_VK_9, "9", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD); yield testKey({layout:KEYBOARD_LAYOUT_FRENCH, keyCode:WIN_VK_9, modifiers:{capsLockKey:1, shiftKey:1}, chars:"\u00E7"}, "\u00E7", "Digit9", KeyboardEvent.DOM_VK_9, "\u00E7", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD); // OEM keys + // If the key doesn't cause ASCII character even with or without Shift key, keyCode value should be same as + // the key which causes the virtual keycode on ANSI keyboard layout. yield testKey({layout:KEYBOARD_LAYOUT_FRENCH, keyCode:WIN_VK_OEM_7, modifiers:{}, chars:"\u00B2"}, - "\u00B2", "Backquote", 0, "\u00B2", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD); + "\u00B2", "Backquote", KeyboardEvent.DOM_VK_QUOTE, "\u00B2", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD); yield testKey({layout:KEYBOARD_LAYOUT_FRENCH, keyCode:WIN_VK_OEM_7, modifiers:{shiftKey:1}, chars:""}, - "", "Backquote", 0, "", SHOULD_DELIVER_KEYDOWN_KEYUP, KeyboardEvent.DOM_KEY_LOCATION_STANDARD); + "", "Backquote", KeyboardEvent.DOM_VK_QUOTE, "", SHOULD_DELIVER_KEYDOWN_KEYUP, KeyboardEvent.DOM_KEY_LOCATION_STANDARD); yield testKey({layout:KEYBOARD_LAYOUT_FRENCH, keyCode:WIN_VK_OEM_4, modifiers:{}, chars:")"}, ")", "Minus", KeyboardEvent.DOM_VK_CLOSE_PAREN, ")", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD); yield testKey({layout:KEYBOARD_LAYOUT_FRENCH, keyCode:WIN_VK_OEM_4, modifiers:{shiftKey:1}, chars:"\u00B0"}, "\u00B0", "Minus", KeyboardEvent.DOM_VK_CLOSE_PAREN, "\u00B0", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD); yield testKey({layout:KEYBOARD_LAYOUT_FRENCH, keyCode:WIN_VK_OEM_PLUS, modifiers:{}, chars:"="}, @@ -4197,38 +4200,38 @@ function* runKeyEventTests() "!", "Slash", KeyboardEvent.DOM_VK_EXCLAMATION, "!", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD); yield testKey({layout:KEYBOARD_LAYOUT_FRENCH, keyCode:WIN_VK_OEM_8, modifiers:{shiftKey:1}, chars:"\u00A7"}, "\u00A7", "Slash", KeyboardEvent.DOM_VK_EXCLAMATION, "\u00A7", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD); // OEM keys with ShiftLock yield testKey({layout:KEYBOARD_LAYOUT_FRENCH, keyCode:WIN_VK_OEM_7, modifiers:{capsLockKey:1}, chars:"\u00B2"}, - "\u00B2", "Backquote", 0, "\u00B2", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD); + "\u00B2", "Backquote", KeyboardEvent.DOM_VK_QUOTE, "\u00B2", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD); yield testKey({layout:KEYBOARD_LAYOUT_FRENCH, keyCode:WIN_VK_OEM_7, modifiers:{capsLockKey:1, shiftKey:1}, chars:""}, - "", "Backquote", 0, "", SHOULD_DELIVER_KEYDOWN_KEYUP, KeyboardEvent.DOM_KEY_LOCATION_STANDARD); + "", "Backquote", KeyboardEvent.DOM_VK_QUOTE, "", SHOULD_DELIVER_KEYDOWN_KEYUP, KeyboardEvent.DOM_KEY_LOCATION_STANDARD); yield testKey({layout:KEYBOARD_LAYOUT_FRENCH, keyCode:WIN_VK_OEM_4, modifiers:{capsLockKey:1}, chars:"\u00B0"}, "\u00B0", "Minus", KeyboardEvent.DOM_VK_CLOSE_PAREN, "\u00B0", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD); yield testKey({layout:KEYBOARD_LAYOUT_FRENCH, keyCode:WIN_VK_OEM_4, modifiers:{capsLockKey:1, shiftKey:1}, chars:")"}, ")", "Minus", KeyboardEvent.DOM_VK_CLOSE_PAREN, ")", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD); yield testKey({layout:KEYBOARD_LAYOUT_FRENCH, keyCode:WIN_VK_OEM_PLUS, modifiers:{capsLockKey:1}, chars:"+"}, "+", "Equal", KeyboardEvent.DOM_VK_EQUALS, "+", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD); yield testKey({layout:KEYBOARD_LAYOUT_FRENCH, keyCode:WIN_VK_OEM_PLUS, modifiers:{capsLockKey:1, shiftKey:1}, chars:"="}, "=", "Equal", KeyboardEvent.DOM_VK_EQUALS, "=", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD); //yield testKey({layout:KEYBOARD_LAYOUT_FRENCH, keyCode:WIN_VK_OEM_6, // modifiers:{capsLockKey:1}, chars:""}, - // "Dead", "BracketLeft", 0, "", SHOULD_DELIVER_KEYDOWN_KEYUP, KeyboardEvent.DOM_KEY_LOCATION_STANDARD); // Dead-key + // "Dead", "BracketLeft", KeyboardLayout.DOM_VK_CLOSE_BRACKET, "", SHOULD_DELIVER_KEYDOWN_KEYUP, KeyboardEvent.DOM_KEY_LOCATION_STANDARD); // Dead-key //yield testKey({layout:KEYBOARD_LAYOUT_FRENCH, keyCode:WIN_VK_OEM_6, // modifiers:{capsLockKey:1, shiftKey:1}, chars:""}, - // ["\u00A8\u00A8", "\u00A8", "\u00A8", "\u00A8"], "BracketLeft", 0, "", SHOULD_DELIVER_KEYDOWN_KEYUP, KeyboardEvent.DOM_KEY_LOCATION_STANDARD); // Dead-key + // ["\u00A8\u00A8", "\u00A8", "\u00A8", "\u00A8"], "BracketLeft", KeyboardLayout.DOM_VK_CLOSE_BRACKET, "", SHOULD_DELIVER_KEYDOWN_KEYUP, KeyboardEvent.DOM_KEY_LOCATION_STANDARD); // Dead-key yield testKey({layout:KEYBOARD_LAYOUT_FRENCH, keyCode:WIN_VK_OEM_1, modifiers:{capsLockKey:1}, chars:"\u00A3"}, "\u00A3", "BracketRight", KeyboardEvent.DOM_VK_DOLLAR, "\u00A3", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD); yield testKey({layout:KEYBOARD_LAYOUT_FRENCH, keyCode:WIN_VK_OEM_1, modifiers:{capsLockKey:1, shiftKey:1}, chars:"$"}, "$", "BracketRight", KeyboardEvent.DOM_VK_DOLLAR, "$", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD); yield testKey({layout:KEYBOARD_LAYOUT_FRENCH, keyCode:WIN_VK_OEM_3, modifiers:{capsLockKey:1}, chars:"%"}, @@ -4488,66 +4491,66 @@ function* runKeyEventTests() modifiers:{shiftKey:1}, chars:""}, "Dead", "BracketLeft", KeyboardEvent.DOM_VK_BACK_QUOTE, "", SHOULD_DELIVER_KEYDOWN_KEYUP, KeyboardEvent.DOM_KEY_LOCATION_STANDARD); yield testKey({layout:KEYBOARD_LAYOUT_SPANISH, keyCode:WIN_VK_Q, modifiers:{shiftKey:1}, chars:"^Q"}, ["^Q", "^", "Q", "Q"], "KeyQ", KeyboardEvent.DOM_VK_Q, "^Q", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD); yield testKey({layout:KEYBOARD_LAYOUT_SPANISH, keyCode:WIN_VK_OEM_7, modifiers:{}, chars:""}, - "Dead", "Quote", 0, "", SHOULD_DELIVER_KEYDOWN_KEYUP, KeyboardEvent.DOM_KEY_LOCATION_STANDARD); + "Dead", "Quote", KeyboardEvent.DOM_VK_QUOTE, "", SHOULD_DELIVER_KEYDOWN_KEYUP, KeyboardEvent.DOM_KEY_LOCATION_STANDARD); yield testKey({layout:KEYBOARD_LAYOUT_SPANISH, keyCode:WIN_VK_OEM_7, modifiers:{}, chars:"\u00B4\u00B4"}, - ["\u00B4\u00B4", "\u00B4", "\u00B4", "\u00B4"], "Quote", 0, "\u00B4\u00B4", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD); + ["\u00B4\u00B4", "\u00B4", "\u00B4", "\u00B4"], "Quote", KeyboardEvent.DOM_VK_QUOTE, "\u00B4\u00B4", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD); yield testKey({layout:KEYBOARD_LAYOUT_SPANISH, keyCode:WIN_VK_OEM_7, modifiers:{}, chars:""}, - "Dead", "Quote", 0, "", SHOULD_DELIVER_KEYDOWN_KEYUP, KeyboardEvent.DOM_KEY_LOCATION_STANDARD); + "Dead", "Quote", KeyboardEvent.DOM_VK_QUOTE, "", SHOULD_DELIVER_KEYDOWN_KEYUP, KeyboardEvent.DOM_KEY_LOCATION_STANDARD); yield testKey({layout:KEYBOARD_LAYOUT_SPANISH, keyCode:WIN_VK_A, modifiers:{}, chars:"\u00E1"}, ["\u00E1", "\u00E1", "a"], "KeyA", KeyboardEvent.DOM_VK_A, "\u00E1", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD); yield testKey({layout:KEYBOARD_LAYOUT_SPANISH, keyCode:WIN_VK_OEM_7, modifiers:{}, chars:""}, - "Dead", "Quote", 0, "", SHOULD_DELIVER_KEYDOWN_KEYUP, KeyboardEvent.DOM_KEY_LOCATION_STANDARD); + "Dead", "Quote", KeyboardEvent.DOM_VK_QUOTE, "", SHOULD_DELIVER_KEYDOWN_KEYUP, KeyboardEvent.DOM_KEY_LOCATION_STANDARD); yield testKey({layout:KEYBOARD_LAYOUT_SPANISH, keyCode:WIN_VK_A, modifiers:{shiftKey:1}, chars:"\u00C1"}, ["\u00C1", "\u00C1", "A"], "KeyA", KeyboardEvent.DOM_VK_A, "\u00C1", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD); yield testKey({layout:KEYBOARD_LAYOUT_SPANISH, keyCode:WIN_VK_OEM_7, modifiers:{}, chars:""}, - "Dead", "Quote", 0, "", SHOULD_DELIVER_KEYDOWN_KEYUP, KeyboardEvent.DOM_KEY_LOCATION_STANDARD); + "Dead", "Quote", KeyboardEvent.DOM_VK_QUOTE, "", SHOULD_DELIVER_KEYDOWN_KEYUP, KeyboardEvent.DOM_KEY_LOCATION_STANDARD); yield testKey({layout:KEYBOARD_LAYOUT_SPANISH, keyCode:WIN_VK_Q, modifiers:{}, chars:"\u00B4q"}, ["\u00B4q", "\u00B4", "q", "q"], "KeyQ", KeyboardEvent.DOM_VK_Q, "\u00B4q", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD); yield testKey({layout:KEYBOARD_LAYOUT_SPANISH, keyCode:WIN_VK_OEM_7, modifiers:{shiftKey:1}, chars:""}, - "Dead", "Quote", 0, "", SHOULD_DELIVER_KEYDOWN_KEYUP, KeyboardEvent.DOM_KEY_LOCATION_STANDARD); + "Dead", "Quote", KeyboardEvent.DOM_VK_QUOTE, "", SHOULD_DELIVER_KEYDOWN_KEYUP, KeyboardEvent.DOM_KEY_LOCATION_STANDARD); yield testKey({layout:KEYBOARD_LAYOUT_SPANISH, keyCode:WIN_VK_OEM_7, modifiers:{shiftKey:1}, chars:"\u00A8\u00A8"}, - ["\u00A8\u00A8", "\u00A8", "\u00A8", "\u00A8"], "Quote", 0, "\u00A8\u00A8", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD); + ["\u00A8\u00A8", "\u00A8", "\u00A8", "\u00A8"], "Quote", KeyboardEvent.DOM_VK_QUOTE, "\u00A8\u00A8", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD); yield testKey({layout:KEYBOARD_LAYOUT_SPANISH, keyCode:WIN_VK_OEM_7, modifiers:{shiftKey:1}, chars:""}, - "Dead", "Quote", 0, "", SHOULD_DELIVER_KEYDOWN_KEYUP, KeyboardEvent.DOM_KEY_LOCATION_STANDARD); + "Dead", "Quote", KeyboardEvent.DOM_VK_QUOTE, "", SHOULD_DELIVER_KEYDOWN_KEYUP, KeyboardEvent.DOM_KEY_LOCATION_STANDARD); yield testKey({layout:KEYBOARD_LAYOUT_SPANISH, keyCode:WIN_VK_A, modifiers:{shiftKey:1}, chars:"\u00C4"}, ["\u00C4", "\u00C4", "A"], "KeyA", KeyboardEvent.DOM_VK_A, "\u00C4", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD); yield testKey({layout:KEYBOARD_LAYOUT_SPANISH, keyCode:WIN_VK_OEM_7, modifiers:{shiftKey:1}, chars:""}, - "Dead", "Quote", 0, "", SHOULD_DELIVER_KEYDOWN_KEYUP, KeyboardEvent.DOM_KEY_LOCATION_STANDARD); + "Dead", "Quote", KeyboardEvent.DOM_VK_QUOTE, "", SHOULD_DELIVER_KEYDOWN_KEYUP, KeyboardEvent.DOM_KEY_LOCATION_STANDARD); yield testKey({layout:KEYBOARD_LAYOUT_SPANISH, keyCode:WIN_VK_A, modifiers:{}, chars:"\u00E4"}, ["\u00E4", "\u00E4", "a"], "KeyA", KeyboardEvent.DOM_VK_A, "\u00E4", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD); yield testKey({layout:KEYBOARD_LAYOUT_SPANISH, keyCode:WIN_VK_OEM_7, modifiers:{shiftKey:1}, chars:""}, - "Dead", "Quote", 0, "", SHOULD_DELIVER_KEYDOWN_KEYUP, KeyboardEvent.DOM_KEY_LOCATION_STANDARD); + "Dead", "Quote", KeyboardEvent.DOM_VK_QUOTE, "", SHOULD_DELIVER_KEYDOWN_KEYUP, KeyboardEvent.DOM_KEY_LOCATION_STANDARD); yield testKey({layout:KEYBOARD_LAYOUT_SPANISH, keyCode:WIN_VK_Q, modifiers:{shiftKey:1}, chars:"\u00A8Q"}, ["\u00A8Q", "\u00A8", "Q", "Q"], "KeyQ", KeyboardEvent.DOM_VK_Q, "\u00A8Q", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD); if (OS_VERSION >= WIN8) { // On Russian Mnemonic layout, both 'KeyS' and 'KeyC' are dead key. However, the sequence 'KeyS' -> 'KeyC' causes a composite character. yield testKey({layout:KEYBOARD_LAYOUT_RUSSIAN_MNEMONIC, keyCode:WIN_VK_S, modifiers:{}, chars:""},
--- a/widget/windows/KeyboardLayout.cpp +++ b/widget/windows/KeyboardLayout.cpp @@ -4716,17 +4716,85 @@ KeyboardLayout::ConvertNativeKeyCodeToDO UniCharsAndModifiers uniChars = GetUniCharsAndModifiers(aNativeKeyCode, modKeyState); if (uniChars.Length() != 1 || uniChars.CharAt(0) < ' ' || uniChars.CharAt(0) > 0x7F) { modKeyState.Set(MODIFIER_SHIFT); uniChars = GetUniCharsAndModifiers(aNativeKeyCode, modKeyState); if (uniChars.Length() != 1 || uniChars.CharAt(0) < ' ' || uniChars.CharAt(0) > 0x7F) { - return 0; + // In this case, we've returned 0 in this case for long time because + // we decided that we should avoid setting same keyCode value to 2 or + // more keys since active keyboard layout may have a key to input the + // punctuation with different key. However, setting keyCode to 0 + // makes some web applications which are aware of neither + // KeyboardEvent.key nor KeyboardEvent.code not work with Firefox + // when user selects non-ASCII capable keyboard layout such as + // Russian and Thai layout. So, let's decide keyCode value with + // major keyboard layout's key which causes the OEM keycode. + // Actually, this maps same keyCode value to 2 keys on Russian + // keyboard layout. "Period" key causes VK_OEM_PERIOD but inputs + // Yu of Cyrillic and "Slash" key causes VK_OEM_2 (same as US + // keyboard layout) but inputs "." (period of ASCII). Therefore, + // we return DOM_VK_PERIOD which is same as VK_OEM_PERIOD for + // "Period" key. On the other hand, we use same keyCode value for + // "Slash" key too because it inputs ".". + CodeNameIndex code; + switch (aNativeKeyCode) { + case VK_OEM_1: + code = CODE_NAME_INDEX_Semicolon; + break; + case VK_OEM_PLUS: + code = CODE_NAME_INDEX_Equal; + break; + case VK_OEM_COMMA: + code = CODE_NAME_INDEX_Comma; + break; + case VK_OEM_MINUS: + code = CODE_NAME_INDEX_Minus; + break; + case VK_OEM_PERIOD: + code = CODE_NAME_INDEX_Period; + break; + case VK_OEM_2: + code = CODE_NAME_INDEX_Slash; + break; + case VK_OEM_3: + code = CODE_NAME_INDEX_Backquote; + break; + case VK_OEM_4: + code = CODE_NAME_INDEX_BracketLeft; + break; + case VK_OEM_5: + code = CODE_NAME_INDEX_Backslash; + break; + case VK_OEM_6: + code = CODE_NAME_INDEX_BracketRight; + break; + case VK_OEM_7: + code = CODE_NAME_INDEX_Quote; + break; + case VK_OEM_8: + // Use keyCode value for "Backquote" key on UK keyboard layout. + code = CODE_NAME_INDEX_Backquote; + break; + case VK_OEM_102: + // Use keyCode value for "IntlBackslash" key. + code = CODE_NAME_INDEX_IntlBackslash; + break; + case VK_ABNT_C1: // "/" of ABNT. + // Use keyCode value for "IntlBackslash" key on ABNT keyboard + // layout. + code = CODE_NAME_INDEX_IntlBackslash; + break; + default: + MOZ_ASSERT_UNREACHABLE("Handle all OEM keycode values"); + return 0; + } + return WidgetKeyboardEvent::GetFallbackKeyCodeOfPunctuationKey(code); } } return WidgetUtils::ComputeKeyCodeFromChar(uniChars.CharAt(0)); } // IE sets 0xC2 to the DOM keyCode for VK_ABNT_C2. However, we're already // using NS_VK_SEPARATOR for the separator key on Mac and Linux. Therefore, // We should keep consistency between Gecko on all platforms rather than