mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-27 23:02:20 +00:00
Bug 1878224 - Put it off to load keyboard layout when first needed r=m_kato
As far as I've tested on Win 11, we can put it off to load it when first needed of the keyboard layout data. `ToUnicodeEx` API changes the dead key state and it's called a lot in `KeyboardLayout::LoadLayout`, however, this patch does not newly call `LoadLayout` after `TranslateMessage` API at least while handling a key message. Therefore, this should be safe but regressions of this change could be serious, so this makes it enabled only in early beta and earlier for now. Differential Revision: https://phabricator.services.mozilla.com/D200600
This commit is contained in:
parent
84e0f8920d
commit
8b02ebad10
@ -14765,6 +14765,13 @@
|
||||
#endif
|
||||
mirror: always
|
||||
|
||||
#ifdef XP_WIN
|
||||
- name: ui.key.layout.load_when_first_needed
|
||||
type: bool
|
||||
value: @IS_EARLY_BETA_OR_EARLIER@
|
||||
mirror: always
|
||||
#endif
|
||||
|
||||
# Does the access key by itself focus the menu bar?
|
||||
- name: ui.key.menuAccessKeyFocuses
|
||||
type: bool
|
||||
|
@ -9,6 +9,7 @@
|
||||
#include "mozilla/AutoRestore.h"
|
||||
#include "mozilla/MouseEvents.h"
|
||||
#include "mozilla/MiscEvents.h"
|
||||
#include "mozilla/StaticPrefs_ui.h"
|
||||
#include "mozilla/TextEvents.h"
|
||||
#include "mozilla/widget/WinRegistry.h"
|
||||
|
||||
@ -848,7 +849,7 @@ void ModifierKeyState::Update() {
|
||||
// MODIFIER_ALTGRAPH should be set. Otherwise, i.e., if both Ctrl and Alt
|
||||
// keys are pressed to emulate AltGr key, MODIFIER_CONTROL and MODIFIER_ALT
|
||||
// keys should be set separately.
|
||||
if (KeyboardLayout::GetInstance()->HasAltGr() && IS_VK_DOWN(VK_RMENU)) {
|
||||
if (IS_VK_DOWN(VK_RMENU) && KeyboardLayout::GetInstance()->HasAltGr()) {
|
||||
mModifiers |= MODIFIER_ALTGRAPH;
|
||||
} else {
|
||||
if (IS_VK_DOWN(VK_CONTROL)) {
|
||||
@ -1278,10 +1279,10 @@ NativeKey::NativeKey(nsWindow* aWidget, const MSG& aMessage,
|
||||
MOZ_ASSERT(mDispatcher);
|
||||
sLatestInstance = this;
|
||||
KeyboardLayout* keyboardLayout = KeyboardLayout::GetInstance();
|
||||
mKeyboardLayout = keyboardLayout->GetLayout();
|
||||
mKeyboardLayout = KeyboardLayout::GetLayout();
|
||||
if (aOverrideKeyboardLayout && mKeyboardLayout != aOverrideKeyboardLayout) {
|
||||
keyboardLayout->OverrideLayout(aOverrideKeyboardLayout);
|
||||
mKeyboardLayout = keyboardLayout->GetLayout();
|
||||
mKeyboardLayout = keyboardLayout->GetLoadedLayout();
|
||||
MOZ_ASSERT(mKeyboardLayout == aOverrideKeyboardLayout);
|
||||
mIsOverridingKeyboardLayout = true;
|
||||
} else {
|
||||
@ -3229,9 +3230,10 @@ bool NativeKey::GetFollowingCharMessage(MSG& aCharMsg) {
|
||||
"\nWM_NULL has been removed: %d, "
|
||||
"\nNext key message in all windows: %s, "
|
||||
"time=%ld, ",
|
||||
KeyboardLayout::GetActiveLayout(),
|
||||
KeyboardLayout::GetActiveLayoutName().get(), ToString(mMsg).get(),
|
||||
GetResultOfInSendMessageEx().get(), ToString(kFoundCharMsg).get(), i,
|
||||
KeyboardLayout::GetInstance()->GetLoadedLayout(),
|
||||
KeyboardLayout::GetInstance()->GetLoadedLayoutName().get(),
|
||||
ToString(mMsg).get(), GetResultOfInSendMessageEx().get(),
|
||||
ToString(kFoundCharMsg).get(), i,
|
||||
ToString(nextKeyMsgInAllWindows).get(), nextKeyMsgInAllWindows.time);
|
||||
CrashReporter::AppendAppNotesToCrashReport(info);
|
||||
MSG nextMsg;
|
||||
@ -3375,10 +3377,10 @@ bool NativeKey::GetFollowingCharMessage(MSG& aCharMsg) {
|
||||
"\nHandling message: %s, InSendMessageEx()=%s, "
|
||||
"\nFound message: %s, "
|
||||
"\nRemoved message: %s, ",
|
||||
KeyboardLayout::GetActiveLayout(),
|
||||
KeyboardLayout::GetActiveLayoutName().get(), ToString(mMsg).get(),
|
||||
GetResultOfInSendMessageEx().get(), ToString(kFoundCharMsg).get(),
|
||||
ToString(removedMsg).get());
|
||||
KeyboardLayout::GetInstance()->GetLoadedLayout(),
|
||||
KeyboardLayout::GetInstance()->GetLoadedLayoutName().get(),
|
||||
ToString(mMsg).get(), GetResultOfInSendMessageEx().get(),
|
||||
ToString(kFoundCharMsg).get(), ToString(removedMsg).get());
|
||||
CrashReporter::AppendAppNotesToCrashReport(info);
|
||||
// What's the next key message?
|
||||
MSG nextKeyMsgAfter;
|
||||
@ -3417,9 +3419,10 @@ bool NativeKey::GetFollowingCharMessage(MSG& aCharMsg) {
|
||||
"\nActive keyboard layout=0x%p (%s), "
|
||||
"\nHandling message: %s, InSendMessageEx()=%s, \n"
|
||||
"Found message: %s, removed a lot of WM_NULL",
|
||||
KeyboardLayout::GetActiveLayout(),
|
||||
KeyboardLayout::GetActiveLayoutName().get(), ToString(mMsg).get(),
|
||||
GetResultOfInSendMessageEx().get(), ToString(kFoundCharMsg).get());
|
||||
KeyboardLayout::GetInstance()->GetLoadedLayout(),
|
||||
KeyboardLayout::GetInstance()->GetLoadedLayoutName().get(),
|
||||
ToString(mMsg).get(), GetResultOfInSendMessageEx().get(),
|
||||
ToString(kFoundCharMsg).get());
|
||||
CrashReporter::AppendAppNotesToCrashReport(info);
|
||||
MOZ_CRASH("We lost the following char message");
|
||||
return false;
|
||||
@ -3814,16 +3817,12 @@ void NativeKey::WillDispatchKeyboardEvent(WidgetKeyboardEvent& aKeyboardEvent,
|
||||
*****************************************************************************/
|
||||
|
||||
KeyboardLayout* KeyboardLayout::sInstance = nullptr;
|
||||
nsIUserIdleServiceInternal* KeyboardLayout::sIdleService = nullptr;
|
||||
StaticRefPtr<nsIUserIdleServiceInternal> KeyboardLayout::sIdleService;
|
||||
|
||||
// static
|
||||
KeyboardLayout* KeyboardLayout::GetInstance() {
|
||||
if (!sInstance) {
|
||||
sInstance = new KeyboardLayout();
|
||||
nsCOMPtr<nsIUserIdleServiceInternal> idleService =
|
||||
do_GetService("@mozilla.org/widget/useridleservice;1");
|
||||
// The refcount will be decreased at shut down.
|
||||
sIdleService = idleService.forget().take();
|
||||
}
|
||||
return sInstance;
|
||||
}
|
||||
@ -3832,19 +3831,23 @@ KeyboardLayout* KeyboardLayout::GetInstance() {
|
||||
void KeyboardLayout::Shutdown() {
|
||||
delete sInstance;
|
||||
sInstance = nullptr;
|
||||
NS_IF_RELEASE(sIdleService);
|
||||
sIdleService = nullptr;
|
||||
}
|
||||
|
||||
// static
|
||||
void KeyboardLayout::NotifyIdleServiceOfUserActivity() {
|
||||
if (!sIdleService) {
|
||||
sIdleService = nsCOMPtr<nsIUserIdleServiceInternal>(
|
||||
do_GetService("@mozilla.org/widget/useridleservice;1"))
|
||||
.forget();
|
||||
if (NS_WARN_IF(!sIdleService)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
sIdleService->ResetIdleTimeOut(0);
|
||||
}
|
||||
|
||||
KeyboardLayout::KeyboardLayout()
|
||||
: mKeyboardLayout(0),
|
||||
mIsOverridden(false),
|
||||
mIsPendingToRestoreKeyboardLayout(false),
|
||||
mHasAltGr(false) {
|
||||
KeyboardLayout::KeyboardLayout() {
|
||||
mDeadKeyTableListHead = nullptr;
|
||||
// A dead key sequence should be made from up to 5 keys. Therefore, 4 is
|
||||
// enough and makes sense because the item is uint8_t.
|
||||
@ -3853,7 +3856,12 @@ KeyboardLayout::KeyboardLayout()
|
||||
mActiveDeadKeys.SetCapacity(4);
|
||||
mDeadKeyShiftStates.SetCapacity(4);
|
||||
|
||||
// NOTE: LoadLayout() should be called via OnLayoutChange().
|
||||
// If we put it off to load active keyboard layout when first needed, we need
|
||||
// to load it at instanciation. That makes us save the cost of a call of
|
||||
// GetKeyboardLayout() API.
|
||||
if (StaticPrefs::ui_key_layout_load_when_first_needed()) {
|
||||
OnLayoutChange(::GetKeyboardLayout(0));
|
||||
}
|
||||
}
|
||||
|
||||
KeyboardLayout::~KeyboardLayout() { ReleaseDeadKeyTables(); }
|
||||
@ -3864,8 +3872,8 @@ bool KeyboardLayout::IsPrintableCharKey(uint8_t aVirtualKey) {
|
||||
|
||||
WORD KeyboardLayout::ComputeScanCodeForVirtualKeyCode(
|
||||
uint8_t aVirtualKeyCode) const {
|
||||
return static_cast<WORD>(
|
||||
::MapVirtualKeyEx(aVirtualKeyCode, MAPVK_VK_TO_VSC, GetLayout()));
|
||||
return static_cast<WORD>(::MapVirtualKeyEx(aVirtualKeyCode, MAPVK_VK_TO_VSC,
|
||||
KeyboardLayout::GetLayout()));
|
||||
}
|
||||
|
||||
bool KeyboardLayout::IsDeadKey(uint8_t aVirtualKey,
|
||||
@ -4245,14 +4253,6 @@ char16_t KeyboardLayout::GetCompositeChar(char16_t aBaseChar) const {
|
||||
return mVirtualKeys[key].GetCompositeChar(mDeadKeyShiftStates[0], aBaseChar);
|
||||
}
|
||||
|
||||
// static
|
||||
HKL KeyboardLayout::GetActiveLayout() { return GetInstance()->mKeyboardLayout; }
|
||||
|
||||
// static
|
||||
nsCString KeyboardLayout::GetActiveLayoutName() {
|
||||
return GetInstance()->GetLayoutName(GetActiveLayout());
|
||||
}
|
||||
|
||||
static bool IsValidKeyboardLayoutsChild(const nsAString& aChildName) {
|
||||
if (aChildName.Length() != 8) {
|
||||
return false;
|
||||
@ -4268,7 +4268,8 @@ static bool IsValidKeyboardLayoutsChild(const nsAString& aChildName) {
|
||||
return true;
|
||||
}
|
||||
|
||||
nsCString KeyboardLayout::GetLayoutName(HKL aLayout) const {
|
||||
// static
|
||||
nsCString KeyboardLayout::GetLayoutName(HKL aLayout) {
|
||||
constexpr auto kKeyboardLayouts =
|
||||
u"SYSTEM\\CurrentControlSet\\Control\\Keyboard Layouts\\"_ns;
|
||||
uint16_t language = reinterpret_cast<uintptr_t>(aLayout) & 0xFFFF;
|
||||
@ -5076,7 +5077,7 @@ KeyNameIndex KeyboardLayout::ConvertNativeKeyCodeToKeyNameIndex(
|
||||
break;
|
||||
}
|
||||
|
||||
HKL layout = GetLayout();
|
||||
HKL layout = KeyboardLayout::GetLayout();
|
||||
WORD langID = LOWORD(static_cast<HKL>(layout));
|
||||
WORD primaryLangID = PRIMARYLANGID(langID);
|
||||
|
||||
|
@ -14,6 +14,7 @@
|
||||
#include "nsWindowDefs.h"
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "mozilla/EventForwards.h"
|
||||
#include "mozilla/StaticPtr.h"
|
||||
#include "mozilla/TextEventDispatcher.h"
|
||||
#include "mozilla/widget/WinMessages.h"
|
||||
#include "mozilla/widget/WinModifierKeyState.h"
|
||||
@ -824,8 +825,34 @@ class KeyboardLayout {
|
||||
public:
|
||||
static KeyboardLayout* GetInstance();
|
||||
static void Shutdown();
|
||||
static HKL GetActiveLayout();
|
||||
static nsCString GetActiveLayoutName();
|
||||
|
||||
/**
|
||||
* GetLayout() returns a keyboard layout which has already been loaded in the
|
||||
* singleton instance or active keyboard layout.
|
||||
*/
|
||||
static HKL GetLayout() {
|
||||
if (!sInstance || sInstance->mIsPendingToRestoreKeyboardLayout) {
|
||||
return ::GetKeyboardLayout(0);
|
||||
}
|
||||
return sInstance->mKeyboardLayout;
|
||||
}
|
||||
|
||||
/**
|
||||
* GetLoadedLayout() returns a keyboard layout which was loaded in the
|
||||
* singleton instance. This may be different from the active keyboard layout
|
||||
* on the system if we override the keyboard layout for synthesizing native
|
||||
* key events for tests.
|
||||
*/
|
||||
HKL GetLoadedLayout() { return mKeyboardLayout; }
|
||||
|
||||
/**
|
||||
* GetLoadedLayoutName() returns the name of the loaded keyboard layout in the
|
||||
* singleton instance.
|
||||
*/
|
||||
nsCString GetLoadedLayoutName() {
|
||||
return KeyboardLayout::GetLayoutName(mKeyboardLayout);
|
||||
}
|
||||
|
||||
static void NotifyIdleServiceOfUserActivity();
|
||||
|
||||
static bool IsPrintableCharKey(uint8_t aVirtualKey);
|
||||
@ -925,11 +952,6 @@ class KeyboardLayout {
|
||||
*/
|
||||
static CodeNameIndex ConvertScanCodeToCodeNameIndex(UINT aScanCode);
|
||||
|
||||
HKL GetLayout() const {
|
||||
return mIsPendingToRestoreKeyboardLayout ? ::GetKeyboardLayout(0)
|
||||
: mKeyboardLayout;
|
||||
}
|
||||
|
||||
/**
|
||||
* This wraps MapVirtualKeyEx() API with MAPVK_VK_TO_VSC.
|
||||
*/
|
||||
@ -950,17 +972,17 @@ class KeyboardLayout {
|
||||
~KeyboardLayout();
|
||||
|
||||
static KeyboardLayout* sInstance;
|
||||
static nsIUserIdleServiceInternal* sIdleService;
|
||||
static StaticRefPtr<nsIUserIdleServiceInternal> sIdleService;
|
||||
|
||||
struct DeadKeyTableListEntry {
|
||||
DeadKeyTableListEntry* next;
|
||||
uint8_t data[1];
|
||||
};
|
||||
|
||||
HKL mKeyboardLayout;
|
||||
HKL mKeyboardLayout = nullptr;
|
||||
|
||||
VirtualKey mVirtualKeys[NS_NUM_OF_KEYS];
|
||||
DeadKeyTableListEntry* mDeadKeyTableListHead;
|
||||
VirtualKey mVirtualKeys[NS_NUM_OF_KEYS] = {};
|
||||
DeadKeyTableListEntry* mDeadKeyTableListHead = nullptr;
|
||||
// When mActiveDeadKeys is empty, it's not in dead key sequence.
|
||||
// Otherwise, it contains virtual keycodes which are pressed in current
|
||||
// dead key sequence.
|
||||
@ -970,9 +992,9 @@ class KeyboardLayout {
|
||||
// mActiveDeadKeys.
|
||||
nsTArray<VirtualKey::ShiftState> mDeadKeyShiftStates;
|
||||
|
||||
bool mIsOverridden;
|
||||
bool mIsPendingToRestoreKeyboardLayout;
|
||||
bool mHasAltGr;
|
||||
bool mIsOverridden = false;
|
||||
bool mIsPendingToRestoreKeyboardLayout = false;
|
||||
bool mHasAltGr = false;
|
||||
|
||||
static inline int32_t GetKeyIndex(uint8_t aVirtualKey);
|
||||
static bool AddDeadKeyEntry(char16_t aBaseChar, char16_t aCompositeChar,
|
||||
@ -1003,7 +1025,7 @@ class KeyboardLayout {
|
||||
* Gets the keyboard layout name of aLayout. Be careful, this may be too
|
||||
* slow to call at handling user input.
|
||||
*/
|
||||
nsCString GetLayoutName(HKL aLayout) const;
|
||||
static nsCString GetLayoutName(HKL aLayout);
|
||||
|
||||
/**
|
||||
* InitNativeKey() must be called when actually widget receives WM_KEYDOWN or
|
||||
|
@ -6,9 +6,12 @@
|
||||
#include "WinIMEHandler.h"
|
||||
|
||||
#include "IMMHandler.h"
|
||||
#include "KeyboardLayout.h"
|
||||
#include "mozilla/Preferences.h"
|
||||
#include "mozilla/StaticPrefs_intl.h"
|
||||
#include "mozilla/StaticPrefs_ui.h"
|
||||
#include "mozilla/TextEvents.h"
|
||||
#include "mozilla/Unused.h"
|
||||
#include "mozilla/WindowsVersion.h"
|
||||
#include "nsWindowDefs.h"
|
||||
#include "WinTextEventDispatcherListener.h"
|
||||
@ -134,6 +137,12 @@ void* IMEHandler::GetNativeData(nsWindow* aWindow, uint32_t aDataType) {
|
||||
|
||||
// static
|
||||
bool IMEHandler::ProcessRawKeyMessage(const MSG& aMsg) {
|
||||
if (StaticPrefs::ui_key_layout_load_when_first_needed()) {
|
||||
// Getting instance creates the singleton instance and that will
|
||||
// automatically load active keyboard layout data. We should do that
|
||||
// before TSF or TranslateMessage handles a key message.
|
||||
Unused << KeyboardLayout::GetInstance();
|
||||
}
|
||||
if (IsTSFAvailable()) {
|
||||
return TSFTextStore::ProcessRawKeyMessage(aMsg);
|
||||
}
|
||||
|
@ -162,6 +162,7 @@
|
||||
#include "mozilla/StaticPrefs_dom.h"
|
||||
#include "mozilla/StaticPrefs_gfx.h"
|
||||
#include "mozilla/StaticPrefs_layout.h"
|
||||
#include "mozilla/StaticPrefs_ui.h"
|
||||
#include "mozilla/StaticPrefs_widget.h"
|
||||
#include "nsNativeAppSupportWin.h"
|
||||
#include "mozilla/browser/NimbusFeatures.h"
|
||||
@ -682,7 +683,9 @@ nsWindow::nsWindow(bool aIsChildWindow)
|
||||
if (!WinUtils::HasPackageIdentity()) {
|
||||
mozilla::widget::WinTaskbar::RegisterAppUserModelID();
|
||||
}
|
||||
KeyboardLayout::GetInstance()->OnLayoutChange(::GetKeyboardLayout(0));
|
||||
if (!StaticPrefs::ui_key_layout_load_when_first_needed()) {
|
||||
KeyboardLayout::GetInstance()->OnLayoutChange(::GetKeyboardLayout(0));
|
||||
}
|
||||
#if defined(ACCESSIBILITY)
|
||||
mozilla::TIPMessageHandler::Initialize();
|
||||
#endif // defined(ACCESSIBILITY)
|
||||
@ -5738,7 +5741,7 @@ bool nsWindow::ProcessMessageInternal(UINT msg, WPARAM& wParam, LPARAM& lParam,
|
||||
sJustGotDeactivate = true;
|
||||
}
|
||||
if (mIsTopWidgetWindow) {
|
||||
mLastKeyboardLayout = KeyboardLayout::GetInstance()->GetLayout();
|
||||
mLastKeyboardLayout = KeyboardLayout::GetLayout();
|
||||
}
|
||||
} else {
|
||||
StopFlashing();
|
||||
|
Loading…
Reference in New Issue
Block a user