Bug 757688 part.7 Make nsWindow for Windows possible to test dead keys r=jimm

This commit is contained in:
Masayuki Nakano 2012-06-15 18:52:51 +09:00
parent 7515c8fa8e
commit 00843733cd
5 changed files with 217 additions and 15 deletions

View File

@ -91,6 +91,7 @@ if (IS_MAC) {
"US":0x409,
"German":0x407,
"Greek":0x408,
"Spanish":0x40a,
"French":0x40c,
"Swedish":0x41d,
"Arabic":0x401,
@ -248,13 +249,18 @@ function runKeyEventTests()
var expectEventTypeList = [];
if (aShouldDelivedEvent & SHOULD_DELIVER_KEYDOWN)
expectEventTypeList.push("keydown");
if (aShouldDelivedEvent & SHOULD_DELIVER_KEYPRESS)
if (aShouldDelivedEvent & SHOULD_DELIVER_KEYPRESS) {
expectEventTypeList.push("keypress");
for (var i = 1; i < aExpectGeckoChar.length; i++) {
expectEventTypeList.push("keypress");
}
}
if (aShouldDelivedEvent & SHOULD_DELIVER_KEYUP)
expectEventTypeList.push("keyup");
is(eventList.length, expectEventTypeList.length, name + ", wrong number of key events");
var longerLength = Math.max(eventList.length, expectEventTypeList.length);
var keypressCount = 0;
for (var i = 0; i < longerLength; i++) {
var firedEventType = i < eventList.length ? eventList[i].type : "";
var expectEventType = i < expectEventTypeList.length ? expectEventTypeList[i] : "";
@ -271,7 +277,7 @@ function runKeyEventTests()
is(e.shiftKey, aEvent.shift || aEvent.shiftRight || 0, name + ", Shift mismatch");
if (aExpectGeckoChar.length > 0 && e.type == "keypress") {
is(e.charCode, aExpectGeckoChar.charCodeAt(0), name + ", charcode");
is(e.charCode, aExpectGeckoChar.charCodeAt(keypressCount++), name + ", charcode");
if (aExpectedGeckoKeyCode >= 0) {
if (aExpectGeckoChar) {
is(e.keyCode, 0, name + ", wrong keycode");
@ -1761,9 +1767,9 @@ function runKeyEventTests()
testKey({layout:"French", keyCode:187, shift:1, chars:"+"},
nsIDOMKeyEvent.DOM_VK_EQUALS, "+", SHOULD_DELIVER_ALL);
//testKey({layout:"French", keyCode:221, chars:""},
// 0, "", SHOULD_DELIVER_KEYDOWN_KEYUP); // Dead-key
// nsIDOMKeyEvent.DOM_VK_CIRCUMFLEX, "", SHOULD_DELIVER_KEYDOWN_KEYUP); // Dead-key
//testKey({layout:"French", keyCode:221, shift:1, chars:""},
// 0, "", SHOULD_DELIVER_KEYDOWN_KEYUP); // Dead-key
// nsIDOMKeyEvent.DOM_VK_CIRCUMFLEX, "", SHOULD_DELIVER_ALL); // Dead-key
testKey({layout:"French", keyCode:186, chars:"$"},
nsIDOMKeyEvent.DOM_VK_DOLLAR, "$", SHOULD_DELIVER_ALL);
testKey({layout:"French", keyCode:186, shift:1, chars:"\u00A3"},
@ -1884,6 +1890,127 @@ function runKeyEventTests()
nsIDOMKeyEvent.DOM_VK_PIPE, "|", SHOULD_DELIVER_ALL);
testKey({layout:"Norwegian", keyCode:220, shift:1, chars:"\u00A7"},
nsIDOMKeyEvent.DOM_VK_PIPE, "\u00A7", SHOULD_DELIVER_ALL);
// Dead keys on any layouts
testKey({layout:"French", keyCode:221, chars:""},
nsIDOMKeyEvent.DOM_VK_CIRCUMFLEX, "", SHOULD_DELIVER_KEYDOWN_KEYUP);
testKey({layout:"French", keyCode:221, chars:"^^"},
nsIDOMKeyEvent.DOM_VK_CIRCUMFLEX, "^^", SHOULD_DELIVER_ALL);
testKey({layout:"French", keyCode:221, chars:""},
nsIDOMKeyEvent.DOM_VK_CIRCUMFLEX, "", SHOULD_DELIVER_KEYDOWN_KEYUP);
testKey({layout:"French", keyCode:65, chars:"\u00E2"},
nsIDOMKeyEvent.DOM_VK_A, "\u00E2", SHOULD_DELIVER_ALL);
testKey({layout:"French", keyCode:221, chars:""},
nsIDOMKeyEvent.DOM_VK_CIRCUMFLEX, "", SHOULD_DELIVER_KEYDOWN_KEYUP);
testKey({layout:"French", keyCode:65, shift:1, chars:"\u00C2"},
nsIDOMKeyEvent.DOM_VK_A, "\u00C2", SHOULD_DELIVER_ALL);
testKey({layout:"French", keyCode:221, chars:""},
nsIDOMKeyEvent.DOM_VK_CIRCUMFLEX, "", SHOULD_DELIVER_KEYDOWN_KEYUP);
testKey({layout:"French", keyCode:81, chars:"^q"},
nsIDOMKeyEvent.DOM_VK_Q, "^q", SHOULD_DELIVER_ALL);
testKey({layout:"French", keyCode:221, shift:1, chars:""},
nsIDOMKeyEvent.DOM_VK_CIRCUMFLEX, "", SHOULD_DELIVER_KEYDOWN_KEYUP);
testKey({layout:"French", keyCode:221, shift:1, chars:"\u00A8\u00A8"},
nsIDOMKeyEvent.DOM_VK_CIRCUMFLEX, "\u00A8\u00A8", SHOULD_DELIVER_ALL);
testKey({layout:"French", keyCode:221, shift:1, chars:""},
nsIDOMKeyEvent.DOM_VK_CIRCUMFLEX, "", SHOULD_DELIVER_KEYDOWN_KEYUP);
testKey({layout:"French", keyCode:65, shift:1, chars:"\u00C4"},
nsIDOMKeyEvent.DOM_VK_A, "\u00C4", SHOULD_DELIVER_ALL);
testKey({layout:"French", keyCode:221, shift:1, chars:""},
nsIDOMKeyEvent.DOM_VK_CIRCUMFLEX, "", SHOULD_DELIVER_KEYDOWN_KEYUP);
testKey({layout:"French", keyCode:65, chars:"\u00E4"},
nsIDOMKeyEvent.DOM_VK_A, "\u00E4", SHOULD_DELIVER_ALL);
testKey({layout:"French", keyCode:221, shift:1, chars:""},
nsIDOMKeyEvent.DOM_VK_CIRCUMFLEX, "", SHOULD_DELIVER_KEYDOWN_KEYUP);
testKey({layout:"French", keyCode:81, shift:1, chars:"\u00A8Q"},
nsIDOMKeyEvent.DOM_VK_Q, "\u00A8Q", SHOULD_DELIVER_ALL);
testKey({layout:"Spanish", keyCode:186, chars:""},
nsIDOMKeyEvent.DOM_VK_BACK_QUOTE, "", SHOULD_DELIVER_KEYDOWN_KEYUP);
testKey({layout:"Spanish", keyCode:186, chars:"``"},
nsIDOMKeyEvent.DOM_VK_BACK_QUOTE, "``", SHOULD_DELIVER_ALL);
testKey({layout:"Spanish", keyCode:186, chars:""},
nsIDOMKeyEvent.DOM_VK_BACK_QUOTE, "", SHOULD_DELIVER_KEYDOWN_KEYUP);
testKey({layout:"Spanish", keyCode:65, chars:"\u00E0"},
nsIDOMKeyEvent.DOM_VK_A, "\u00E0", SHOULD_DELIVER_ALL);
testKey({layout:"Spanish", keyCode:186, chars:""},
nsIDOMKeyEvent.DOM_VK_BACK_QUOTE, "", SHOULD_DELIVER_KEYDOWN_KEYUP);
testKey({layout:"Spanish", keyCode:65, shift:1, chars:"\u00C0"},
nsIDOMKeyEvent.DOM_VK_A, "\u00C0", SHOULD_DELIVER_ALL);
testKey({layout:"Spanish", keyCode:186, chars:""},
nsIDOMKeyEvent.DOM_VK_BACK_QUOTE, "", SHOULD_DELIVER_KEYDOWN_KEYUP);
testKey({layout:"Spanish", keyCode:81, chars:"`q"},
nsIDOMKeyEvent.DOM_VK_Q, "`q", SHOULD_DELIVER_ALL);
testKey({layout:"Spanish", keyCode:186, shift:1, chars:""},
nsIDOMKeyEvent.DOM_VK_BACK_QUOTE, "", SHOULD_DELIVER_KEYDOWN_KEYUP);
testKey({layout:"Spanish", keyCode:186, shift:1, chars:"^^"},
nsIDOMKeyEvent.DOM_VK_BACK_QUOTE, "^^", SHOULD_DELIVER_ALL);
testKey({layout:"Spanish", keyCode:186, shift:1, chars:""},
nsIDOMKeyEvent.DOM_VK_BACK_QUOTE, "", SHOULD_DELIVER_KEYDOWN_KEYUP);
testKey({layout:"Spanish", keyCode:65, shift:1, chars:"\u00C2"},
nsIDOMKeyEvent.DOM_VK_A, "\u00C2", SHOULD_DELIVER_ALL);
testKey({layout:"Spanish", keyCode:186, shift:1, chars:""},
nsIDOMKeyEvent.DOM_VK_BACK_QUOTE, "", SHOULD_DELIVER_KEYDOWN_KEYUP);
testKey({layout:"Spanish", keyCode:65, chars:"\u00E2"},
nsIDOMKeyEvent.DOM_VK_A, "\u00E2", SHOULD_DELIVER_ALL);
testKey({layout:"Spanish", keyCode:186, shift:1, chars:""},
nsIDOMKeyEvent.DOM_VK_BACK_QUOTE, "", SHOULD_DELIVER_KEYDOWN_KEYUP);
testKey({layout:"Spanish", keyCode:81, shift:1, chars:"^Q"},
nsIDOMKeyEvent.DOM_VK_Q, "^Q", SHOULD_DELIVER_ALL);
testKey({layout:"Spanish", keyCode:222, chars:""},
0, "", SHOULD_DELIVER_KEYDOWN_KEYUP);
testKey({layout:"Spanish", keyCode:222, chars:"\u00B4\u00B4"},
0, "\u00B4\u00B4", SHOULD_DELIVER_ALL);
testKey({layout:"Spanish", keyCode:222, chars:""},
0, "", SHOULD_DELIVER_KEYDOWN_KEYUP);
testKey({layout:"Spanish", keyCode:65, chars:"\u00E1"},
nsIDOMKeyEvent.DOM_VK_A, "\u00E1", SHOULD_DELIVER_ALL);
testKey({layout:"Spanish", keyCode:222, chars:""},
0, "", SHOULD_DELIVER_KEYDOWN_KEYUP);
testKey({layout:"Spanish", keyCode:65, shift:1, chars:"\u00C1"},
nsIDOMKeyEvent.DOM_VK_A, "\u00C1", SHOULD_DELIVER_ALL);
testKey({layout:"Spanish", keyCode:222, chars:""},
0, "", SHOULD_DELIVER_KEYDOWN_KEYUP);
testKey({layout:"Spanish", keyCode:81, chars:"\u00B4q"},
nsIDOMKeyEvent.DOM_VK_Q, "\u00B4q", SHOULD_DELIVER_ALL);
testKey({layout:"Spanish", keyCode:222, shift:1, chars:""},
0, "", SHOULD_DELIVER_KEYDOWN_KEYUP);
testKey({layout:"Spanish", keyCode:222, shift:1, chars:"\u00A8\u00A8"},
0, "\u00A8\u00A8", SHOULD_DELIVER_ALL);
testKey({layout:"Spanish", keyCode:222, shift:1, chars:""},
0, "", SHOULD_DELIVER_KEYDOWN_KEYUP);
testKey({layout:"Spanish", keyCode:65, shift:1, chars:"\u00C4"},
nsIDOMKeyEvent.DOM_VK_A, "\u00C4", SHOULD_DELIVER_ALL);
testKey({layout:"Spanish", keyCode:222, shift:1, chars:""},
0, "", SHOULD_DELIVER_KEYDOWN_KEYUP);
testKey({layout:"Spanish", keyCode:65, chars:"\u00E4"},
nsIDOMKeyEvent.DOM_VK_A, "\u00E4", SHOULD_DELIVER_ALL);
testKey({layout:"Spanish", keyCode:222, shift:1, chars:""},
0, "", SHOULD_DELIVER_KEYDOWN_KEYUP);
testKey({layout:"Spanish", keyCode:81, shift:1, chars:"\u00A8Q"},
nsIDOMKeyEvent.DOM_VK_Q, "\u00A8Q", SHOULD_DELIVER_ALL);
}
document.removeEventListener("keydown", onKeyEvent, false);

View File

@ -513,7 +513,7 @@ NativeKey::GetKeyLocation() const
*****************************************************************************/
KeyboardLayout::KeyboardLayout() :
mKeyboardLayout(0)
mKeyboardLayout(0), mPendingKeyboardLayout(0)
{
mDeadKeyTableListHead = nsnull;
@ -550,6 +550,10 @@ UniCharsAndModifiers
KeyboardLayout::OnKeyDown(PRUint8 aVirtualKey,
const ModifierKeyState& aModKeyState)
{
if (mPendingKeyboardLayout) {
LoadLayout(mPendingKeyboardLayout);
}
PRInt32 virtualKeyIndex = GetKeyIndex(aVirtualKey);
if (virtualKeyIndex < 0) {
@ -626,8 +630,15 @@ KeyboardLayout::GetUniCharsAndModifiers(
}
void
KeyboardLayout::LoadLayout(HKL aLayout)
KeyboardLayout::LoadLayout(HKL aLayout, bool aLoadLater)
{
if (aLoadLater) {
mPendingKeyboardLayout = aLayout;
return;
}
mPendingKeyboardLayout = 0;
if (mKeyboardLayout == aLayout) {
return;
}

View File

@ -8,6 +8,7 @@
#include "nscore.h"
#include "nsEvent.h"
#include "nsString.h"
#include <windows.h>
#define NS_NUM_OF_KEYS 68
@ -135,6 +136,8 @@ struct UniCharsAndModifiers
bool UniCharsEqual(const UniCharsAndModifiers& aOther) const;
bool UniCharsCaseInsensitiveEqual(const UniCharsAndModifiers& aOther) const;
nsString ToString() const { return nsString(mChars, mLength); }
};
struct DeadKeyEntry;
@ -305,6 +308,7 @@ class KeyboardLayout
};
HKL mKeyboardLayout;
HKL mPendingKeyboardLayout;
VirtualKey mVirtualKeys[NS_NUM_OF_KEYS];
DeadKeyTableListEntry* mDeadKeyTableListHead;
@ -357,11 +361,18 @@ public:
UniCharsAndModifiers OnKeyDown(PRUint8 aVirtualKey,
const ModifierKeyState& aModKeyState);
void LoadLayout(HKL aLayout);
/**
* LoadLayout() loads the keyboard layout. If aLoadLater is true,
* it will be done when OnKeyDown() is called.
*/
void LoadLayout(HKL aLayout, bool aLoadLater = false);
PRUint32 ConvertNativeKeyCodeToDOMKeyCode(UINT aNativeKeyCode) const;
HKL GetLayout() const { return mKeyboardLayout; }
HKL GetLayout() const
{
return mPendingKeyboardLayout ? mPendingKeyboardLayout : mKeyboardLayout;
}
};
} // namespace widget

View File

@ -5653,10 +5653,26 @@ nsWindow::SynthesizeNativeKeyEvent(PRInt32 aNativeKeyboardLayout,
const nsAString& aCharacters,
const nsAString& aUnmodifiedCharacters)
{
UINT keyboardLayoutListCount = ::GetKeyboardLayoutList(0, NULL);
NS_ASSERTION(keyboardLayoutListCount > 0,
"One keyboard layout must be installed at least");
HKL keyboardLayoutListBuff[50];
HKL* keyboardLayoutList =
keyboardLayoutListCount < 50 ? keyboardLayoutListBuff :
new HKL[keyboardLayoutListCount];
keyboardLayoutListCount =
::GetKeyboardLayoutList(keyboardLayoutListCount, keyboardLayoutList);
NS_ASSERTION(keyboardLayoutListCount > 0,
"Failed to get all keyboard layouts installed on the system");
nsPrintfCString layoutName("%08x", aNativeKeyboardLayout);
HKL loadedLayout = LoadKeyboardLayoutA(layoutName.get(), KLF_NOTELLSHELL);
if (loadedLayout == NULL)
if (loadedLayout == NULL) {
if (keyboardLayoutListBuff != keyboardLayoutList) {
delete [] keyboardLayoutList;
}
return NS_ERROR_NOT_AVAILABLE;
}
// Setup clean key state and load desired layout
BYTE originalKbdState[256];
@ -5694,9 +5710,30 @@ nsWindow::SynthesizeNativeKeyEvent(PRInt32 aNativeKeyboardLayout,
lParam |= 0x1000000;
}
MSG msg = WinUtils::InitMSG(WM_KEYDOWN, key, lParam);
if (i == keySequence.Length() - 1 && aCharacters.Length() > 0) {
nsFakeCharMessage fakeMsg = { aCharacters.CharAt(0), scanCode };
OnKeyDown(msg, modKeyState, nsnull, &fakeMsg);
if (i == keySequence.Length() - 1) {
bool makeDeadCharMessage =
gKbdLayout.IsDeadKey(key, modKeyState) && aCharacters.IsEmpty();
nsAutoString chars(aCharacters);
if (makeDeadCharMessage) {
UniCharsAndModifiers deadChars =
gKbdLayout.GetUniCharsAndModifiers(key, modKeyState);
chars = deadChars.ToString();
NS_ASSERTION(chars.Length() == 1,
"Dead char must be only one character");
}
if (chars.IsEmpty()) {
OnKeyDown(msg, modKeyState, nsnull, nsnull);
} else {
nsFakeCharMessage fakeMsg = { chars.CharAt(0), scanCode,
makeDeadCharMessage };
OnKeyDown(msg, modKeyState, nsnull, &fakeMsg);
for (PRUint32 j = 1; j < chars.Length(); j++) {
nsFakeCharMessage fakeMsg = { chars.CharAt(j), scanCode, false };
MSG msg = fakeMsg.GetCharMessage(mWnd);
NativeKey nativeKey(gKbdLayout, this, msg);
OnChar(msg, nativeKey, modKeyState, nsnull);
}
}
} else {
OnKeyDown(msg, modKeyState, nsnull, nsnull);
}
@ -5724,9 +5761,21 @@ nsWindow::SynthesizeNativeKeyEvent(PRInt32 aNativeKeyboardLayout,
// Restore old key state and layout
::SetKeyboardState(originalKbdState);
gKbdLayout.LoadLayout(oldLayout);
gKbdLayout.LoadLayout(oldLayout, true);
UnloadKeyboardLayout(loadedLayout);
// Don't unload the layout if it's installed actually.
for (PRUint32 i = 0; i < keyboardLayoutListCount; i++) {
if (keyboardLayoutList[i] == loadedLayout) {
loadedLayout = 0;
break;
}
}
if (keyboardLayoutListBuff != keyboardLayoutList) {
delete [] keyboardLayoutList;
}
if (loadedLayout) {
::UnloadKeyboardLayout(loadedLayout);
}
return NS_OK;
}
@ -6358,6 +6407,9 @@ LRESULT nsWindow::OnKeyDown(const MSG &aMsg,
msg.message == WM_CHAR || msg.message == WM_SYSCHAR || msg.message == WM_DEADCHAR)) {
if (aFakeCharMessage) {
MSG msg = aFakeCharMessage->GetCharMessage(mWnd);
if (msg.message == WM_DEADCHAR) {
return false;
}
return OnChar(msg, nativeKey, aModKeyState, nsnull, extraFlags);
}

View File

@ -211,12 +211,13 @@ struct nsAlternativeCharCode; // defined in nsGUIEvent.h
struct nsFakeCharMessage {
UINT mCharCode;
UINT mScanCode;
bool mIsDeadKey;
MSG GetCharMessage(HWND aWnd)
{
MSG msg;
msg.hwnd = aWnd;
msg.message = WM_CHAR;
msg.message = mIsDeadKey ? WM_DEADCHAR : WM_CHAR;
msg.wParam = static_cast<WPARAM>(mCharCode);
msg.lParam = static_cast<LPARAM>(mScanCode);
msg.time = 0;