Bug 1036008 - Use alternative ASCII capable keyboard layout information to decide keyCode even if the key produces an ASCII punctuation character r=smaug

Gecko decides keyCode from an ASCII character which is produced by the key
by itself or with Shift on active keyboard layout or alternative ASCII capable
keyboard layout if active keyboard layout isn't ASCII capable.  However, we've
ignored alternative ASCII capable keyboard layout's character if both the
key itself and with Shift don't produce ASCII alphabet nor ASCII numeral,
i.e., ASCII punctuation characters are not used in alternative ASCII capable
keyboard layout because of avoiding mapping a keyCode value to 2 or more keys.

However, setting 0 to keyCode value makes Firefox unusable with some web
applications which are aware of neither KeyboardEvent.key nor
KeyboardEvent.code.  So, even if we map same keyCode value to a key, we should
avoid setting keyCode value to 0 as far as possible.

This patch's approach is, we behave same keyCode value as the alternative ASCII
capable keyCode is selected when computed keyCode value of active keyboard
layout is 0.  This means that we will make some language users whose keyboard
layout for their language is not ASCII capable can use global web services
which support US keyboard layout of Firefox since the new keyCode values
are mostly computed with US layout on Windows or actual alternative ASCII
capable keyboard layout on macOS and Linux.  In other words, we cannot improve
compatibility with web applications which don't support Firefox  by this patch
since our keyCode values are really different from Chrome's.  So, unfortunately,
if we'd use exactly same keyCode computation as Chromium, we'd break
compatibility with existing web applications which are aware of Firefox since
it's necessary to check UA name or something before using keyCode values.

Note that the most important difference between Windows and the others is,
such keyCode value is computed with alternative ASCII capable keyboard
layout on macOS and Linux but only on Windows, it's computed with OEM virtual
keycode.  This means that only on Windows, the keyCode value may be different
from actual alternative ASCII capable keyboard layout's keyCode.

MozReview-Commit-ID: As289r9wp6i

--HG--
extra : rebase_source : 66181403dbe8ca8dab893edc8f4eec1991d544d0
This commit is contained in:
Masayuki Nakano 2018-02-16 15:54:07 +09:00
parent 98c246e41e
commit ed18f14624
7 changed files with 222 additions and 51 deletions

View File

@ -459,6 +459,17 @@ public:
GetDOMCodeName(mCodeNameIndex, aCodeName); 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 bool IsModifierKeyEvent() const
{ {
return GetModifierForKeyName(mKeyNameIndex) != MODIFIER_NONE; return GetModifierForKeyName(mKeyNameIndex) != MODIFIER_NONE;

View File

@ -1183,6 +1183,42 @@ WidgetKeyboardEvent::GetCodeNameIndex(const nsAString& aCodeValue)
return 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* /* static */ const char*
WidgetKeyboardEvent::GetCommandStr(Command aCommand) WidgetKeyboardEvent::GetCommandStr(Command aCommand)
{ {

View File

@ -1410,25 +1410,34 @@ TISInputSourceWrapper::ComputeGeckoKeyCode(UInt32 aNativeKeyCode,
return keyCode; return keyCode;
} }
// If this is ASCII capable, give up to compute it. if (!IsASCIICapable()) {
if (IsASCIICapable()) { // Retry with ASCII capable keyboard layout.
return 0; 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. // Otherwise, let's decide keyCode value from the native virtual keycode
TISInputSourceWrapper currentKeyboardLayout; // value on major keyboard layout.
currentKeyboardLayout.InitByCurrentASCIICapableKeyboardLayout(); CodeNameIndex code = ComputeGeckoCodeNameIndex(aNativeKeyCode, aKbType);
NS_ENSURE_TRUE(mInputSource != currentKeyboardLayout.mInputSource, 0); return WidgetKeyboardEvent::GetFallbackKeyCodeOfPunctuationKey(code);
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;
} }
// static // static

View File

@ -795,7 +795,7 @@ KeymapWrapper::ComputeDOMKeyCode(const GdkEventKey* aGdkKeyEvent)
// If the unmodified character is not an ASCII character, that means we // If the unmodified character is not an ASCII character, that means we
// couldn't find the hint. We should reset it. // couldn't find the hint. We should reset it.
if (unmodifiedChar > 0x7F) { if (!IsPrintableASCIICharacter(unmodifiedChar)) {
unmodifiedChar = 0; unmodifiedChar = 0;
} }
@ -814,7 +814,7 @@ KeymapWrapper::ComputeDOMKeyCode(const GdkEventKey* aGdkKeyEvent)
// If the shifted unmodified character isn't an ASCII character, we should // If the shifted unmodified character isn't an ASCII character, we should
// discard it too. // discard it too.
if (shiftedChar > 0x7F) { if (!IsPrintableASCIICharacter(shiftedChar)) {
shiftedChar = 0; shiftedChar = 0;
} }
@ -822,14 +822,12 @@ KeymapWrapper::ComputeDOMKeyCode(const GdkEventKey* aGdkKeyEvent)
// look for ASCII alphabet inputtable keyboard layout. If the key // look for ASCII alphabet inputtable keyboard layout. If the key
// inputs an ASCII alphabet or an ASCII numeric, we should use it // inputs an ASCII alphabet or an ASCII numeric, we should use it
// for deciding our keyCode. // for deciding our keyCode.
// Note that it's important not to use alternative keyboard layout for ASCII uint32_t unmodCharLatin = 0;
// alphabet inputabble keyboard layout because the keycode for the key with uint32_t shiftedCharLatin = 0;
// alternative keyboard layout may conflict with another key on current
// keyboard layout.
if (!keymapWrapper->IsLatinGroup(aGdkKeyEvent->group)) { if (!keymapWrapper->IsLatinGroup(aGdkKeyEvent->group)) {
gint minGroup = keymapWrapper->GetFirstLatinGroup(); gint minGroup = keymapWrapper->GetFirstLatinGroup();
if (minGroup >= 0) { if (minGroup >= 0) {
uint32_t unmodCharLatin = unmodCharLatin =
keymapWrapper->GetCharCodeFor(aGdkKeyEvent, baseState, keymapWrapper->GetCharCodeFor(aGdkKeyEvent, baseState,
minGroup); minGroup);
if (IsBasicLatinLetterOrNumeral(unmodCharLatin)) { if (IsBasicLatinLetterOrNumeral(unmodCharLatin)) {
@ -837,7 +835,13 @@ KeymapWrapper::ComputeDOMKeyCode(const GdkEventKey* aGdkKeyEvent)
// an ASCII numeric, we should use it for the keyCode. // an ASCII numeric, we should use it for the keyCode.
return WidgetUtils::ComputeKeyCodeFromChar(unmodCharLatin); 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, keymapWrapper->GetCharCodeFor(aGdkKeyEvent, shiftState,
minGroup); minGroup);
if (IsBasicLatinLetterOrNumeral(shiftedCharLatin)) { if (IsBasicLatinLetterOrNumeral(shiftedCharLatin)) {
@ -845,16 +849,46 @@ KeymapWrapper::ComputeDOMKeyCode(const GdkEventKey* aGdkKeyEvent)
// numeric, we should use it for the keyCode. // numeric, we should use it for the keyCode.
return WidgetUtils::ComputeKeyCodeFromChar(shiftedCharLatin); 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 // If the key itself or with Shift state on active keyboard layout produces
// shifted character. // an ASCII punctuation character, we should decide keyCode value with it.
if (!unmodifiedChar && !shiftedChar) { if (unmodifiedChar || shiftedChar) {
return 0; 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 KeyNameIndex

View File

@ -337,6 +337,16 @@ protected:
*/ */
static bool IsBasicLatinLetterOrNumeral(uint32_t aCharCode); 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 * GetGDKKeyvalWithoutModifier() returns the keyval for aGdkKeyEvent when
* ignoring the modifier state except NumLock. (NumLock is a key to change * ignoring the modifier state except NumLock. (NumLock is a key to change

View File

@ -491,7 +491,7 @@ function* runKeyEventTests()
"a", "KeyA", KeyboardEvent.DOM_VK_A, "a", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD); "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, yield testKey({layout:KEYBOARD_LAYOUT_GERMAN, keyCode:MAC_VK_ANSI_LeftBracket,
modifiers: {}, chars:"\u00fc", unmodifiedChars:"\u00fc"}, 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, yield testKey({layout:KEYBOARD_LAYOUT_GERMAN, keyCode:MAC_VK_ANSI_Minus,
modifiers: {}, chars:"\u00df", unmodifiedChars:"\u00df"}, modifiers: {}, chars:"\u00df", unmodifiedChars:"\u00df"},
"\u00df", "Minus", KeyboardEvent.DOM_VK_QUESTION_MARK, "\u00df", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD); "\u00df", "Minus", KeyboardEvent.DOM_VK_QUESTION_MARK, "\u00df", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
@ -2734,10 +2734,11 @@ function* runKeyEventTests()
yield testKey({layout:KEYBOARD_LAYOUT_THAI, keyCode:MAC_VK_ANSI_Quote, yield testKey({layout:KEYBOARD_LAYOUT_THAI, keyCode:MAC_VK_ANSI_Quote,
modifiers:{}, chars:"\u0E07", unmodifiedChars:"\u0E07"}, modifiers:{}, chars:"\u0E07", unmodifiedChars:"\u0E07"},
"\u0E07", "Quote", KeyboardEvent.DOM_VK_PERIOD, "\u0E07", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD); "\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, yield testKey({layout:KEYBOARD_LAYOUT_THAI, keyCode:MAC_VK_ANSI_Period,
modifiers:{}, chars:"\u0E43", unmodifiedChars:"\u0E43"}, 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 // 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, yield testKey({layout:KEYBOARD_LAYOUT_THAI, keyCode:MAC_VK_ANSI_1,
modifiers:{}, chars:"\u0E45", unmodifiedChars:"\u0E45"}, modifiers:{}, chars:"\u0E45", unmodifiedChars:"\u0E45"},
@ -4126,12 +4127,14 @@ function* runKeyEventTests()
"\u00E7", "Digit9", KeyboardEvent.DOM_VK_9, "\u00E7", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD); "\u00E7", "Digit9", KeyboardEvent.DOM_VK_9, "\u00E7", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
// OEM keys // 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, yield testKey({layout:KEYBOARD_LAYOUT_FRENCH, keyCode:WIN_VK_OEM_7,
modifiers:{}, chars:"\u00B2"}, 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, yield testKey({layout:KEYBOARD_LAYOUT_FRENCH, keyCode:WIN_VK_OEM_7,
modifiers:{shiftKey:1}, chars:""}, 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, yield testKey({layout:KEYBOARD_LAYOUT_FRENCH, keyCode:WIN_VK_OEM_4,
modifiers:{}, chars:")"}, modifiers:{}, chars:")"},
")", "Minus", KeyboardEvent.DOM_VK_CLOSE_PAREN, ")", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD); ")", "Minus", KeyboardEvent.DOM_VK_CLOSE_PAREN, ")", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
@ -4202,10 +4205,10 @@ function* runKeyEventTests()
// OEM keys with ShiftLock // OEM keys with ShiftLock
yield testKey({layout:KEYBOARD_LAYOUT_FRENCH, keyCode:WIN_VK_OEM_7, yield testKey({layout:KEYBOARD_LAYOUT_FRENCH, keyCode:WIN_VK_OEM_7,
modifiers:{capsLockKey:1}, chars:"\u00B2"}, 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, yield testKey({layout:KEYBOARD_LAYOUT_FRENCH, keyCode:WIN_VK_OEM_7,
modifiers:{capsLockKey:1, shiftKey:1}, chars:""}, 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, yield testKey({layout:KEYBOARD_LAYOUT_FRENCH, keyCode:WIN_VK_OEM_4,
modifiers:{capsLockKey:1}, chars:"\u00B0"}, modifiers:{capsLockKey:1}, chars:"\u00B0"},
"\u00B0", "Minus", KeyboardEvent.DOM_VK_CLOSE_PAREN, "\u00B0", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD); "\u00B0", "Minus", KeyboardEvent.DOM_VK_CLOSE_PAREN, "\u00B0", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
@ -4220,10 +4223,10 @@ function* runKeyEventTests()
"=", "Equal", KeyboardEvent.DOM_VK_EQUALS, "=", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD); "=", "Equal", KeyboardEvent.DOM_VK_EQUALS, "=", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
//yield testKey({layout:KEYBOARD_LAYOUT_FRENCH, keyCode:WIN_VK_OEM_6, //yield testKey({layout:KEYBOARD_LAYOUT_FRENCH, keyCode:WIN_VK_OEM_6,
// modifiers:{capsLockKey:1}, chars:""}, // 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, //yield testKey({layout:KEYBOARD_LAYOUT_FRENCH, keyCode:WIN_VK_OEM_6,
// modifiers:{capsLockKey:1, shiftKey:1}, chars:""}, // 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, yield testKey({layout:KEYBOARD_LAYOUT_FRENCH, keyCode:WIN_VK_OEM_1,
modifiers:{capsLockKey:1}, chars:"\u00A3"}, modifiers:{capsLockKey:1}, chars:"\u00A3"},
"\u00A3", "BracketRight", KeyboardEvent.DOM_VK_DOLLAR, "\u00A3", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD); "\u00A3", "BracketRight", KeyboardEvent.DOM_VK_DOLLAR, "\u00A3", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
@ -4493,56 +4496,56 @@ function* runKeyEventTests()
yield testKey({layout:KEYBOARD_LAYOUT_SPANISH, keyCode:WIN_VK_OEM_7, yield testKey({layout:KEYBOARD_LAYOUT_SPANISH, keyCode:WIN_VK_OEM_7,
modifiers:{}, chars:""}, 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, yield testKey({layout:KEYBOARD_LAYOUT_SPANISH, keyCode:WIN_VK_OEM_7,
modifiers:{}, chars:"\u00B4\u00B4"}, 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, yield testKey({layout:KEYBOARD_LAYOUT_SPANISH, keyCode:WIN_VK_OEM_7,
modifiers:{}, chars:""}, 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, yield testKey({layout:KEYBOARD_LAYOUT_SPANISH, keyCode:WIN_VK_A,
modifiers:{}, chars:"\u00E1"}, modifiers:{}, chars:"\u00E1"},
["\u00E1", "\u00E1", "a"], "KeyA", KeyboardEvent.DOM_VK_A, "\u00E1", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD); ["\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, yield testKey({layout:KEYBOARD_LAYOUT_SPANISH, keyCode:WIN_VK_OEM_7,
modifiers:{}, chars:""}, 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, yield testKey({layout:KEYBOARD_LAYOUT_SPANISH, keyCode:WIN_VK_A,
modifiers:{shiftKey:1}, chars:"\u00C1"}, modifiers:{shiftKey:1}, chars:"\u00C1"},
["\u00C1", "\u00C1", "A"], "KeyA", KeyboardEvent.DOM_VK_A, "\u00C1", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD); ["\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, yield testKey({layout:KEYBOARD_LAYOUT_SPANISH, keyCode:WIN_VK_OEM_7,
modifiers:{}, chars:""}, 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, yield testKey({layout:KEYBOARD_LAYOUT_SPANISH, keyCode:WIN_VK_Q,
modifiers:{}, chars:"\u00B4q"}, modifiers:{}, chars:"\u00B4q"},
["\u00B4q", "\u00B4", "q", "q"], "KeyQ", KeyboardEvent.DOM_VK_Q, "\u00B4q", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD); ["\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, yield testKey({layout:KEYBOARD_LAYOUT_SPANISH, keyCode:WIN_VK_OEM_7,
modifiers:{shiftKey:1}, chars:""}, 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, yield testKey({layout:KEYBOARD_LAYOUT_SPANISH, keyCode:WIN_VK_OEM_7,
modifiers:{shiftKey:1}, chars:"\u00A8\u00A8"}, 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, yield testKey({layout:KEYBOARD_LAYOUT_SPANISH, keyCode:WIN_VK_OEM_7,
modifiers:{shiftKey:1}, chars:""}, 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, yield testKey({layout:KEYBOARD_LAYOUT_SPANISH, keyCode:WIN_VK_A,
modifiers:{shiftKey:1}, chars:"\u00C4"}, modifiers:{shiftKey:1}, chars:"\u00C4"},
["\u00C4", "\u00C4", "A"], "KeyA", KeyboardEvent.DOM_VK_A, "\u00C4", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD); ["\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, yield testKey({layout:KEYBOARD_LAYOUT_SPANISH, keyCode:WIN_VK_OEM_7,
modifiers:{shiftKey:1}, chars:""}, 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, yield testKey({layout:KEYBOARD_LAYOUT_SPANISH, keyCode:WIN_VK_A,
modifiers:{}, chars:"\u00E4"}, modifiers:{}, chars:"\u00E4"},
["\u00E4", "\u00E4", "a"], "KeyA", KeyboardEvent.DOM_VK_A, "\u00E4", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD); ["\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, yield testKey({layout:KEYBOARD_LAYOUT_SPANISH, keyCode:WIN_VK_OEM_7,
modifiers:{shiftKey:1}, chars:""}, 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, yield testKey({layout:KEYBOARD_LAYOUT_SPANISH, keyCode:WIN_VK_Q,
modifiers:{shiftKey:1}, chars:"\u00A8Q"}, modifiers:{shiftKey:1}, chars:"\u00A8Q"},
["\u00A8Q", "\u00A8", "Q", "Q"], "KeyQ", KeyboardEvent.DOM_VK_Q, "\u00A8Q", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD); ["\u00A8Q", "\u00A8", "Q", "Q"], "KeyQ", KeyboardEvent.DOM_VK_Q, "\u00A8Q", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);

View File

@ -4721,7 +4721,75 @@ KeyboardLayout::ConvertNativeKeyCodeToDOMKeyCode(UINT aNativeKeyCode) const
uniChars = GetUniCharsAndModifiers(aNativeKeyCode, modKeyState); uniChars = GetUniCharsAndModifiers(aNativeKeyCode, modKeyState);
if (uniChars.Length() != 1 || if (uniChars.Length() != 1 ||
uniChars.CharAt(0) < ' ' || uniChars.CharAt(0) > 0x7F) { 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)); return WidgetUtils::ComputeKeyCodeFromChar(uniChars.CharAt(0));