diff options
Diffstat (limited to 'widget/windows/nsBidiKeyboard.cpp')
-rw-r--r-- | widget/windows/nsBidiKeyboard.cpp | 169 |
1 files changed, 169 insertions, 0 deletions
diff --git a/widget/windows/nsBidiKeyboard.cpp b/widget/windows/nsBidiKeyboard.cpp new file mode 100644 index 0000000000..87d81d458e --- /dev/null +++ b/widget/windows/nsBidiKeyboard.cpp @@ -0,0 +1,169 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include <stdio.h> +#include "nsBidiKeyboard.h" +#include "WidgetUtils.h" +#include "nsIWidget.h" +#include <tchar.h> + +NS_IMPL_ISUPPORTS(nsBidiKeyboard, nsIBidiKeyboard) + +nsBidiKeyboard::nsBidiKeyboard() : nsIBidiKeyboard() { Reset(); } + +nsBidiKeyboard::~nsBidiKeyboard() {} + +NS_IMETHODIMP nsBidiKeyboard::Reset() { + mInitialized = false; + mHaveBidiKeyboards = false; + mLTRKeyboard[0] = '\0'; + mRTLKeyboard[0] = '\0'; + mCurrentLocaleName[0] = '\0'; + return NS_OK; +} + +NS_IMETHODIMP nsBidiKeyboard::IsLangRTL(bool* aIsRTL) { + *aIsRTL = false; + + nsresult result = SetupBidiKeyboards(); + if (NS_FAILED(result)) return result; + + HKL currentLocale; + + currentLocale = ::GetKeyboardLayout(0); + *aIsRTL = IsRTLLanguage(currentLocale); + + if (!::GetKeyboardLayoutNameW(mCurrentLocaleName)) return NS_ERROR_FAILURE; + + NS_ASSERTION(*mCurrentLocaleName, + "GetKeyboardLayoutName return string length == 0"); + NS_ASSERTION((wcslen(mCurrentLocaleName) < KL_NAMELENGTH), + "GetKeyboardLayoutName return string length >= KL_NAMELENGTH"); + + // The language set by the user overrides the default language for that + // direction + if (*aIsRTL) { + wcsncpy(mRTLKeyboard, mCurrentLocaleName, KL_NAMELENGTH); + mRTLKeyboard[KL_NAMELENGTH - 1] = '\0'; // null terminate + } else { + wcsncpy(mLTRKeyboard, mCurrentLocaleName, KL_NAMELENGTH); + mLTRKeyboard[KL_NAMELENGTH - 1] = '\0'; // null terminate + } + + NS_ASSERTION((wcslen(mRTLKeyboard) < KL_NAMELENGTH), + "mLTRKeyboard has string length >= KL_NAMELENGTH"); + NS_ASSERTION((wcslen(mLTRKeyboard) < KL_NAMELENGTH), + "mRTLKeyboard has string length >= KL_NAMELENGTH"); + return NS_OK; +} + +NS_IMETHODIMP nsBidiKeyboard::GetHaveBidiKeyboards(bool* aResult) { + NS_ENSURE_ARG_POINTER(aResult); + + nsresult result = SetupBidiKeyboards(); + if (NS_FAILED(result)) return result; + + *aResult = mHaveBidiKeyboards; + return NS_OK; +} + +// Get the list of keyboard layouts available in the system +// Set mLTRKeyboard to the first LTR keyboard in the list and mRTLKeyboard to +// the first RTL keyboard in the list These defaults will be used unless the +// user explicitly sets something else. +nsresult nsBidiKeyboard::SetupBidiKeyboards() { + if (mInitialized) return mHaveBidiKeyboards ? NS_OK : NS_ERROR_FAILURE; + + int keyboards; + HKL far* buf; + HKL locale; + wchar_t localeName[KL_NAMELENGTH]; + bool isLTRKeyboardSet = false; + bool isRTLKeyboardSet = false; + + // GetKeyboardLayoutList with 0 as first parameter returns the number of + // keyboard layouts available + keyboards = ::GetKeyboardLayoutList(0, nullptr); + if (!keyboards) return NS_ERROR_FAILURE; + + // allocate a buffer to hold the list + buf = (HKL far*)malloc(keyboards * sizeof(HKL)); + if (!buf) return NS_ERROR_OUT_OF_MEMORY; + + // Call again to fill the buffer + if (::GetKeyboardLayoutList(keyboards, buf) != keyboards) { + free(buf); + return NS_ERROR_UNEXPECTED; + } + + // Go through the list and pick a default LTR and RTL keyboard layout + while (keyboards--) { + locale = buf[keyboards]; + if (IsRTLLanguage(locale)) { + _snwprintf(mRTLKeyboard, KL_NAMELENGTH, L"%.*x", KL_NAMELENGTH - 1, + LANGIDFROMLCID((DWORD_PTR)locale)); + isRTLKeyboardSet = true; + } else { + _snwprintf(mLTRKeyboard, KL_NAMELENGTH, L"%.*x", KL_NAMELENGTH - 1, + LANGIDFROMLCID((DWORD_PTR)locale)); + isLTRKeyboardSet = true; + } + } + free(buf); + mInitialized = true; + + // If there is not at least one keyboard of each directionality, Bidi + // keyboard functionality will be disabled. + mHaveBidiKeyboards = (isRTLKeyboardSet && isLTRKeyboardSet); + if (!mHaveBidiKeyboards) return NS_ERROR_FAILURE; + + // Get the current keyboard layout and use it for either mRTLKeyboard or + // mLTRKeyboard as appropriate. If the user has many keyboard layouts + // installed this prevents us from arbitrarily resetting the current + // layout (bug 80274) + locale = ::GetKeyboardLayout(0); + if (!::GetKeyboardLayoutNameW(localeName)) return NS_ERROR_FAILURE; + + NS_ASSERTION(*localeName, "GetKeyboardLayoutName return string length == 0"); + NS_ASSERTION((wcslen(localeName) < KL_NAMELENGTH), + "GetKeyboardLayout return string length >= KL_NAMELENGTH"); + + if (IsRTLLanguage(locale)) { + wcsncpy(mRTLKeyboard, localeName, KL_NAMELENGTH); + mRTLKeyboard[KL_NAMELENGTH - 1] = '\0'; // null terminate + } else { + wcsncpy(mLTRKeyboard, localeName, KL_NAMELENGTH); + mLTRKeyboard[KL_NAMELENGTH - 1] = '\0'; // null terminate + } + + NS_ASSERTION(*mRTLKeyboard, "mLTRKeyboard has string length == 0"); + NS_ASSERTION(*mLTRKeyboard, "mLTRKeyboard has string length == 0"); + + return NS_OK; +} + +// Test whether the language represented by this locale identifier is a +// right-to-left language, using bit 123 of the Unicode subset bitfield in +// the LOCALESIGNATURE +// See +// http://msdn.microsoft.com/library/default.asp?url=/library/en-us/intl/unicode_63ub.asp +bool nsBidiKeyboard::IsRTLLanguage(HKL aLocale) { + LOCALESIGNATURE localesig; + return (::GetLocaleInfoW(PRIMARYLANGID((DWORD_PTR)aLocale), + LOCALE_FONTSIGNATURE, (LPWSTR)&localesig, + (sizeof(localesig) / sizeof(WCHAR))) && + (localesig.lsUsb[3] & 0x08000000)); +} + +// static +void nsBidiKeyboard::OnLayoutChange() { + mozilla::widget::WidgetUtils::SendBidiKeyboardInfoToContent(); +} + +// static +already_AddRefed<nsIBidiKeyboard> nsIWidget::CreateBidiKeyboardInner() { + return do_AddRef(new nsBidiKeyboard()); +} |