Bug 855975 part.1 Make widget::KeyboardLayout a singleton class r=jimm

This commit is contained in:
Masayuki Nakano 2013-05-29 15:34:47 +09:00
parent ab6c25371c
commit 73367a9a5c
5 changed files with 135 additions and 85 deletions

View File

@ -381,12 +381,13 @@ VirtualKey::FillKbdState(PBYTE aKbdState,
* mozilla::widget::NativeKey
*****************************************************************************/
NativeKey::NativeKey(const KeyboardLayout& aKeyboardLayout,
nsWindow* aWindow,
const MSG& aKeyOrCharMessage) :
NativeKey::NativeKey(nsWindow* aWindow,
const MSG& aKeyOrCharMessage,
const ModifierKeyState& aModKeyState) :
mDOMKeyCode(0), mMessage(aKeyOrCharMessage.message),
mVirtualKeyCode(0), mOriginalVirtualKeyCode(0)
{
KeyboardLayout* keyboardLayout = KeyboardLayout::GetInstance();
mScanCode = WinUtils::GetScanCode(aKeyOrCharMessage.lParam);
mIsExtended = WinUtils::IsExtendedScanCode(aKeyOrCharMessage.lParam);
// On WinXP and WinServer2003, we cannot compute the virtual keycode for
@ -486,7 +487,7 @@ NativeKey::NativeKey(const KeyboardLayout& aKeyboardLayout,
// Otherwise, compute the virtual keycode with MapVirtualKeyEx().
mVirtualKeyCode = static_cast<uint8_t>(
::MapVirtualKeyEx(GetScanCodeWithExtendedFlag(),
MAPVK_VSC_TO_VK_EX, aKeyboardLayout.GetLayout()));
MAPVK_VSC_TO_VK_EX, keyboardLayout->GetLayout()));
// The result might be unexpected value due to the scan code is
// wrong. For example, any key messages can be generated by
@ -528,7 +529,7 @@ NativeKey::NativeKey(const KeyboardLayout& aKeyboardLayout,
}
mVirtualKeyCode = mOriginalVirtualKeyCode = static_cast<uint8_t>(
::MapVirtualKeyEx(GetScanCodeWithExtendedFlag(),
MAPVK_VSC_TO_VK_EX, aKeyboardLayout.GetLayout()));
MAPVK_VSC_TO_VK_EX, keyboardLayout->GetLayout()));
break;
default:
MOZ_NOT_REACHED("Unsupported message");
@ -540,9 +541,11 @@ NativeKey::NativeKey(const KeyboardLayout& aKeyboardLayout,
}
mDOMKeyCode =
aKeyboardLayout.ConvertNativeKeyCodeToDOMKeyCode(mOriginalVirtualKeyCode);
keyboardLayout->ConvertNativeKeyCodeToDOMKeyCode(mOriginalVirtualKeyCode);
mKeyNameIndex =
aKeyboardLayout.ConvertNativeKeyCodeToKeyNameIndex(mOriginalVirtualKeyCode);
keyboardLayout->ConvertNativeKeyCodeToKeyNameIndex(mOriginalVirtualKeyCode);
keyboardLayout->InitNativeKey(*this, aModKeyState);
}
UINT
@ -628,14 +631,33 @@ NativeKey::GetKeyLocation() const
* mozilla::widget::KeyboardLayout
*****************************************************************************/
KeyboardLayout* KeyboardLayout::sInstance = nullptr;
// static
KeyboardLayout*
KeyboardLayout::GetInstance()
{
if (!sInstance) {
sInstance = new KeyboardLayout();
}
return sInstance;
}
// static
void
KeyboardLayout::Shutdown()
{
delete sInstance;
sInstance = nullptr;
}
KeyboardLayout::KeyboardLayout() :
mKeyboardLayout(0), mPendingKeyboardLayout(0)
mKeyboardLayout(0), mIsOverridden(false),
mIsPendingToRestoreKeyboardLayout(false)
{
mDeadKeyTableListHead = nullptr;
// Note: Don't call LoadLayout from here. Because an instance of this class
// can be static. In that case, we cannot use any services in LoadLayout,
// e.g., pref service.
// NOTE: LoadLayout() should be called via OnLayoutChange().
}
KeyboardLayout::~KeyboardLayout()
@ -666,8 +688,8 @@ void
KeyboardLayout::InitNativeKey(NativeKey& aNativeKey,
const ModifierKeyState& aModKeyState)
{
if (mPendingKeyboardLayout) {
LoadLayout(mPendingKeyboardLayout);
if (mIsPendingToRestoreKeyboardLayout) {
LoadLayout(::GetKeyboardLayout(0));
}
uint8_t virtualKey = aNativeKey.GetOriginalVirtualKeyCode();
@ -769,14 +791,9 @@ KeyboardLayout::GetUniCharsAndModifiers(
}
void
KeyboardLayout::LoadLayout(HKL aLayout, bool aLoadLater)
KeyboardLayout::LoadLayout(HKL aLayout)
{
if (aLoadLater) {
mPendingKeyboardLayout = aLayout;
return;
}
mPendingKeyboardLayout = 0;
mIsPendingToRestoreKeyboardLayout = false;
if (mKeyboardLayout == aLayout) {
return;

View File

@ -272,18 +272,14 @@ public:
UniCharsAndModifiers GetUniChars(ShiftState aShiftState) const;
};
class NativeKey {
public:
NativeKey() :
mDOMKeyCode(0), mKeyNameIndex(KEY_NAME_INDEX_Unidentified),
mMessage(0), mVirtualKeyCode(0), mOriginalVirtualKeyCode(0),
mScanCode(0), mIsExtended(false)
{
}
class MOZ_STACK_CLASS NativeKey
{
friend class KeyboardLayout;
NativeKey(const KeyboardLayout& aKeyboardLayout,
nsWindow* aWindow,
const MSG& aKeyOrCharMessage);
public:
NativeKey(nsWindow* aWindow,
const MSG& aKeyOrCharMessage,
const ModifierKeyState& aModKeyState);
uint32_t GetDOMKeyCode() const { return mDOMKeyCode; }
KeyNameIndex GetKeyNameIndex() const { return mKeyNameIndex; }
@ -325,13 +321,24 @@ private:
WORD mScanCode;
bool mIsExtended;
UINT GetScanCodeWithExtendedFlag() const;
NativeKey()
{
MOZ_NOT_REACHED("The default constructor of NativeKey isn't available");
}
friend class KeyboardLayout;
UINT GetScanCodeWithExtendedFlag() const;
};
class KeyboardLayout
{
friend class NativeKey;
private:
KeyboardLayout();
~KeyboardLayout();
static KeyboardLayout* sInstance;
struct DeadKeyTableListEntry
{
DeadKeyTableListEntry* next;
@ -339,13 +346,15 @@ class KeyboardLayout
};
HKL mKeyboardLayout;
HKL mPendingKeyboardLayout;
VirtualKey mVirtualKeys[NS_NUM_OF_KEYS];
DeadKeyTableListEntry* mDeadKeyTableListHead;
int32_t mActiveDeadKey; // -1 = no active dead-key
VirtualKey::ShiftState mDeadKeyShiftState;
bool mIsOverridden : 1;
bool mIsPendingToRestoreKeyboardLayout : 1;
static inline int32_t GetKeyIndex(uint8_t aVirtualKey);
static int CompareDeadKeyEntries(const void* aArg1, const void* aArg2,
void* aData);
@ -363,9 +372,24 @@ class KeyboardLayout
uint32_t aEntries);
void ReleaseDeadKeyTables();
/**
* Loads the specified keyboard layout. This method always clear the dead key
* state.
*/
void LoadLayout(HKL aLayout);
/**
* InitNativeKey() must be called when actually widget receives WM_KEYDOWN or
* WM_KEYUP. This method is stateful. This saves current dead key state at
* WM_KEYDOWN. Additionally, computes current inputted character(s) and set
* them to the aNativeKey.
*/
void InitNativeKey(NativeKey& aNativeKey,
const ModifierKeyState& aModKeyState);
public:
KeyboardLayout();
~KeyboardLayout();
static KeyboardLayout* GetInstance();
static void Shutdown();
static bool IsPrintableCharKey(uint8_t aVirtualKey);
@ -385,19 +409,34 @@ public:
const ModifierKeyState& aModKeyState) const;
/**
* InitNativeKey() must be called when actually widget receives WM_KEYDOWN or
* WM_KEYUP. This method is stateful. This saves current dead key state at
* WM_KEYDOWN. Additionally, computes current inputted character(s) and set
* them to the aNativeKey.
* OnLayoutChange() must be called before the first keydown message is
* received. LoadLayout() changes the keyboard state, that causes breaking
* dead key state. Therefore, we need to load the layout before the first
* keydown message.
*/
void InitNativeKey(NativeKey& aNativeKey,
const ModifierKeyState& aModKeyState);
void OnLayoutChange(HKL aKeyboardLayout)
{
MOZ_ASSERT(!mIsOverridden);
LoadLayout(aKeyboardLayout);
}
/**
* LoadLayout() loads the keyboard layout. If aLoadLater is true,
* it will be done when OnKeyDown() is called.
* OverrideLayout() loads the specified keyboard layout.
*/
void LoadLayout(HKL aLayout, bool aLoadLater = false);
void OverrideLayout(HKL aLayout)
{
mIsOverridden = true;
LoadLayout(aLayout);
}
/**
* RestoreLayout() loads the current keyboard layout of the thread.
*/
void RestoreLayout()
{
mIsOverridden = false;
mIsPendingToRestoreKeyboardLayout = true;
}
uint32_t ConvertNativeKeyCodeToDOMKeyCode(UINT aNativeKeyCode) const;
@ -409,7 +448,8 @@ public:
HKL GetLayout() const
{
return mPendingKeyboardLayout ? mPendingKeyboardLayout : mKeyboardLayout;
return mIsPendingToRestoreKeyboardLayout ? ::GetKeyboardLayout(0) :
mKeyboardLayout;
}
};

View File

@ -17,6 +17,7 @@
#include "nsScreenManagerWin.h"
#include "nsSound.h"
#include "WinMouseScrollHandler.h"
#include "KeyboardLayout.h"
#include "GfxInfo.h"
#include "nsToolkit.h"
@ -259,6 +260,7 @@ static const mozilla::Module::ContractIDEntry kWidgetContracts[] = {
static void
nsWidgetWindowsModuleDtor()
{
KeyboardLayout::Shutdown();
MouseScrollHandler::Shutdown();
nsLookAndFeel::Shutdown();
nsToolkit::Shutdown();

View File

@ -248,9 +248,6 @@ static const char *sScreenManagerContractID = "@mozilla.org/gfx/screenmana
PRLogModuleInfo* gWindowsLog = nullptr;
#endif
// Kbd layout. Used throughout character processing.
static KeyboardLayout gKbdLayout;
// Global used in Show window enumerations.
static bool gWindowsVisible = false;
@ -356,7 +353,7 @@ nsWindow::nsWindow() : nsWindowBase()
// Global app registration id for Win7 and up. See
// WinTaskbar.cpp for details.
mozilla::widget::WinTaskbar::RegisterAppUserModelID();
gKbdLayout.LoadLayout(::GetKeyboardLayout(0));
KeyboardLayout::GetInstance()->OnLayoutChange(::GetKeyboardLayout(0));
IMEHandler::Initialize();
if (SUCCEEDED(::OleInitialize(NULL))) {
sIsOleInitialized = TRUE;
@ -5110,7 +5107,7 @@ bool nsWindow::ProcessMessage(UINT msg, WPARAM &wParam, LPARAM &lParam,
sJustGotDeactivate = true;
if (mIsTopWidgetWindow)
mLastKeyboardLayout = gKbdLayout.GetLayout();
mLastKeyboardLayout = KeyboardLayout::GetInstance()->GetLayout();
} else {
StopFlashing();
@ -5195,7 +5192,9 @@ bool nsWindow::ProcessMessage(UINT msg, WPARAM &wParam, LPARAM &lParam,
break;
case WM_INPUTLANGCHANGE:
result = OnInputLangChange((HKL)lParam);
KeyboardLayout::GetInstance()->
OnLayoutChange(reinterpret_cast<HKL>(lParam));
result = false; // always pass to child window
break;
case WM_DESTROYCLIPBOARD:
@ -5656,8 +5655,7 @@ LRESULT nsWindow::ProcessCharMessage(const MSG &aMsg, bool *aEventDispatched)
// These must be checked here too as a lone WM_CHAR could be received
// if a child window didn't handle it (for example Alt+Space in a content window)
ModifierKeyState modKeyState;
NativeKey nativeKey(gKbdLayout, this, aMsg);
gKbdLayout.InitNativeKey(nativeKey, modKeyState);
NativeKey nativeKey(this, aMsg, modKeyState);
return OnChar(aMsg, nativeKey, modKeyState, aEventDispatched);
}
@ -5790,8 +5788,9 @@ nsWindow::SynthesizeNativeKeyEvent(int32_t aNativeKeyboardLayout,
// This changes the state of the keyboard for the current thread only,
// and we'll restore it soon, so this should be OK.
::SetKeyboardState(kbdState);
HKL oldLayout = gKbdLayout.GetLayout();
gKbdLayout.LoadLayout(loadedLayout);
KeyboardLayout* keyboardLayout = KeyboardLayout::GetInstance();
keyboardLayout->OverrideLayout(loadedLayout);
uint8_t argumentKeySpecific = 0;
switch (aNativeKeyCode) {
@ -5865,7 +5864,8 @@ nsWindow::SynthesizeNativeKeyEvent(int32_t aNativeKeyboardLayout,
ModifierKeyState modKeyState;
UINT scanCode = ::MapVirtualKeyEx(argumentKeySpecific ?
argumentKeySpecific : aNativeKeyCode,
MAPVK_VK_TO_VSC, gKbdLayout.GetLayout());
MAPVK_VK_TO_VSC,
keyboardLayout->GetLayout());
LPARAM lParam = static_cast<LPARAM>(scanCode << 16);
// Add extended key flag to the lParam for right control key and right alt
// key.
@ -5875,11 +5875,11 @@ nsWindow::SynthesizeNativeKeyEvent(int32_t aNativeKeyboardLayout,
MSG msg = WinUtils::InitMSG(WM_KEYDOWN, key, lParam);
if (i == keySequence.Length() - 1) {
bool makeDeadCharMessage =
gKbdLayout.IsDeadKey(key, modKeyState) && aCharacters.IsEmpty();
keyboardLayout->IsDeadKey(key, modKeyState) && aCharacters.IsEmpty();
nsAutoString chars(aCharacters);
if (makeDeadCharMessage) {
UniCharsAndModifiers deadChars =
gKbdLayout.GetUniCharsAndModifiers(key, modKeyState);
keyboardLayout->GetUniCharsAndModifiers(key, modKeyState);
chars = deadChars.ToString();
NS_ASSERTION(chars.Length() == 1,
"Dead char must be only one character");
@ -5893,7 +5893,7 @@ nsWindow::SynthesizeNativeKeyEvent(int32_t aNativeKeyboardLayout,
for (uint32_t j = 1; j < chars.Length(); j++) {
nsFakeCharMessage fakeMsg = { chars.CharAt(j), scanCode, false };
MSG msg = fakeMsg.GetCharMessage(mWnd);
NativeKey nativeKey(gKbdLayout, this, msg);
NativeKey nativeKey(this, msg, modKeyState);
OnChar(msg, nativeKey, modKeyState, nullptr);
}
}
@ -5912,7 +5912,8 @@ nsWindow::SynthesizeNativeKeyEvent(int32_t aNativeKeyboardLayout,
ModifierKeyState modKeyState;
UINT scanCode = ::MapVirtualKeyEx(argumentKeySpecific ?
argumentKeySpecific : aNativeKeyCode,
MAPVK_VK_TO_VSC, gKbdLayout.GetLayout());
MAPVK_VK_TO_VSC,
keyboardLayout->GetLayout());
LPARAM lParam = static_cast<LPARAM>(scanCode << 16);
// Add extended key flag to the lParam for right control key and right alt
// key.
@ -5925,7 +5926,7 @@ nsWindow::SynthesizeNativeKeyEvent(int32_t aNativeKeyboardLayout,
// Restore old key state and layout
::SetKeyboardState(originalKbdState);
gKbdLayout.LoadLayout(oldLayout, true);
keyboardLayout->RestoreLayout();
// Don't unload the layout if it's installed actually.
for (uint32_t i = 0; i < keyboardLayoutListCount; i++) {
@ -5985,15 +5986,6 @@ nsWindow::SynthesizeNativeMouseScrollEvent(nsIntPoint aPoint,
*
**************************************************************/
BOOL nsWindow::OnInputLangChange(HKL aHKL)
{
#ifdef KE_DEBUG
PR_LOG(gWindowsLog, PR_LOG_ALWAYS, ("OnInputLanguageChange\n"));
#endif
gKbdLayout.LoadLayout(aHKL);
return false; // always pass to child window
}
void nsWindow::OnWindowPosChanged(WINDOWPOS *wp, bool& result)
{
if (wp == nullptr)
@ -6464,8 +6456,8 @@ LRESULT nsWindow::OnKeyDown(const MSG &aMsg,
bool *aEventDispatched,
nsFakeCharMessage* aFakeCharMessage)
{
NativeKey nativeKey(gKbdLayout, this, aMsg);
gKbdLayout.InitNativeKey(nativeKey, aModKeyState);
KeyboardLayout* keyboardLayout = KeyboardLayout::GetInstance();
NativeKey nativeKey(this, aMsg, aModKeyState);
UniCharsAndModifiers inputtingChars =
nativeKey.GetCommittedCharsAndModifiers();
uint32_t DOMKeyCode = nativeKey.GetDOMKeyCode();
@ -6556,7 +6548,7 @@ LRESULT nsWindow::OnKeyDown(const MSG &aMsg,
}
UINT virtualKeyCode = nativeKey.GetOriginalVirtualKeyCode();
bool isDeadKey = gKbdLayout.IsDeadKey(virtualKeyCode, aModKeyState);
bool isDeadKey = keyboardLayout->IsDeadKey(virtualKeyCode, aModKeyState);
EventFlags extraFlags;
extraFlags.mDefaultPrevented = noDefault;
MSG msg;
@ -6681,10 +6673,10 @@ LRESULT nsWindow::OnKeyDown(const MSG &aMsg,
widget::ModifierKeyState capsLockState(
aModKeyState.GetModifiers() & MODIFIER_CAPSLOCK);
unshiftedChars =
gKbdLayout.GetUniCharsAndModifiers(virtualKeyCode, capsLockState);
keyboardLayout->GetUniCharsAndModifiers(virtualKeyCode, capsLockState);
capsLockState.Set(MODIFIER_SHIFT);
shiftedChars =
gKbdLayout.GetUniCharsAndModifiers(virtualKeyCode, capsLockState);
keyboardLayout->GetUniCharsAndModifiers(virtualKeyCode, capsLockState);
// The current keyboard cannot input alphabets or numerics,
// we should append them for Shortcut/Access keys.
@ -6831,8 +6823,7 @@ LRESULT nsWindow::OnKeyUp(const MSG &aMsg,
if (aEventDispatched)
*aEventDispatched = true;
nsKeyEvent keyupEvent(true, NS_KEY_UP, this);
NativeKey nativeKey(gKbdLayout, this, aMsg);
gKbdLayout.InitNativeKey(nativeKey, aModKeyState);
NativeKey nativeKey(this, aMsg, aModKeyState);
keyupEvent.keyCode = nativeKey.GetDOMKeyCode();
InitKeyEvent(keyupEvent, nativeKey, aModKeyState);
// Set defaultPrevented of the key event if the VK_MENU is not a system key
@ -6900,14 +6891,15 @@ LRESULT nsWindow::OnChar(const MSG &aMsg,
// Keep the characters unshifted for shortcuts and accesskeys and make sure
// that numbers are always passed as such (among others: bugs 50255 and 351310)
if (uniChar && (modKeyState.IsControl() || modKeyState.IsAlt())) {
UINT virtualKeyCode = ::MapVirtualKeyEx(aNativeKey.GetScanCode(),
MAPVK_VSC_TO_VK,
gKbdLayout.GetLayout());
KeyboardLayout* keyboardLayout = KeyboardLayout::GetInstance();
UINT virtualKeyCode =
::MapVirtualKeyEx(aNativeKey.GetScanCode(),
MAPVK_VSC_TO_VK, keyboardLayout->GetLayout());
UINT unshiftedCharCode =
virtualKeyCode >= '0' && virtualKeyCode <= '9' ? virtualKeyCode :
modKeyState.IsShift() ? ::MapVirtualKeyEx(virtualKeyCode,
MAPVK_VK_TO_CHAR,
gKbdLayout.GetLayout()) : 0;
modKeyState.IsShift() ?
::MapVirtualKeyEx(virtualKeyCode, MAPVK_VK_TO_CHAR,
keyboardLayout->GetLayout()) : 0;
// ignore diacritics (top bit set) and key mapping errors (char code 0)
if ((INT)unshiftedCharCode > 0)
uniChar = unshiftedCharCode;

View File

@ -388,7 +388,6 @@ protected:
bool OnGesture(WPARAM wParam, LPARAM lParam);
bool OnTouch(WPARAM wParam, LPARAM lParam);
bool OnHotKey(WPARAM wParam, LPARAM lParam);
BOOL OnInputLangChange(HKL aHKL);
bool OnPaint(HDC aDC, uint32_t aNestingLevel);
void OnWindowPosChanged(WINDOWPOS *wp, bool& aResult);
void OnWindowPosChanging(LPWINDOWPOS& info);