/src/mozilla-central/widget/gtk/nsGtkKeyUtils.h
Line | Count | Source (jump to first uncovered line) |
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 | | #ifdef MOZ_WAYLAND |
17 | | #include <gdk/gdkwayland.h> |
18 | | #include <xkbcommon/xkbcommon.h> |
19 | | #endif |
20 | | |
21 | | namespace mozilla { |
22 | | namespace widget { |
23 | | |
24 | | /** |
25 | | * KeymapWrapper is a wrapper class of GdkKeymap. GdkKeymap doesn't support |
26 | | * all our needs, therefore, we need to access lower level APIs. |
27 | | * But such code is usually complex and might be slow. Against such issues, |
28 | | * we should cache some information. |
29 | | * |
30 | | * This class provides only static methods. The methods is using internal |
31 | | * singleton instance which is initialized by default GdkKeymap. When the |
32 | | * GdkKeymap is destroyed, the singleton instance will be destroyed. |
33 | | */ |
34 | | |
35 | | class KeymapWrapper |
36 | | { |
37 | | public: |
38 | | /** |
39 | | * Compute an our DOM keycode from a GDK keyval. |
40 | | */ |
41 | | static uint32_t ComputeDOMKeyCode(const GdkEventKey* aGdkKeyEvent); |
42 | | |
43 | | /** |
44 | | * Compute a DOM key name index from aGdkKeyEvent. |
45 | | */ |
46 | | static KeyNameIndex ComputeDOMKeyNameIndex(const GdkEventKey* aGdkKeyEvent); |
47 | | |
48 | | /** |
49 | | * Compute a DOM code name index from aGdkKeyEvent. |
50 | | */ |
51 | | static CodeNameIndex ComputeDOMCodeNameIndex( |
52 | | const GdkEventKey* aGdkKeyEvent); |
53 | | |
54 | | /** |
55 | | * Modifier is list of modifiers which we support in widget level. |
56 | | */ |
57 | | enum Modifier { |
58 | | NOT_MODIFIER = 0x0000, |
59 | | CAPS_LOCK = 0x0001, |
60 | | NUM_LOCK = 0x0002, |
61 | | SCROLL_LOCK = 0x0004, |
62 | | SHIFT = 0x0008, |
63 | | CTRL = 0x0010, |
64 | | ALT = 0x0020, |
65 | | META = 0x0040, |
66 | | SUPER = 0x0080, |
67 | | HYPER = 0x0100, |
68 | | LEVEL3 = 0x0200, |
69 | | LEVEL5 = 0x0400 |
70 | | }; |
71 | | |
72 | | /** |
73 | | * Modifiers is used for combination of Modifier. |
74 | | * E.g., |Modifiers modifiers = (SHIFT | CTRL);| means Shift and Ctrl. |
75 | | */ |
76 | | typedef uint32_t Modifiers; |
77 | | |
78 | | /** |
79 | | * GetCurrentModifierState() returns current modifier key state. |
80 | | * The "current" means actual state of hardware keyboard when this is |
81 | | * called. I.e., if some key events are not still dispatched by GDK, |
82 | | * the state may mismatch with GdkEventKey::state. |
83 | | * |
84 | | * @return Current modifier key state. |
85 | | */ |
86 | | static guint GetCurrentModifierState(); |
87 | | |
88 | | /** |
89 | | * AreModifiersCurrentlyActive() checks the "current" modifier state |
90 | | * on aGdkWindow with the keymap of the singleton instance. |
91 | | * |
92 | | * @param aModifiers One or more of Modifier values except |
93 | | * NOT_MODIFIER. |
94 | | * @return TRUE if all of modifieres in aModifiers are |
95 | | * active. Otherwise, FALSE. |
96 | | */ |
97 | | static bool AreModifiersCurrentlyActive(Modifiers aModifiers); |
98 | | |
99 | | /** |
100 | | * AreModifiersActive() just checks whether aModifierState indicates |
101 | | * all modifiers in aModifiers are active or not. |
102 | | * |
103 | | * @param aModifiers One or more of Modifier values except |
104 | | * NOT_MODIFIER. |
105 | | * @param aModifierState GDK's modifier states. |
106 | | * @return TRUE if aGdkModifierType indecates all of |
107 | | * modifiers in aModifier are active. |
108 | | * Otherwise, FALSE. |
109 | | */ |
110 | | static bool AreModifiersActive(Modifiers aModifiers, |
111 | | guint aModifierState); |
112 | | |
113 | | /** |
114 | | * Utility function to compute current keyboard modifiers for |
115 | | * WidgetInputEvent |
116 | | */ |
117 | | static uint32_t ComputeCurrentKeyModifiers(); |
118 | | |
119 | | /** |
120 | | * Utility function to covert platform modifier state to keyboard modifiers |
121 | | * of WidgetInputEvent |
122 | | */ |
123 | | static uint32_t ComputeKeyModifiers(guint aModifierState); |
124 | | |
125 | | /** |
126 | | * InitInputEvent() initializes the aInputEvent with aModifierState. |
127 | | */ |
128 | | static void InitInputEvent(WidgetInputEvent& aInputEvent, |
129 | | guint aModifierState); |
130 | | |
131 | | /** |
132 | | * InitKeyEvent() intializes aKeyEvent's modifier key related members |
133 | | * and keycode related values. |
134 | | * |
135 | | * @param aKeyEvent It's an WidgetKeyboardEvent which needs to be |
136 | | * initialized. |
137 | | * @param aGdkKeyEvent A native GDK key event. |
138 | | * @param aIsProcessedByIME true if aGdkKeyEvent is handled by IME. |
139 | | */ |
140 | | static void InitKeyEvent(WidgetKeyboardEvent& aKeyEvent, |
141 | | GdkEventKey* aGdkKeyEvent, |
142 | | bool aIsProcessedByIME); |
143 | | |
144 | | /** |
145 | | * WillDispatchKeyboardEvent() is called via |
146 | | * TextEventDispatcherListener::WillDispatchKeyboardEvent(). |
147 | | * |
148 | | * @param aKeyEvent An instance of KeyboardEvent which will be |
149 | | * dispatched. This method should set charCode |
150 | | * and alternative char codes if it's necessary. |
151 | | * @param aGdkKeyEvent A GdkEventKey instance which caused the |
152 | | * aKeyEvent. |
153 | | */ |
154 | | static void WillDispatchKeyboardEvent(WidgetKeyboardEvent& aKeyEvent, |
155 | | GdkEventKey* aGdkKeyEvent); |
156 | | |
157 | | #ifdef MOZ_WAYLAND |
158 | | /** |
159 | | * Utility function to set all supported modifier masks |
160 | | * from xkb_keymap. We call that from Wayland backend routines. |
161 | | */ |
162 | | static void SetModifierMasks(xkb_keymap *aKeymap); |
163 | | #endif |
164 | | |
165 | | /** |
166 | | * Destroys the singleton KeymapWrapper instance, if it exists. |
167 | | */ |
168 | | static void Shutdown(); |
169 | | |
170 | | protected: |
171 | | |
172 | | /** |
173 | | * GetInstance() returns a KeymapWrapper instance. |
174 | | * |
175 | | * @return A singleton instance of KeymapWrapper. |
176 | | */ |
177 | | static KeymapWrapper* GetInstance(); |
178 | | |
179 | | KeymapWrapper(); |
180 | | ~KeymapWrapper(); |
181 | | |
182 | | bool mInitialized; |
183 | | |
184 | | /** |
185 | | * Initializing methods. |
186 | | */ |
187 | | void Init(); |
188 | | void InitXKBExtension(); |
189 | | void InitBySystemSettingsX11(); |
190 | | #ifdef MOZ_WAYLAND |
191 | | void InitBySystemSettingsWayland(); |
192 | | #endif |
193 | | |
194 | | /** |
195 | | * mModifierKeys stores each hardware key information. |
196 | | */ |
197 | | struct ModifierKey { |
198 | | guint mHardwareKeycode; |
199 | | guint mMask; |
200 | | |
201 | | explicit ModifierKey(guint aHardwareKeycode) : |
202 | | mHardwareKeycode(aHardwareKeycode), mMask(0) |
203 | 0 | { |
204 | 0 | } |
205 | | }; |
206 | | nsTArray<ModifierKey> mModifierKeys; |
207 | | |
208 | | /** |
209 | | * GetModifierKey() returns modifier key information of the hardware |
210 | | * keycode. If the key isn't a modifier key, returns nullptr. |
211 | | */ |
212 | | ModifierKey* GetModifierKey(guint aHardwareKeycode); |
213 | | |
214 | | /** |
215 | | * mModifierMasks is bit masks for each modifier. The index should be one |
216 | | * of ModifierIndex values. |
217 | | */ |
218 | | enum ModifierIndex { |
219 | | INDEX_NUM_LOCK, |
220 | | INDEX_SCROLL_LOCK, |
221 | | INDEX_ALT, |
222 | | INDEX_META, |
223 | | INDEX_SUPER, |
224 | | INDEX_HYPER, |
225 | | INDEX_LEVEL3, |
226 | | INDEX_LEVEL5, |
227 | | COUNT_OF_MODIFIER_INDEX |
228 | | }; |
229 | | guint mModifierMasks[COUNT_OF_MODIFIER_INDEX]; |
230 | | |
231 | | guint GetModifierMask(Modifier aModifier) const; |
232 | | |
233 | | /** |
234 | | * @param aGdkKeyval A GDK defined modifier key value such as |
235 | | * GDK_Shift_L. |
236 | | * @return Returns Modifier values for aGdkKeyval. |
237 | | * If the given key code isn't a modifier key, |
238 | | * returns NOT_MODIFIER. |
239 | | */ |
240 | | static Modifier GetModifierForGDKKeyval(guint aGdkKeyval); |
241 | | |
242 | | static const char* GetModifierName(Modifier aModifier); |
243 | | |
244 | | /** |
245 | | * mGdkKeymap is a wrapped instance by this class. |
246 | | */ |
247 | | GdkKeymap* mGdkKeymap; |
248 | | |
249 | | /** |
250 | | * The base event code of XKB extension. |
251 | | */ |
252 | | int mXKBBaseEventCode; |
253 | | |
254 | | /** |
255 | | * Only auto_repeats[] stores valid value. If you need to use other |
256 | | * members, you need to listen notification events for them. |
257 | | * See a call of XkbSelectEventDetails() with XkbControlsNotify in |
258 | | * InitXKBExtension(). |
259 | | */ |
260 | | XKeyboardState mKeyboardState; |
261 | | |
262 | | /** |
263 | | * Pointer of the singleton instance. |
264 | | */ |
265 | | static KeymapWrapper* sInstance; |
266 | | |
267 | | /** |
268 | | * Auto key repeat management. |
269 | | */ |
270 | | static guint sLastRepeatableHardwareKeyCode; |
271 | | enum RepeatState |
272 | | { |
273 | | NOT_PRESSED, |
274 | | FIRST_PRESS, |
275 | | REPEATING |
276 | | }; |
277 | | static RepeatState sRepeatState; |
278 | | |
279 | | /** |
280 | | * IsAutoRepeatableKey() returns true if the key supports auto repeat. |
281 | | * Otherwise, false. |
282 | | */ |
283 | | bool IsAutoRepeatableKey(guint aHardwareKeyCode); |
284 | | |
285 | | /** |
286 | | * Signal handlers. |
287 | | */ |
288 | | static void OnKeysChanged(GdkKeymap* aKeymap, KeymapWrapper* aKeymapWrapper); |
289 | | static void OnDirectionChanged(GdkKeymap *aGdkKeymap, |
290 | | KeymapWrapper* aKeymapWrapper); |
291 | | |
292 | | /** |
293 | | * GetCharCodeFor() Computes what character is inputted by the key event |
294 | | * with aModifierState and aGroup. |
295 | | * |
296 | | * @param aGdkKeyEvent Native key event, must not be nullptr. |
297 | | * @param aModifierState Combination of GdkModifierType which you |
298 | | * want to test with aGdkKeyEvent. |
299 | | * @param aGroup Set group in the mGdkKeymap. |
300 | | * @return charCode which is inputted by aGdkKeyEvent. |
301 | | * If failed, this returns 0. |
302 | | */ |
303 | | static uint32_t GetCharCodeFor(const GdkEventKey *aGdkKeyEvent); |
304 | | uint32_t GetCharCodeFor(const GdkEventKey *aGdkKeyEvent, |
305 | | guint aModifierState, |
306 | | gint aGroup); |
307 | | |
308 | | /** |
309 | | * GetUnmodifiedCharCodeFor() computes what character is inputted by the |
310 | | * key event without Ctrl/Alt/Meta/Super/Hyper modifiers. |
311 | | * If Level3 or Level5 Shift causes no character input, this also ignores |
312 | | * them. |
313 | | * |
314 | | * @param aGdkKeyEvent Native key event, must not be nullptr. |
315 | | * @return charCode which is computed without modifiers |
316 | | * which prevent text input. |
317 | | */ |
318 | | uint32_t GetUnmodifiedCharCodeFor(const GdkEventKey* aGdkKeyEvent); |
319 | | |
320 | | /** |
321 | | * GetKeyLevel() returns level of the aGdkKeyEvent in mGdkKeymap. |
322 | | * |
323 | | * @param aGdkKeyEvent Native key event, must not be nullptr. |
324 | | * @return Using level. Typically, this is 0 or 1. |
325 | | * If failed, this returns -1. |
326 | | */ |
327 | | gint GetKeyLevel(GdkEventKey *aGdkKeyEvent); |
328 | | |
329 | | /** |
330 | | * GetFirstLatinGroup() returns group of mGdkKeymap which can input an |
331 | | * ASCII character by GDK_A. |
332 | | * |
333 | | * @return group value of GdkEventKey. |
334 | | */ |
335 | | gint GetFirstLatinGroup(); |
336 | | |
337 | | /** |
338 | | * IsLatinGroup() checkes whether the keyboard layout of aGroup is |
339 | | * ASCII alphabet inputtable or not. |
340 | | * |
341 | | * @param aGroup The group value of GdkEventKey. |
342 | | * @return TRUE if the keyboard layout can input |
343 | | * ASCII alphabet. Otherwise, FALSE. |
344 | | */ |
345 | | bool IsLatinGroup(guint8 aGroup); |
346 | | |
347 | | /** |
348 | | * IsBasicLatinLetterOrNumeral() Checks whether the aCharCode is an |
349 | | * alphabet or a numeric character in ASCII. |
350 | | * |
351 | | * @param aCharCode Charcode which you want to test. |
352 | | * @return TRUE if aCharCode is an alphabet or a numeric |
353 | | * in ASCII range. Otherwise, FALSE. |
354 | | */ |
355 | | static bool IsBasicLatinLetterOrNumeral(uint32_t aCharCode); |
356 | | |
357 | | /** |
358 | | * IsPrintableASCIICharacter() checks whether the aCharCode is a printable |
359 | | * ASCII character. I.e., returns false if aCharCode is a control |
360 | | * character even in an ASCII character. |
361 | | */ |
362 | | static bool IsPrintableASCIICharacter(uint32_t aCharCode) |
363 | 0 | { |
364 | 0 | return aCharCode >= 0x20 && aCharCode <= 0x7E; |
365 | 0 | } |
366 | | |
367 | | /** |
368 | | * GetGDKKeyvalWithoutModifier() returns the keyval for aGdkKeyEvent when |
369 | | * ignoring the modifier state except NumLock. (NumLock is a key to change |
370 | | * some key's meaning.) |
371 | | */ |
372 | | static guint GetGDKKeyvalWithoutModifier(const GdkEventKey *aGdkKeyEvent); |
373 | | |
374 | | /** |
375 | | * GetDOMKeyCodeFromKeyPairs() returns DOM keycode for aGdkKeyval if |
376 | | * it's in KeyPair table. |
377 | | */ |
378 | | static uint32_t GetDOMKeyCodeFromKeyPairs(guint aGdkKeyval); |
379 | | |
380 | | /** |
381 | | * FilterEvents() listens all events on all our windows. |
382 | | * Be careful, this may make damage to performance if you add expensive |
383 | | * code in this method. |
384 | | */ |
385 | | static GdkFilterReturn FilterEvents(GdkXEvent* aXEvent, |
386 | | GdkEvent* aGdkEvent, |
387 | | gpointer aData); |
388 | | |
389 | | /** |
390 | | * See the document of WillDispatchKeyboardEvent(). |
391 | | */ |
392 | | void WillDispatchKeyboardEventInternal(WidgetKeyboardEvent& aKeyEvent, |
393 | | GdkEventKey* aGdkKeyEvent); |
394 | | |
395 | | #ifdef MOZ_WAYLAND |
396 | | /** |
397 | | * Utility function to set Xkb modifier key mask. |
398 | | */ |
399 | | void SetModifierMask(xkb_keymap *aKeymap, |
400 | | ModifierIndex aModifierIndex, |
401 | | const char* aModifierName); |
402 | | #endif |
403 | | }; |
404 | | |
405 | | } // namespace widget |
406 | | } // namespace mozilla |
407 | | |
408 | | #endif /* __nsGdkKeyUtils_h__ */ |