|
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ |
|
2 /* vim:expandtab:shiftwidth=4:tabstop=4: |
|
3 */ |
|
4 /* This Source Code Form is subject to the terms of the Mozilla Public |
|
5 * License, v. 2.0. If a copy of the MPL was not distributed with this |
|
6 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
|
7 |
|
8 #ifndef __nsGdkKeyUtils_h__ |
|
9 #define __nsGdkKeyUtils_h__ |
|
10 |
|
11 #include "nsTArray.h" |
|
12 #include "mozilla/EventForwards.h" |
|
13 |
|
14 #include <gdk/gdk.h> |
|
15 #include <X11/XKBlib.h> |
|
16 |
|
17 namespace mozilla { |
|
18 namespace widget { |
|
19 |
|
20 /** |
|
21 * KeymapWrapper is a wrapper class of GdkKeymap. GdkKeymap doesn't support |
|
22 * all our needs, therefore, we need to access lower level APIs. |
|
23 * But such code is usually complex and might be slow. Against such issues, |
|
24 * we should cache some information. |
|
25 * |
|
26 * This class provides only static methods. The methods is using internal |
|
27 * singleton instance which is initialized by default GdkKeymap. When the |
|
28 * GdkKeymap is destroyed, the singleton instance will be destroyed. |
|
29 */ |
|
30 |
|
31 class KeymapWrapper |
|
32 { |
|
33 public: |
|
34 /** |
|
35 * Compute an our DOM keycode from a GDK keyval. |
|
36 */ |
|
37 static uint32_t ComputeDOMKeyCode(const GdkEventKey* aGdkKeyEvent); |
|
38 |
|
39 /** |
|
40 * Compute a DOM key name index from aGdkKeyEvent. |
|
41 */ |
|
42 KeyNameIndex ComputeDOMKeyNameIndex(const GdkEventKey* aGdkKeyEvent); |
|
43 |
|
44 /** |
|
45 * Modifier is list of modifiers which we support in widget level. |
|
46 */ |
|
47 enum Modifier { |
|
48 NOT_MODIFIER = 0x0000, |
|
49 CAPS_LOCK = 0x0001, |
|
50 NUM_LOCK = 0x0002, |
|
51 SCROLL_LOCK = 0x0004, |
|
52 SHIFT = 0x0008, |
|
53 CTRL = 0x0010, |
|
54 ALT = 0x0020, |
|
55 META = 0x0040, |
|
56 SUPER = 0x0080, |
|
57 HYPER = 0x0100, |
|
58 LEVEL3 = 0x0200, |
|
59 LEVEL5 = 0x0400 |
|
60 }; |
|
61 |
|
62 /** |
|
63 * Modifiers is used for combination of Modifier. |
|
64 * E.g., |Modifiers modifiers = (SHIFT | CTRL);| means Shift and Ctrl. |
|
65 */ |
|
66 typedef uint32_t Modifiers; |
|
67 |
|
68 /** |
|
69 * GetCurrentModifierState() returns current modifier key state. |
|
70 * The "current" means actual state of hardware keyboard when this is |
|
71 * called. I.e., if some key events are not still dispatched by GDK, |
|
72 * the state may mismatch with GdkEventKey::state. |
|
73 * |
|
74 * @return Current modifier key state. |
|
75 */ |
|
76 static guint GetCurrentModifierState(); |
|
77 |
|
78 /** |
|
79 * AreModifiersCurrentlyActive() checks the "current" modifier state |
|
80 * on aGdkWindow with the keymap of the singleton instance. |
|
81 * |
|
82 * @param aModifiers One or more of Modifier values except |
|
83 * NOT_MODIFIER. |
|
84 * @return TRUE if all of modifieres in aModifiers are |
|
85 * active. Otherwise, FALSE. |
|
86 */ |
|
87 static bool AreModifiersCurrentlyActive(Modifiers aModifiers); |
|
88 |
|
89 /** |
|
90 * AreModifiersActive() just checks whether aModifierState indicates |
|
91 * all modifiers in aModifiers are active or not. |
|
92 * |
|
93 * @param aModifiers One or more of Modifier values except |
|
94 * NOT_MODIFIER. |
|
95 * @param aModifierState GDK's modifier states. |
|
96 * @return TRUE if aGdkModifierType indecates all of |
|
97 * modifiers in aModifier are active. |
|
98 * Otherwise, FALSE. |
|
99 */ |
|
100 static bool AreModifiersActive(Modifiers aModifiers, |
|
101 guint aModifierState); |
|
102 |
|
103 /** |
|
104 * InitInputEvent() initializes the aInputEvent with aModifierState. |
|
105 */ |
|
106 static void InitInputEvent(WidgetInputEvent& aInputEvent, |
|
107 guint aModifierState); |
|
108 |
|
109 /** |
|
110 * InitKeyEvent() intializes aKeyEvent's modifier key related members |
|
111 * and keycode related values. |
|
112 * |
|
113 * @param aKeyEvent It's an WidgetKeyboardEvent which needs to be |
|
114 * initialized. |
|
115 * @param aGdkKeyEvent A native GDK key event. |
|
116 */ |
|
117 static void InitKeyEvent(WidgetKeyboardEvent& aKeyEvent, |
|
118 GdkEventKey* aGdkKeyEvent); |
|
119 |
|
120 /** |
|
121 * IsKeyPressEventNecessary() returns TRUE when aGdkKeyEvent should cause |
|
122 * a DOM keypress event. Otherwise, FALSE. |
|
123 */ |
|
124 static bool IsKeyPressEventNecessary(GdkEventKey* aGdkKeyEvent); |
|
125 |
|
126 protected: |
|
127 |
|
128 /** |
|
129 * GetInstance() returns a KeymapWrapper instance. |
|
130 * |
|
131 * @return A singleton instance of KeymapWrapper. |
|
132 */ |
|
133 static KeymapWrapper* GetInstance(); |
|
134 |
|
135 KeymapWrapper(); |
|
136 ~KeymapWrapper(); |
|
137 |
|
138 bool mInitialized; |
|
139 |
|
140 /** |
|
141 * Initializing methods. |
|
142 */ |
|
143 void Init(); |
|
144 void InitXKBExtension(); |
|
145 void InitBySystemSettings(); |
|
146 |
|
147 /** |
|
148 * mModifierKeys stores each hardware key information. |
|
149 */ |
|
150 struct ModifierKey { |
|
151 guint mHardwareKeycode; |
|
152 guint mMask; |
|
153 |
|
154 ModifierKey(guint aHardwareKeycode) : |
|
155 mHardwareKeycode(aHardwareKeycode), mMask(0) |
|
156 { |
|
157 } |
|
158 }; |
|
159 nsTArray<ModifierKey> mModifierKeys; |
|
160 |
|
161 /** |
|
162 * GetModifierKey() returns modifier key information of the hardware |
|
163 * keycode. If the key isn't a modifier key, returns nullptr. |
|
164 */ |
|
165 ModifierKey* GetModifierKey(guint aHardwareKeycode); |
|
166 |
|
167 /** |
|
168 * mModifierMasks is bit masks for each modifier. The index should be one |
|
169 * of ModifierIndex values. |
|
170 */ |
|
171 enum ModifierIndex { |
|
172 INDEX_NUM_LOCK, |
|
173 INDEX_SCROLL_LOCK, |
|
174 INDEX_ALT, |
|
175 INDEX_META, |
|
176 INDEX_SUPER, |
|
177 INDEX_HYPER, |
|
178 INDEX_LEVEL3, |
|
179 INDEX_LEVEL5, |
|
180 COUNT_OF_MODIFIER_INDEX |
|
181 }; |
|
182 guint mModifierMasks[COUNT_OF_MODIFIER_INDEX]; |
|
183 |
|
184 guint GetModifierMask(Modifier aModifier) const; |
|
185 |
|
186 /** |
|
187 * @param aGdkKeyval A GDK defined modifier key value such as |
|
188 * GDK_Shift_L. |
|
189 * @return Returns Modifier values for aGdkKeyval. |
|
190 * If the given key code isn't a modifier key, |
|
191 * returns NOT_MODIFIER. |
|
192 */ |
|
193 static Modifier GetModifierForGDKKeyval(guint aGdkKeyval); |
|
194 |
|
195 #ifdef PR_LOGGING |
|
196 static const char* GetModifierName(Modifier aModifier); |
|
197 #endif // PR_LOGGING |
|
198 |
|
199 /** |
|
200 * mGdkKeymap is a wrapped instance by this class. |
|
201 */ |
|
202 GdkKeymap* mGdkKeymap; |
|
203 |
|
204 /** |
|
205 * The base event code of XKB extension. |
|
206 */ |
|
207 int mXKBBaseEventCode; |
|
208 |
|
209 /** |
|
210 * Only auto_repeats[] stores valid value. If you need to use other |
|
211 * members, you need to listen notification events for them. |
|
212 * See a call of XkbSelectEventDetails() with XkbControlsNotify in |
|
213 * InitXKBExtension(). |
|
214 */ |
|
215 XKeyboardState mKeyboardState; |
|
216 |
|
217 /** |
|
218 * Pointer of the singleton instance. |
|
219 */ |
|
220 static KeymapWrapper* sInstance; |
|
221 |
|
222 /** |
|
223 * Auto key repeat management. |
|
224 */ |
|
225 static guint sLastRepeatableHardwareKeyCode; |
|
226 enum RepeatState |
|
227 { |
|
228 NOT_PRESSED, |
|
229 FIRST_PRESS, |
|
230 REPEATING |
|
231 }; |
|
232 static RepeatState sRepeatState; |
|
233 |
|
234 /** |
|
235 * IsAutoRepeatableKey() returns true if the key supports auto repeat. |
|
236 * Otherwise, false. |
|
237 */ |
|
238 bool IsAutoRepeatableKey(guint aHardwareKeyCode); |
|
239 |
|
240 /** |
|
241 * Signal handlers. |
|
242 */ |
|
243 static void OnKeysChanged(GdkKeymap* aKeymap, KeymapWrapper* aKeymapWrapper); |
|
244 static void OnDestroyKeymap(KeymapWrapper* aKeymapWrapper, |
|
245 GdkKeymap *aGdkKeymap); |
|
246 |
|
247 /** |
|
248 * GetCharCodeFor() Computes what character is inputted by the key event |
|
249 * with aModifierState and aGroup. |
|
250 * |
|
251 * @param aGdkKeyEvent Native key event, must not be nullptr. |
|
252 * @param aModifierState Combination of GdkModifierType which you |
|
253 * want to test with aGdkKeyEvent. |
|
254 * @param aGroup Set group in the mGdkKeymap. |
|
255 * @return charCode which is inputted by aGdkKeyEvent. |
|
256 * If failed, this returns 0. |
|
257 */ |
|
258 static uint32_t GetCharCodeFor(const GdkEventKey *aGdkKeyEvent); |
|
259 uint32_t GetCharCodeFor(const GdkEventKey *aGdkKeyEvent, |
|
260 guint aModifierState, |
|
261 gint aGroup); |
|
262 |
|
263 /** |
|
264 * GetUnmodifiedCharCodeFor() computes what character is inputted by the |
|
265 * key event without Ctrl/Alt/Meta/Super/Hyper modifiers. |
|
266 * If Level3 or Level5 Shift causes no character input, this also ignores |
|
267 * them. |
|
268 * |
|
269 * @param aGdkKeyEvent Native key event, must not be nullptr. |
|
270 * @return charCode which is computed without modifiers |
|
271 * which prevent text input. |
|
272 */ |
|
273 uint32_t GetUnmodifiedCharCodeFor(const GdkEventKey* aGdkKeyEvent); |
|
274 |
|
275 /** |
|
276 * GetKeyLevel() returns level of the aGdkKeyEvent in mGdkKeymap. |
|
277 * |
|
278 * @param aGdkKeyEvent Native key event, must not be nullptr. |
|
279 * @return Using level. Typically, this is 0 or 1. |
|
280 * If failed, this returns -1. |
|
281 */ |
|
282 gint GetKeyLevel(GdkEventKey *aGdkKeyEvent); |
|
283 |
|
284 /** |
|
285 * GetFirstLatinGroup() returns group of mGdkKeymap which can input an |
|
286 * ASCII character by GDK_A. |
|
287 * |
|
288 * @return group value of GdkEventKey. |
|
289 */ |
|
290 gint GetFirstLatinGroup(); |
|
291 |
|
292 /** |
|
293 * IsLatinGroup() checkes whether the keyboard layout of aGroup is |
|
294 * ASCII alphabet inputtable or not. |
|
295 * |
|
296 * @param aGroup The group value of GdkEventKey. |
|
297 * @return TRUE if the keyboard layout can input |
|
298 * ASCII alphabet. Otherwise, FALSE. |
|
299 */ |
|
300 bool IsLatinGroup(guint8 aGroup); |
|
301 |
|
302 /** |
|
303 * IsBasicLatinLetterOrNumeral() Checks whether the aCharCode is an |
|
304 * alphabet or a numeric character in ASCII. |
|
305 * |
|
306 * @param aCharCode Charcode which you want to test. |
|
307 * @return TRUE if aCharCode is an alphabet or a numeric |
|
308 * in ASCII range. Otherwise, FALSE. |
|
309 */ |
|
310 static bool IsBasicLatinLetterOrNumeral(uint32_t aCharCode); |
|
311 |
|
312 /** |
|
313 * GetGDKKeyvalWithoutModifier() returns the keyval for aGdkKeyEvent when |
|
314 * ignoring the modifier state except NumLock. (NumLock is a key to change |
|
315 * some key's meaning.) |
|
316 */ |
|
317 static guint GetGDKKeyvalWithoutModifier(const GdkEventKey *aGdkKeyEvent); |
|
318 |
|
319 /** |
|
320 * GetDOMKeyCodeFromKeyPairs() returns DOM keycode for aGdkKeyval if |
|
321 * it's in KeyPair table. |
|
322 */ |
|
323 static uint32_t GetDOMKeyCodeFromKeyPairs(guint aGdkKeyval); |
|
324 |
|
325 /** |
|
326 * InitKeypressEvent() intializes keyCode, charCode and |
|
327 * alternativeCharCodes of keypress event. |
|
328 * |
|
329 * @param aKeyEvent An NS_KEY_PRESS event, must not be nullptr. |
|
330 * The modifier related members and keyCode must |
|
331 * be initialized already. |
|
332 * @param aGdkKeyEvent A native key event which causes dispatching |
|
333 * aKeyEvent. |
|
334 */ |
|
335 void InitKeypressEvent(WidgetKeyboardEvent& aKeyEvent, |
|
336 GdkEventKey* aGdkKeyEvent); |
|
337 |
|
338 /** |
|
339 * FilterEvents() listens all events on all our windows. |
|
340 * Be careful, this may make damage to performance if you add expensive |
|
341 * code in this method. |
|
342 */ |
|
343 static GdkFilterReturn FilterEvents(GdkXEvent* aXEvent, |
|
344 GdkEvent* aGdkEvent, |
|
345 gpointer aData); |
|
346 }; |
|
347 |
|
348 } // namespace widget |
|
349 } // namespace mozilla |
|
350 |
|
351 #endif /* __nsGdkKeyUtils_h__ */ |