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