|
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- |
|
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/. */ |
|
6 |
|
7 #include <stdio.h> |
|
8 #include "nsBidiKeyboard.h" |
|
9 #include "prmem.h" |
|
10 #include <tchar.h> |
|
11 |
|
12 NS_IMPL_ISUPPORTS(nsBidiKeyboard, nsIBidiKeyboard) |
|
13 |
|
14 nsBidiKeyboard::nsBidiKeyboard() : nsIBidiKeyboard() |
|
15 { |
|
16 Reset(); |
|
17 } |
|
18 |
|
19 nsBidiKeyboard::~nsBidiKeyboard() |
|
20 { |
|
21 } |
|
22 |
|
23 NS_IMETHODIMP nsBidiKeyboard::Reset() |
|
24 { |
|
25 mInitialized = false; |
|
26 mHaveBidiKeyboards = false; |
|
27 mLTRKeyboard[0] = '\0'; |
|
28 mRTLKeyboard[0] = '\0'; |
|
29 mCurrentLocaleName[0] = '\0'; |
|
30 return NS_OK; |
|
31 } |
|
32 |
|
33 NS_IMETHODIMP nsBidiKeyboard::IsLangRTL(bool *aIsRTL) |
|
34 { |
|
35 *aIsRTL = false; |
|
36 |
|
37 nsresult result = SetupBidiKeyboards(); |
|
38 if (NS_FAILED(result)) |
|
39 return result; |
|
40 |
|
41 HKL currentLocale; |
|
42 |
|
43 currentLocale = ::GetKeyboardLayout(0); |
|
44 *aIsRTL = IsRTLLanguage(currentLocale); |
|
45 |
|
46 if (!::GetKeyboardLayoutNameW(mCurrentLocaleName)) |
|
47 return NS_ERROR_FAILURE; |
|
48 |
|
49 NS_ASSERTION(*mCurrentLocaleName, |
|
50 "GetKeyboardLayoutName return string length == 0"); |
|
51 NS_ASSERTION((wcslen(mCurrentLocaleName) < KL_NAMELENGTH), |
|
52 "GetKeyboardLayoutName return string length >= KL_NAMELENGTH"); |
|
53 |
|
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 |
|
61 } |
|
62 |
|
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; |
|
68 } |
|
69 |
|
70 NS_IMETHODIMP nsBidiKeyboard::GetHaveBidiKeyboards(bool* aResult) |
|
71 { |
|
72 NS_ENSURE_ARG_POINTER(aResult); |
|
73 |
|
74 nsresult result = SetupBidiKeyboards(); |
|
75 if (NS_FAILED(result)) |
|
76 return result; |
|
77 |
|
78 *aResult = mHaveBidiKeyboards; |
|
79 return NS_OK; |
|
80 } |
|
81 |
|
82 |
|
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() |
|
87 { |
|
88 if (mInitialized) |
|
89 return mHaveBidiKeyboards ? NS_OK : NS_ERROR_FAILURE; |
|
90 |
|
91 int keyboards; |
|
92 HKL far* buf; |
|
93 HKL locale; |
|
94 wchar_t localeName[KL_NAMELENGTH]; |
|
95 bool isLTRKeyboardSet = false; |
|
96 bool isRTLKeyboardSet = false; |
|
97 |
|
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; |
|
102 |
|
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; |
|
107 |
|
108 // Call again to fill the buffer |
|
109 if (::GetKeyboardLayoutList(keyboards, buf) != keyboards) { |
|
110 PR_Free(buf); |
|
111 return NS_ERROR_UNEXPECTED; |
|
112 } |
|
113 |
|
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; |
|
121 } |
|
122 else { |
|
123 _snwprintf(mLTRKeyboard, KL_NAMELENGTH, L"%.*x", KL_NAMELENGTH - 1, |
|
124 LANGIDFROMLCID((DWORD_PTR)locale)); |
|
125 isLTRKeyboardSet = true; |
|
126 } |
|
127 } |
|
128 PR_Free(buf); |
|
129 mInitialized = true; |
|
130 |
|
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; |
|
136 |
|
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; |
|
144 |
|
145 NS_ASSERTION(*localeName, |
|
146 "GetKeyboardLayoutName return string length == 0"); |
|
147 NS_ASSERTION((wcslen(localeName) < KL_NAMELENGTH), |
|
148 "GetKeyboardLayout return string length >= KL_NAMELENGTH"); |
|
149 |
|
150 if (IsRTLLanguage(locale)) { |
|
151 wcsncpy(mRTLKeyboard, localeName, KL_NAMELENGTH); |
|
152 mRTLKeyboard[KL_NAMELENGTH-1] = '\0'; // null terminate |
|
153 } |
|
154 else { |
|
155 wcsncpy(mLTRKeyboard, localeName, KL_NAMELENGTH); |
|
156 mLTRKeyboard[KL_NAMELENGTH-1] = '\0'; // null terminate |
|
157 } |
|
158 |
|
159 NS_ASSERTION(*mRTLKeyboard, |
|
160 "mLTRKeyboard has string length == 0"); |
|
161 NS_ASSERTION(*mLTRKeyboard, |
|
162 "mLTRKeyboard has string length == 0"); |
|
163 |
|
164 return NS_OK; |
|
165 } |
|
166 |
|
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) |
|
172 { |
|
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)); |
|
179 } |