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