Relanding fix for bug 287179 unmodified charCode is generated for keypress event when both ctrl and shift are held down, patch by Dainis Jonitis r=emaijala sr=me for changes since previous attempts (see previous checkins for superreviewers)

This commit is contained in:
neil%parkwaycc.co.uk 2006-03-16 21:02:22 +00:00
Родитель 2c19163739
Коммит 84dd62f553
4 изменённых файлов: 148 добавлений и 94 удалений

Просмотреть файл

@ -67,9 +67,9 @@ REQUIRES = xpcom \
xuldoc \
view \
imglib2 \
uriloader \
webbrowserpersist \
unicharutil \
uriloader \
webbrowserpersist \
unicharutil \
$(NULL)
ifdef MOZ_ENABLE_CAIRO_GFX
@ -82,6 +82,7 @@ CPPSRCS = \
nsAppShell.cpp \
nsLookAndFeel.cpp \
nsToolkit.cpp \
nsKeyboardLayout.cpp \
nsDataObj.cpp \
nsDataObjCollection.cpp \
nsClipboard.cpp \

Просмотреть файл

@ -225,6 +225,22 @@ PRUint32 VirtualKey::GetNativeUniChars (PRUint8 aShiftState, PRUint16* aUniChars
KeyboardLayout::KeyboardLayout ()
{
#ifndef WINCE
mDeadKeyTableListHead = nsnull;
#endif
LoadLayout ();
}
KeyboardLayout::~KeyboardLayout ()
{
#ifndef WINCE
ReleaseDeadKeyTables ();
#endif
}
PRBool KeyboardLayout::IsPrintableCharKey (PRUint8 aVirtualKey)
{
#ifndef WINCE
@ -361,37 +377,39 @@ void KeyboardLayout::LoadLayout ()
NS_ASSERTION (vki < NS_ARRAY_LENGTH (mVirtualKeys), "invalid index");
PRUint16 uniChars [5];
WORD ascii;
WORD ascii [2]; // On Win9x ToAsciiEx returns WORD per character, on Win2k BYTE per character.
PRInt32 rv;
if (nsToolkit::mIsNT)
rv = ::ToUnicode (virtualKey, 0, kbdState, (LPWSTR)uniChars, NS_ARRAY_LENGTH (uniChars), 0);
else
rv = ::ToAsciiEx (virtualKey, 0, kbdState, &ascii, 0, mKeyboardLayout);
rv = ::ToAsciiEx (virtualKey, 0, kbdState, ascii, 0, mKeyboardLayout);
if (rv == -1) // dead-key
if (rv < 0) // dead-key
{
shiftStatesWithDeadKeys |= 1 << shiftState;
// Repeat dead-key to deactivate it and get its character representation.
PRUint16 deadChar;
PRUint16 deadChar [2];
if (nsToolkit::mIsNT)
::ToUnicode (virtualKey, 0, kbdState, (LPWSTR)&deadChar, 1, 0);
rv = ::ToUnicode (virtualKey, 0, kbdState, (LPWSTR)deadChar, NS_ARRAY_LENGTH (deadChar), 0);
else
{
rv = ::ToAsciiEx (virtualKey, 0, kbdState, &ascii, 0, mKeyboardLayout);
::MultiByteToWideChar (mCodePage, 0, (LPCSTR)&ascii, rv, (WCHAR*)&deadChar, 1);
rv = ::ToAsciiEx (virtualKey, 0, kbdState, ascii, 0, mKeyboardLayout);
::MultiByteToWideChar (mCodePage, 0, (LPCSTR)ascii, 1, (WCHAR*)deadChar, 1);
}
mVirtualKeys [vki].SetDeadChar (shiftState, deadChar);
NS_ASSERTION (rv == 2, "Expecting twice repeated dead-key character");
mVirtualKeys [vki].SetDeadChar (shiftState, deadChar [0]);
} else
{
if (rv == 1) // dead-key can pair only with exactly one base character.
shiftStatesWithBaseChars |= 1 << shiftState;
if (!nsToolkit::mIsNT)
rv = ::MultiByteToWideChar (mCodePage, 0, (LPCSTR)&ascii, rv, (WCHAR*)uniChars, NS_ARRAY_LENGTH (uniChars));
rv = ::MultiByteToWideChar (mCodePage, 0, (LPCSTR)ascii, rv, (WCHAR*)uniChars, NS_ARRAY_LENGTH (uniChars));
mVirtualKeys [vki].SetNormalChars (shiftState, uniChars, rv);
}
@ -485,11 +503,12 @@ void KeyboardLayout::SetShiftState (PBYTE aKbdState, PRUint8 aShiftState)
inline PRInt32 KeyboardLayout::GetKeyIndex (PRUint8 aVirtualKey)
{
// Currently these 49 (NUM_OF_KEYS) virtual keys are assumed
// Currently these 50 (NUM_OF_KEYS) virtual keys are assumed
// to produce visible representation:
// 0x20 - VK_SPACE ' '
// 0x30..0x39 '0'..'9'
// 0x41..0x5A 'A'..'Z'
// 0x6E - VK_DECIMAL '.'
// 0xBA - VK_OEM_1 ';:' for US
// 0xBB - VK_OEM_PLUS '+' any country
// 0xBC - VK_OEM_COMMA ',' any country
@ -513,14 +532,14 @@ inline PRInt32 KeyboardLayout::GetKeyIndex (PRUint8 aVirtualKey)
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, -1, -1, -1, -1, -1, -1, // 30
-1, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, // 40
26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, -1, -1, -1, -1, -1, // 50
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 60
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 37, -1, // 60
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 70
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 80
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 90
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // A0
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 37, 38, 39, 40, 41, 42, // B0
43, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // C0
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 44, 45, 46, 47, 48, // D0
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 38, 39, 40, 41, 42, 43, // B0
44, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // C0
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 45, 46, 47, 48, 49, // D0
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // E0
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 // F0
};
@ -577,13 +596,13 @@ PRBool KeyboardLayout::EnsureDeadKeyActive (PRBool aIsActive, PRUint8 aDeadKey,
else
rv = ::ToAsciiEx (aDeadKey, 0, (PBYTE)aDeadKeyKbdState, dummyChars, 0, mKeyboardLayout);
// returned values:
// -1 - Dead key state is active. The keyboard driver will wait for next character.
// <0 - Dead key state is active. The keyboard driver will wait for next character.
// 1 - Previous pressed key was a valid base character that produced exactly one composite character.
// >1 - Previous pressed key does not produce any composite characters. Return dead-key character
// followed by base character(s).
} while ((rv == -1) != aIsActive);
} while ((rv < 0) != aIsActive);
return (rv == -1);
return (rv < 0);
}
void KeyboardLayout::DeactivateDeadKeyState ()
@ -644,26 +663,16 @@ PRUint32 KeyboardLayout::GetDeadKeyCombinations (PRUint8 aDeadKey, const PBYTE a
// Depending on the character the followed the dead-key, the keyboard driver can produce
// one composite character, or a dead-key character followed by a second character.
PRUint16 compositeChars [5];
WORD ascii [2]; // On Win9x ToAsciiEx returns WORD per character, on Win2k BYTE per character.
PRInt32 rv;
if (nsToolkit::mIsNT)
rv = ::ToUnicode (virtualKey, 0, kbdState, (LPWSTR)compositeChars, NS_ARRAY_LENGTH (compositeChars), 0);
else
{
WORD ascii;
rv = ::ToAsciiEx (virtualKey, 0, kbdState, &ascii, 0, mKeyboardLayout);
if (rv == 1)
::MultiByteToWideChar (mCodePage, 0, (LPCSTR)&ascii, 1, (WCHAR*)compositeChars, NS_ARRAY_LENGTH (compositeChars));
}
rv = ::ToAsciiEx (virtualKey, 0, kbdState, ascii, 0, mKeyboardLayout);
switch (rv)
{
case -1:
// Unexpected dead-key
deadKeyActive = PR_FALSE;
break;
case 0:
// This key combination does not produce any characters. The dead-key is still in active state.
break;
@ -678,14 +687,15 @@ PRUint32 KeyboardLayout::GetDeadKeyCombinations (PRUint8 aDeadKey, const PBYTE a
rv = ::ToUnicode (virtualKey, 0, kbdState, (LPWSTR)baseChars, NS_ARRAY_LENGTH (baseChars), 0);
else
{
WORD ascii;
rv = ::ToAsciiEx (virtualKey, 0, kbdState, &ascii, 0, mKeyboardLayout);
::MultiByteToWideChar (mCodePage, 0, (LPCSTR)ascii, 1, (WCHAR*)compositeChars, NS_ARRAY_LENGTH (compositeChars));
if (rv == 1)
::MultiByteToWideChar (mCodePage, 0, (LPCSTR)&ascii, 1, (WCHAR*)baseChars, NS_ARRAY_LENGTH (baseChars));
rv = ::ToAsciiEx (virtualKey, 0, kbdState, ascii, 0, mKeyboardLayout);
rv = ::MultiByteToWideChar (mCodePage, 0, (LPCSTR)ascii, rv, (WCHAR*)baseChars, NS_ARRAY_LENGTH (baseChars));
}
if (entries < aMaxEntries)
NS_ASSERTION (rv == 1, "One base character expected");
if (rv == 1 && entries < aMaxEntries)
if (AddDeadKeyEntry (baseChars [0], compositeChars [0], aDeadKeyArray, entries))
entries++;
@ -694,7 +704,8 @@ PRUint32 KeyboardLayout::GetDeadKeyCombinations (PRUint8 aDeadKey, const PBYTE a
}
default:
// More than one character generated. This is not a valid dead-key and base character combination.
// 1. Unexpected dead-key. Dead-key chaining is not supported.
// 2. More than one character generated. This is not a valid dead-key and base character combination.
deadKeyActive = PR_FALSE;
break;
}

Просмотреть файл

@ -49,10 +49,10 @@
#define VK_OEM_PERIOD 0xBE // '.' any country
#define VK_OEM_2 0xBF // '/?' for US
#define VK_OEM_3 0xC0 // '`~' for US
#define VK_OEM_4 0xDB // '[{' for US
#define VK_OEM_5 0xDC // '\|' for US
#define VK_OEM_6 0xDD // ']}' for US
#define VK_OEM_7 0xDE // ''"' for US
#define VK_OEM_4 0xDB // '[{' for US
#define VK_OEM_5 0xDC // '\|' for US
#define VK_OEM_6 0xDD // ']}' for US
#define VK_OEM_7 0xDE // ''"' for US
#define VK_OEM_8 0xDF
@ -143,7 +143,7 @@ class KeyboardLayout
PRUint8 data [1];
};
#define NUM_OF_KEYS 49
#define NUM_OF_KEYS 50
UINT mCodePage; // Used for Win9x only
HKL mKeyboardLayout;
@ -172,17 +172,8 @@ class KeyboardLayout
#endif
public:
KeyboardLayout ()
{
LoadLayout ();
}
~KeyboardLayout ()
{
#ifndef WINCE
ReleaseDeadKeyTables ();
#endif
}
KeyboardLayout ();
~KeyboardLayout ();
static PRBool IsPrintableCharKey (PRUint8 aVirtualKey);

Просмотреть файл

@ -75,6 +75,7 @@
#include "imgIContainer.h"
#include "gfxIImageFrame.h"
#include "nsNativeCharsetUtils.h"
#include "nsKeyboardLayout.h"
#include <windows.h>
#include <process.h>
@ -784,6 +785,7 @@ nsWindow::nsWindow() : nsBaseWidget()
HKL nsWindow::gKeyboardLayout = 0;
UINT nsWindow::gCurrentKeyboardCP = 0;
PRBool nsWindow::gSwitchKeyboardLayout = PR_FALSE;
static KeyboardLayout gKbdLayout;
//-------------------------------------------------------------------------
//
@ -3183,9 +3185,9 @@ NS_METHOD nsWindow::EnableDragDrop(PRBool aEnable)
UINT nsWindow::MapFromNativeToDOM(UINT aNativeKeyCode)
{
switch (aNativeKeyCode) {
case 0xBA: return NS_VK_SEMICOLON;
case 0xBB: return NS_VK_EQUALS;
case 0xBD: return NS_VK_SUBTRACT;
case VK_OEM_1: return NS_VK_SEMICOLON; // 0xBA, For the US standard keyboard, the ';:' key
case VK_OEM_PLUS: return NS_VK_EQUALS; // 0xBB, For any country/region, the '+' key
case VK_OEM_MINUS: return NS_VK_SUBTRACT; // 0xBD, For any country/region, the '-' key
}
return aNativeKeyCode;
@ -3265,6 +3267,8 @@ PRBool nsWindow::DispatchKeyEvent(PRUint32 aEventType, WORD aCharCode, UINT aVir
//-------------------------------------------------------------------------
BOOL nsWindow::OnKeyDown(UINT aVirtualKeyCode, UINT aScanCode, LPARAM aKeyData)
{
gKbdLayout.OnKeyDown (aVirtualKeyCode);
UINT virtualKeyCode = sIMEIsComposing ? aVirtualKeyCode : MapFromNativeToDOM(aVirtualKeyCode);
#ifdef DEBUG
@ -3296,12 +3300,25 @@ BOOL nsWindow::OnKeyDown(UINT aVirtualKeyCode, UINT aScanCode, LPARAM aKeyData)
if (virtualKeyCode == NS_VK_RETURN || virtualKeyCode == NS_VK_BACK ||
(mIsControlDown && !mIsAltDown && !mIsShiftDown &&
(virtualKeyCode == NS_VK_ADD || virtualKeyCode == NS_VK_SUBTRACT ||
virtualKeyCode == NS_VK_EQUALS)))
virtualKeyCode == NS_VK_EQUALS)) ||
((mIsControlDown || mIsAltDown) && KeyboardLayout::IsPrintableCharKey (aVirtualKeyCode)))
{
// Remove a possible WM_CHAR or WM_SYSCHAR from the message queue
if (gotMsg && (msg.message == WM_CHAR || msg.message == WM_SYSCHAR)) {
// Remove a possible WM_CHAR or WM_SYSCHAR messages from the message queue.
// They can be more than one because of:
// * Dead-keys not pairing with base character
// * Some keyboard layouts may map up to 4 characters to the single key
PRBool anyCharMessagesRemoved = PR_FALSE;
while (gotMsg && (msg.message == WM_CHAR || msg.message == WM_SYSCHAR))
{
nsToolkit::mGetMessage(&msg, mWnd, WM_KEYFIRST, WM_KEYLAST);
} else if (virtualKeyCode == NS_VK_BACK) {
anyCharMessagesRemoved = PR_TRUE;
gotMsg = nsToolkit::mPeekMessage (&msg, mWnd, WM_KEYFIRST, WM_KEYLAST, PM_NOREMOVE | PM_NOYIELD);
}
if (!anyCharMessagesRemoved && virtualKeyCode == NS_VK_BACK) {
MSG imeStartCompositionMsg, imeCompositionMsg;
if (nsToolkit::mPeekMessage(&imeStartCompositionMsg, mWnd, WM_IME_STARTCOMPOSITION, WM_IME_STARTCOMPOSITION, PM_NOREMOVE | PM_NOYIELD)
&& nsToolkit::mPeekMessage(&imeCompositionMsg, mWnd, WM_IME_COMPOSITION, WM_IME_COMPOSITION, PM_NOREMOVE | PM_NOYIELD)
@ -3336,8 +3353,10 @@ BOOL nsWindow::OnKeyDown(UINT aVirtualKeyCode, UINT aScanCode, LPARAM aKeyData)
(msg.message == WM_CHAR || msg.message == WM_SYSCHAR || msg.message == WM_DEADCHAR)) {
// If prevent default set for keydown, do same for keypress
nsToolkit::mGetMessage(&msg, mWnd, msg.message, msg.message);
if (msg.message == WM_DEADCHAR)
return PR_FALSE;
#ifdef KE_DEBUG
printf("%s\tchar=%c\twp=%4x\tlp=%8x\n",
(msg.message == WM_SYSCHAR) ? "WM_SYSCHAR" : "WM_CHAR",
@ -3346,47 +3365,77 @@ BOOL nsWindow::OnKeyDown(UINT aVirtualKeyCode, UINT aScanCode, LPARAM aKeyData)
return OnChar(msg.wParam, extraFlags);
}
WORD asciiKey = 0;
if (gKbdLayout.IsDeadKey ())
return PR_FALSE;
PRUint8 shiftStates [5];
PRUint16 uniChars [5];
PRUint32 numOfUniChars = 0;
PRUint32 numOfShiftStates = 0;
switch (virtualKeyCode) {
// keys to be sent as characters
case NS_VK_ADD : asciiKey = '+'; break;
case NS_VK_SUBTRACT : asciiKey = '-'; break;
case NS_VK_SEMICOLON : asciiKey = ';'; break;
case NS_VK_EQUALS : asciiKey = '='; break;
case NS_VK_COMMA : asciiKey = ','; break;
case NS_VK_PERIOD : asciiKey = '.'; break;
case NS_VK_QUOTE : asciiKey = '\''; break;
case NS_VK_BACK_QUOTE: asciiKey = '`'; break;
case NS_VK_DIVIDE :
case NS_VK_SLASH : asciiKey = '/'; break;
case NS_VK_MULTIPLY : asciiKey = '*'; break;
case NS_VK_NUMPAD0 : asciiKey = '0'; break;
case NS_VK_NUMPAD1 : asciiKey = '1'; break;
case NS_VK_NUMPAD2 : asciiKey = '2'; break;
case NS_VK_NUMPAD3 : asciiKey = '3'; break;
case NS_VK_NUMPAD4 : asciiKey = '4'; break;
case NS_VK_NUMPAD5 : asciiKey = '5'; break;
case NS_VK_NUMPAD6 : asciiKey = '6'; break;
case NS_VK_NUMPAD7 : asciiKey = '7'; break;
case NS_VK_NUMPAD8 : asciiKey = '8'; break;
case NS_VK_NUMPAD9 : asciiKey = '9'; break;
case NS_VK_ADD: uniChars [0] = '+'; numOfUniChars = 1; break;
case NS_VK_SUBTRACT: uniChars [0] = '-'; numOfUniChars = 1; break;
case NS_VK_DIVIDE: uniChars [0] = '/'; numOfUniChars = 1; break;
case NS_VK_MULTIPLY: uniChars [0] = '*'; numOfUniChars = 1; break;
case NS_VK_NUMPAD0:
case NS_VK_NUMPAD1:
case NS_VK_NUMPAD2:
case NS_VK_NUMPAD3:
case NS_VK_NUMPAD4:
case NS_VK_NUMPAD5:
case NS_VK_NUMPAD6:
case NS_VK_NUMPAD7:
case NS_VK_NUMPAD8:
case NS_VK_NUMPAD9: uniChars [0] = virtualKeyCode - NS_VK_NUMPAD0 + '0'; numOfUniChars = 1; break;
default:
// NS_VK_0 - NS_VK_9 and NS_VK_A - NS_VK_Z match their ascii values
if ((NS_VK_0 <= virtualKeyCode && virtualKeyCode <= NS_VK_9) ||
(NS_VK_A <= virtualKeyCode && virtualKeyCode <= NS_VK_Z)) {
asciiKey = virtualKeyCode;
// Take the Shift state into account
if (!mIsShiftDown
&& NS_VK_A <= virtualKeyCode && virtualKeyCode <= NS_VK_Z) {
asciiKey += 0x20;
if (KeyboardLayout::IsPrintableCharKey (aVirtualKeyCode))
numOfUniChars = numOfShiftStates = gKbdLayout.GetUniChars (uniChars, shiftStates, NS_ARRAY_LENGTH (uniChars));
if (mIsControlDown ^ mIsAltDown)
{
// XXX
// For both Alt+key and Ctrl+key combinations we return the latin characters A..Z and
// numbers 0..9, ignoring the real characters returned by active keyboard layout.
// This is required to make sure that all shortcut keys (e.g. Ctrl+c, Ctrl+1, Alt+f)
// work the same way no matter what keyboard layout you are using.
// Currently it is impossible to use non-latin characters for keyboard shortcuts.
if ((NS_VK_0 <= virtualKeyCode && virtualKeyCode <= NS_VK_9) ||
(NS_VK_A <= virtualKeyCode && virtualKeyCode <= NS_VK_Z))
{
uniChars [0] = virtualKeyCode;
numOfUniChars = 1;
numOfShiftStates = 0;
// For letters take the Shift state into account
if (!mIsShiftDown &&
NS_VK_A <= virtualKeyCode && virtualKeyCode <= NS_VK_Z)
uniChars [0] += 0x20;
}
}
}
if (asciiKey)
DispatchKeyEvent(NS_KEY_PRESS, asciiKey, 0, aKeyData, extraFlags);
else
if (numOfUniChars)
{
for (PRUint32 cnt = 0; cnt < numOfUniChars; cnt++)
{
if (cnt < numOfShiftStates)
{
// If key in combination with Alt and/or Ctrl produces a different character than without them
// then do not report these flags because it is separate keyboard layout shift state.
// If dead-key and base character does not produce a valid composite character then both produced
// dead-key character and following base character may have different modifier flags, too.
mIsShiftDown = (shiftStates [cnt] & eShift) != 0;
mIsControlDown = (shiftStates [cnt] & eCtrl) != 0;
mIsAltDown = (shiftStates [cnt] & eAlt) != 0;
}
DispatchKeyEvent(NS_KEY_PRESS, uniChars [cnt], 0, aKeyData, extraFlags);
}
} else
DispatchKeyEvent(NS_KEY_PRESS, 0, virtualKeyCode, aKeyData, extraFlags);
return noDefault;
@ -6613,6 +6662,8 @@ BOOL nsWindow::OnInputLangChange(HKL aHKL, LRESULT *oRetValue)
NS_IMM_GETPROPERTY(gKeyboardLayout, IGP_PROPERTY, imeProp);
nsToolkit::mUseImeApiW = (imeProp & IME_PROP_UNICODE) ? PR_TRUE : PR_FALSE;
}
gKbdLayout.LoadLayout();
}
ResetInputState();