--- a/widget/windows/KeyboardLayout.cpp
+++ b/widget/windows/KeyboardLayout.cpp
@@ -14,16 +14,17 @@
#include "nsAlgorithm.h"
#ifdef MOZ_CRASHREPORTER
#include "nsExceptionHandler.h"
#endif
#include "nsGkAtoms.h"
#include "nsIDOMKeyEvent.h"
#include "nsIIdleServiceInternal.h"
+#include "nsIWindowsRegKey.h"
#include "nsMemory.h"
#include "nsPrintfCString.h"
#include "nsQuickSort.h"
#include "nsServiceManagerUtils.h"
#include "nsToolkit.h"
#include "nsUnicharUtils.h"
#include "nsWindowDbg.h"
@@ -2943,21 +2944,24 @@ NativeKey::GetFollowingCharMessage(MSG&
("%p NativeKey::GetFollowingCharMessage(), FAILED, lost target "
"message to remove, nextKeyMsg=%s",
this, ToString(nextKeyMsg).get()));
}
if (doCrash) {
#ifdef MOZ_CRASHREPORTER
nsPrintfCString info("\nPeekMessage() failed to remove char message! "
+ "\nActive keyboard layout=0x%08X (%s), "
"\nHandling message: %s, InSendMessageEx()=%s, "
"\nFound message: %s, "
"\nWM_NULL has been removed: %d, "
"\nNext key message in all windows: %s, "
"time=%d, ",
+ KeyboardLayout::GetActiveLayout(),
+ KeyboardLayout::GetActiveLayoutName().get(),
ToString(mMsg).get(),
GetResultOfInSendMessageEx().get(),
ToString(nextKeyMsg).get(), i,
ToString(nextKeyMsgInAllWindows).get(),
nextKeyMsgInAllWindows.time);
CrashReporter::AppendAppNotesToCrashReport(info);
MSG nextMsg;
if (WinUtils::PeekMessage(&nextMsg, 0, 0, 0,
@@ -3001,19 +3005,22 @@ NativeKey::GetFollowingCharMessage(MSG&
if (!MayBeSameCharMessage(removedMsg, nextKeyMsg)) {
MOZ_LOG(sNativeKeyLogger, LogLevel::Error,
("%p NativeKey::GetFollowingCharMessage(), FAILED, removed message "
"is really different from what we have already found, removedMsg=%s, "
"nextKeyMsg=%s",
this, ToString(removedMsg).get(), ToString(nextKeyMsg).get()));
#ifdef MOZ_CRASHREPORTER
nsPrintfCString info("\nPeekMessage() removed unexpcted char message! "
+ "\nActive keyboard layout=0x%08X (%s), "
"\nHandling message: %s, InSendMessageEx()=%s, "
"\nFound message: %s, "
"\nRemoved message: %s, ",
+ KeyboardLayout::GetActiveLayout(),
+ KeyboardLayout::GetActiveLayoutName().get(),
ToString(mMsg).get(),
GetResultOfInSendMessageEx().get(),
ToString(nextKeyMsg).get(),
ToString(removedMsg).get());
CrashReporter::AppendAppNotesToCrashReport(info);
// What's the next key message?
MSG nextKeyMsgAfter;
if (WinUtils::PeekMessage(&nextKeyMsgAfter, mMsg.hwnd,
@@ -3052,18 +3059,21 @@ NativeKey::GetFollowingCharMessage(MSG&
return true;
}
MOZ_LOG(sNativeKeyLogger, LogLevel::Error,
("%p NativeKey::GetFollowingCharMessage(), FAILED, removed messages "
"are all WM_NULL, nextKeyMsg=%s",
this, ToString(nextKeyMsg).get()));
#ifdef MOZ_CRASHREPORTER
nsPrintfCString info("\nWe lost following char message! "
+ "\nActive keyboard layout=0x%08X (%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(nextKeyMsg).get());
CrashReporter::AppendAppNotesToCrashReport(info);
#endif // #ifdef MOZ_CRASHREPORTER
MOZ_CRASH("We lost the following char message");
return false;
}
@@ -3883,29 +3893,148 @@ KeyboardLayout::GetCompositeChar(char16_
}
int32_t key = GetKeyIndex(mActiveDeadKeys[0]);
if (key < 0) {
return 0;
}
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;
+ }
+ for (size_t i = 0; i < aChildName.Length(); i++) {
+ if ((aChildName[i] >= '0' && aChildName[i] <= '9') ||
+ (aChildName[i] >= 'a' && aChildName[i] <= 'f') ||
+ (aChildName[i] >= 'A' && aChildName[i] <= 'F')) {
+ continue;
+ }
+ return false;
+ }
+ return true;
+}
+
+nsCString
+KeyboardLayout::GetLayoutName(HKL aLayout) const
+{
+ const wchar_t kKeyboardLayouts[] =
+ L"SYSTEM\\CurrentControlSet\\Control\\Keyboard Layouts\\";
+ uint16_t language = reinterpret_cast<uintptr_t>(aLayout) & 0xFFFF;
+ uint16_t layout = (reinterpret_cast<uintptr_t>(aLayout) >> 16) & 0xFFFF;
+ // If the layout is less than 0xA000XXXX (normal keyboard layout for the
+ // language) or 0xEYYYXXXX (IMM-IME), we can retrieve its name simply.
+ if (layout < 0xA000 || (layout & 0xF000) == 0xE000) {
+ nsAutoString key(kKeyboardLayouts);
+ key.AppendPrintf("%08X", layout < 0xA000 ?
+ layout : reinterpret_cast<uintptr_t>(aLayout));
+ wchar_t buf[256];
+ if (NS_WARN_IF(!WinUtils::GetRegistryKey(HKEY_LOCAL_MACHINE,
+ key.get(), L"Layout Text",
+ buf, sizeof(buf)))) {
+ return NS_LITERAL_CSTRING("No name or too long name");
+ }
+ return NS_ConvertUTF16toUTF8(buf);
+ }
+
+ if (NS_WARN_IF((layout & 0xF000) != 0xF000)) {
+ nsAutoCString result;
+ result.AppendPrintf("Odd HKL: 0x%08X",
+ reinterpret_cast<uintptr_t>(aLayout));
+ return result;
+ }
+
+ // Otherwise, we need to walk the registry under "Keyboard Layouts".
+ nsCOMPtr<nsIWindowsRegKey> regKey =
+ do_CreateInstance("@mozilla.org/windows-registry-key;1");
+ if (NS_WARN_IF(!regKey)) {
+ return EmptyCString();
+ }
+ nsresult rv = regKey->Open(nsIWindowsRegKey::ROOT_KEY_LOCAL_MACHINE,
+ nsString(kKeyboardLayouts),
+ nsIWindowsRegKey::ACCESS_READ);
+ if (NS_WARN_IF(NS_FAILED(rv))) {
+ return EmptyCString();
+ }
+ uint32_t childCount = 0;
+ if (NS_WARN_IF(NS_FAILED(regKey->GetChildCount(&childCount))) ||
+ NS_WARN_IF(!childCount)) {
+ return EmptyCString();
+ }
+ for (uint32_t i = 0; i < childCount; i++) {
+ nsAutoString childName;
+ if (NS_WARN_IF(NS_FAILED(regKey->GetChildName(i, childName))) ||
+ !IsValidKeyboardLayoutsChild(childName)) {
+ continue;
+ }
+ uint32_t childNum = static_cast<uint32_t>(childName.ToInteger64(&rv, 16));
+ if (NS_WARN_IF(NS_FAILED(rv))) {
+ continue;
+ }
+ // Ignore normal keyboard layouts for each language.
+ if (childNum <= 0xFFFF) {
+ continue;
+ }
+ // If it doesn't start with 'A' nor 'a', language should be matched.
+ if ((childNum & 0xFFFF) != language &&
+ (childNum & 0xF0000000) != 0xA0000000) {
+ continue;
+ }
+ // Then, the child should have "Layout Id" which is "YYY" of 0xFYYYXXXX.
+ nsAutoString key(kKeyboardLayouts);
+ key += childName;
+ wchar_t buf[256];
+ if (NS_WARN_IF(!WinUtils::GetRegistryKey(HKEY_LOCAL_MACHINE,
+ key.get(), L"Layout Id",
+ buf, sizeof(buf)))) {
+ continue;
+ }
+ uint16_t layoutId = wcstol(buf, nullptr, 16);
+ if (layoutId != (layout & 0x0FFF)) {
+ continue;
+ }
+ if (NS_WARN_IF(!WinUtils::GetRegistryKey(HKEY_LOCAL_MACHINE,
+ key.get(), L"Layout Text",
+ buf, sizeof(buf)))) {
+ continue;
+ }
+ return NS_ConvertUTF16toUTF8(buf);
+ }
+ return EmptyCString();
+}
+
void
KeyboardLayout::LoadLayout(HKL aLayout)
{
mIsPendingToRestoreKeyboardLayout = false;
if (mKeyboardLayout == aLayout) {
return;
}
mKeyboardLayout = aLayout;
- MOZ_LOG(sKeyboardLayoutLogger, LogLevel::Debug,
- ("KeyboardLayout::LoadLayout(aLayout=0x%08X)", aLayout));
+ MOZ_LOG(sKeyboardLayoutLogger, LogLevel::Info,
+ ("KeyboardLayout::LoadLayout(aLayout=0x%08X (%s))",
+ aLayout, GetLayoutName(aLayout).get()));
BYTE kbdState[256];
memset(kbdState, 0, sizeof(kbdState));
BYTE originalKbdState[256];
// Bitfield with all shift states that have at least one dead-key.
uint16_t shiftStatesWithDeadKeys = 0;
// Bitfield with all shift states that produce any possible dead-key base