Bumping manifests a=b2g-bump
[gecko.git] / widget / windows / nsBidiKeyboard.cpp
blobbb8407b553e921a61eb149293c610d73f14c27b0
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
3 * This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #include <stdio.h>
8 #include "nsBidiKeyboard.h"
9 #include "prmem.h"
10 #include <tchar.h>
12 NS_IMPL_ISUPPORTS(nsBidiKeyboard, nsIBidiKeyboard)
14 nsBidiKeyboard::nsBidiKeyboard() : nsIBidiKeyboard()
16 Reset();
19 nsBidiKeyboard::~nsBidiKeyboard()
23 NS_IMETHODIMP nsBidiKeyboard::Reset()
25 mInitialized = false;
26 mHaveBidiKeyboards = false;
27 mLTRKeyboard[0] = '\0';
28 mRTLKeyboard[0] = '\0';
29 mCurrentLocaleName[0] = '\0';
30 return NS_OK;
33 NS_IMETHODIMP nsBidiKeyboard::IsLangRTL(bool *aIsRTL)
35 *aIsRTL = false;
37 nsresult result = SetupBidiKeyboards();
38 if (NS_FAILED(result))
39 return result;
41 HKL currentLocale;
43 currentLocale = ::GetKeyboardLayout(0);
44 *aIsRTL = IsRTLLanguage(currentLocale);
46 if (!::GetKeyboardLayoutNameW(mCurrentLocaleName))
47 return NS_ERROR_FAILURE;
49 NS_ASSERTION(*mCurrentLocaleName,
50 "GetKeyboardLayoutName return string length == 0");
51 NS_ASSERTION((wcslen(mCurrentLocaleName) < KL_NAMELENGTH),
52 "GetKeyboardLayoutName return string length >= KL_NAMELENGTH");
54 // The language set by the user overrides the default language for that direction
55 if (*aIsRTL) {
56 wcsncpy(mRTLKeyboard, mCurrentLocaleName, KL_NAMELENGTH);
57 mRTLKeyboard[KL_NAMELENGTH-1] = '\0'; // null terminate
58 } else {
59 wcsncpy(mLTRKeyboard, mCurrentLocaleName, KL_NAMELENGTH);
60 mLTRKeyboard[KL_NAMELENGTH-1] = '\0'; // null terminate
63 NS_ASSERTION((wcslen(mRTLKeyboard) < KL_NAMELENGTH),
64 "mLTRKeyboard has string length >= KL_NAMELENGTH");
65 NS_ASSERTION((wcslen(mLTRKeyboard) < KL_NAMELENGTH),
66 "mRTLKeyboard has string length >= KL_NAMELENGTH");
67 return NS_OK;
70 NS_IMETHODIMP nsBidiKeyboard::GetHaveBidiKeyboards(bool* aResult)
72 NS_ENSURE_ARG_POINTER(aResult);
74 nsresult result = SetupBidiKeyboards();
75 if (NS_FAILED(result))
76 return result;
78 *aResult = mHaveBidiKeyboards;
79 return NS_OK;
83 // Get the list of keyboard layouts available in the system
84 // Set mLTRKeyboard to the first LTR keyboard in the list and mRTLKeyboard to the first RTL keyboard in the list
85 // These defaults will be used unless the user explicitly sets something else.
86 nsresult nsBidiKeyboard::SetupBidiKeyboards()
88 if (mInitialized)
89 return mHaveBidiKeyboards ? NS_OK : NS_ERROR_FAILURE;
91 int keyboards;
92 HKL far* buf;
93 HKL locale;
94 wchar_t localeName[KL_NAMELENGTH];
95 bool isLTRKeyboardSet = false;
96 bool isRTLKeyboardSet = false;
98 // GetKeyboardLayoutList with 0 as first parameter returns the number of keyboard layouts available
99 keyboards = ::GetKeyboardLayoutList(0, nullptr);
100 if (!keyboards)
101 return NS_ERROR_FAILURE;
103 // allocate a buffer to hold the list
104 buf = (HKL far*) PR_Malloc(keyboards * sizeof(HKL));
105 if (!buf)
106 return NS_ERROR_OUT_OF_MEMORY;
108 // Call again to fill the buffer
109 if (::GetKeyboardLayoutList(keyboards, buf) != keyboards) {
110 PR_Free(buf);
111 return NS_ERROR_UNEXPECTED;
114 // Go through the list and pick a default LTR and RTL keyboard layout
115 while (keyboards--) {
116 locale = buf[keyboards];
117 if (IsRTLLanguage(locale)) {
118 _snwprintf(mRTLKeyboard, KL_NAMELENGTH, L"%.*x", KL_NAMELENGTH - 1,
119 LANGIDFROMLCID((DWORD_PTR)locale));
120 isRTLKeyboardSet = true;
122 else {
123 _snwprintf(mLTRKeyboard, KL_NAMELENGTH, L"%.*x", KL_NAMELENGTH - 1,
124 LANGIDFROMLCID((DWORD_PTR)locale));
125 isLTRKeyboardSet = true;
128 PR_Free(buf);
129 mInitialized = true;
131 // If there is not at least one keyboard of each directionality, Bidi
132 // keyboard functionality will be disabled.
133 mHaveBidiKeyboards = (isRTLKeyboardSet && isLTRKeyboardSet);
134 if (!mHaveBidiKeyboards)
135 return NS_ERROR_FAILURE;
137 // Get the current keyboard layout and use it for either mRTLKeyboard or
138 // mLTRKeyboard as appropriate. If the user has many keyboard layouts
139 // installed this prevents us from arbitrarily resetting the current
140 // layout (bug 80274)
141 locale = ::GetKeyboardLayout(0);
142 if (!::GetKeyboardLayoutNameW(localeName))
143 return NS_ERROR_FAILURE;
145 NS_ASSERTION(*localeName,
146 "GetKeyboardLayoutName return string length == 0");
147 NS_ASSERTION((wcslen(localeName) < KL_NAMELENGTH),
148 "GetKeyboardLayout return string length >= KL_NAMELENGTH");
150 if (IsRTLLanguage(locale)) {
151 wcsncpy(mRTLKeyboard, localeName, KL_NAMELENGTH);
152 mRTLKeyboard[KL_NAMELENGTH-1] = '\0'; // null terminate
154 else {
155 wcsncpy(mLTRKeyboard, localeName, KL_NAMELENGTH);
156 mLTRKeyboard[KL_NAMELENGTH-1] = '\0'; // null terminate
159 NS_ASSERTION(*mRTLKeyboard,
160 "mLTRKeyboard has string length == 0");
161 NS_ASSERTION(*mLTRKeyboard,
162 "mLTRKeyboard has string length == 0");
164 return NS_OK;
167 // Test whether the language represented by this locale identifier is a
168 // right-to-left language, using bit 123 of the Unicode subset bitfield in
169 // the LOCALESIGNATURE
170 // See http://msdn.microsoft.com/library/default.asp?url=/library/en-us/intl/unicode_63ub.asp
171 bool nsBidiKeyboard::IsRTLLanguage(HKL aLocale)
173 LOCALESIGNATURE localesig;
174 return (::GetLocaleInfoW(PRIMARYLANGID((DWORD_PTR)aLocale),
175 LOCALE_FONTSIGNATURE,
176 (LPWSTR)&localesig,
177 (sizeof(localesig)/sizeof(WCHAR))) &&
178 (localesig.lsUsb[3] & 0x08000000));