1 | /* GDK - The GIMP Drawing Kit |
2 | * Copyright (C) 2000 Red Hat, Inc. |
3 | * |
4 | * This library is free software; you can redistribute it and/or |
5 | * modify it under the terms of the GNU Lesser General Public |
6 | * License as published by the Free Software Foundation; either |
7 | * version 2 of the License, or (at your option) any later version. |
8 | * |
9 | * This library is distributed in the hope that it will be useful, |
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
12 | * Lesser General Public License for more details. |
13 | * |
14 | * You should have received a copy of the GNU Lesser General Public |
15 | * License along with this library. If not, see <http://www.gnu.org/licenses/>. |
16 | */ |
17 | |
18 | /* |
19 | * Modified by the GTK+ Team and others 1997-2000. See the AUTHORS |
20 | * file for a list of people on the GTK+ Team. See the ChangeLog |
21 | * files for a list of changes. These files are distributed with |
22 | * GTK+ at ftp://ftp.gtk.org/pub/gtk/. |
23 | */ |
24 | |
25 | #include "config.h" |
26 | |
27 | #include "gdkkeysyms.h" |
28 | #include "gdkkeysprivate.h" |
29 | #include "gdkdisplay.h" |
30 | #include "gdkdisplaymanagerprivate.h" |
31 | |
32 | enum { |
33 | PROP_0, |
34 | PROP_DISPLAY, |
35 | LAST_PROP |
36 | }; |
37 | |
38 | enum { |
39 | DIRECTION_CHANGED, |
40 | KEYS_CHANGED, |
41 | STATE_CHANGED, |
42 | LAST_SIGNAL |
43 | }; |
44 | |
45 | static GParamSpec *props[LAST_PROP] = { NULL, }; |
46 | static guint signals[LAST_SIGNAL] = { 0 }; |
47 | |
48 | G_DEFINE_TYPE (GdkKeymap, gdk_keymap, G_TYPE_OBJECT) |
49 | |
50 | static void |
51 | gdk_keymap_get_property (GObject *object, |
52 | guint prop_id, |
53 | GValue *value, |
54 | GParamSpec *pspec) |
55 | { |
56 | GdkKeymap *keymap = GDK_KEYMAP (object); |
57 | |
58 | switch (prop_id) |
59 | { |
60 | case PROP_DISPLAY: |
61 | g_value_set_object (value, v_object: keymap->display); |
62 | break; |
63 | default: |
64 | G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); |
65 | } |
66 | } |
67 | |
68 | static void |
69 | gdk_keymap_set_property (GObject *object, |
70 | guint prop_id, |
71 | const GValue *value, |
72 | GParamSpec *pspec) |
73 | { |
74 | GdkKeymap *keymap = GDK_KEYMAP (object); |
75 | |
76 | switch (prop_id) |
77 | { |
78 | case PROP_DISPLAY: |
79 | keymap->display = g_value_get_object (value); |
80 | break; |
81 | |
82 | default: |
83 | G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); |
84 | } |
85 | } |
86 | |
87 | static void |
88 | gdk_keymap_finalize (GObject *object) |
89 | { |
90 | GdkKeymap *keymap = GDK_KEYMAP (object); |
91 | |
92 | g_array_free (array: keymap->cached_keys, TRUE); |
93 | g_hash_table_unref (hash_table: keymap->cache); |
94 | |
95 | G_OBJECT_CLASS (gdk_keymap_parent_class)->finalize (object); |
96 | } |
97 | |
98 | static void |
99 | gdk_keymap_keys_changed (GdkKeymap *keymap) |
100 | { |
101 | GdkKeymapKey key; |
102 | |
103 | g_array_set_size (array: keymap->cached_keys, length: 0); |
104 | |
105 | key.keycode = 0; |
106 | key.group = 0; |
107 | key.level = 0; |
108 | |
109 | g_array_append_val (keymap->cached_keys, key); |
110 | |
111 | g_hash_table_remove_all (hash_table: keymap->cache); |
112 | } |
113 | |
114 | static void |
115 | gdk_keymap_class_init (GdkKeymapClass *klass) |
116 | { |
117 | GObjectClass *object_class = G_OBJECT_CLASS (klass); |
118 | |
119 | object_class->finalize = gdk_keymap_finalize; |
120 | object_class->get_property = gdk_keymap_get_property; |
121 | object_class->set_property = gdk_keymap_set_property; |
122 | |
123 | klass->keys_changed = gdk_keymap_keys_changed; |
124 | |
125 | props[PROP_DISPLAY] = |
126 | g_param_spec_object (name: "display" , |
127 | nick: "Display" , |
128 | blurb: "The display of the keymap" , |
129 | GDK_TYPE_DISPLAY, |
130 | flags: G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS); |
131 | |
132 | g_object_class_install_properties (oclass: object_class, n_pspecs: LAST_PROP, pspecs: props); |
133 | |
134 | /** |
135 | * GdkKeymap::direction-changed: |
136 | * @keymap: the object on which the signal is emitted |
137 | * |
138 | * Emitted when the direction of the keymap changes. |
139 | * |
140 | * See gdk_keymap_get_direction(). |
141 | */ |
142 | signals[DIRECTION_CHANGED] = |
143 | g_signal_new (signal_name: g_intern_static_string (string: "direction-changed" ), |
144 | G_OBJECT_CLASS_TYPE (object_class), |
145 | signal_flags: G_SIGNAL_RUN_LAST, |
146 | G_STRUCT_OFFSET (GdkKeymapClass, direction_changed), |
147 | NULL, NULL, |
148 | NULL, |
149 | G_TYPE_NONE, |
150 | n_params: 0); |
151 | |
152 | /** |
153 | * GdkKeymap::keys-changed: |
154 | * @keymap: the object on which the signal is emitted |
155 | * |
156 | * The ::keys-changed signal is emitted when the mapping represented by |
157 | * @keymap changes. |
158 | */ |
159 | signals[KEYS_CHANGED] = |
160 | g_signal_new (signal_name: g_intern_static_string (string: "keys-changed" ), |
161 | G_OBJECT_CLASS_TYPE (object_class), |
162 | signal_flags: G_SIGNAL_RUN_FIRST, |
163 | G_STRUCT_OFFSET (GdkKeymapClass, keys_changed), |
164 | NULL, NULL, |
165 | NULL, |
166 | G_TYPE_NONE, |
167 | n_params: 0); |
168 | |
169 | /** |
170 | * GdkKeymap::state-changed: |
171 | * @keymap: the object on which the signal is emitted |
172 | * |
173 | * The ::state-changed signal is emitted when the state of the |
174 | * keyboard changes, e.g when Caps Lock is turned on or off. |
175 | * See gdk_keymap_get_caps_lock_state(). |
176 | */ |
177 | signals[STATE_CHANGED] = |
178 | g_signal_new (signal_name: g_intern_static_string (string: "state-changed" ), |
179 | G_OBJECT_CLASS_TYPE (object_class), |
180 | signal_flags: G_SIGNAL_RUN_LAST, |
181 | G_STRUCT_OFFSET (GdkKeymapClass, state_changed), |
182 | NULL, NULL, |
183 | NULL, |
184 | G_TYPE_NONE, |
185 | n_params: 0); |
186 | } |
187 | |
188 | static void |
189 | gdk_keymap_init (GdkKeymap *keymap) |
190 | { |
191 | GdkKeymapKey key; |
192 | |
193 | keymap->cached_keys = g_array_new (FALSE, FALSE, element_size: sizeof (GdkKeymapKey)); |
194 | |
195 | key.keycode = 0; |
196 | key.group = 0; |
197 | key.level = 0; |
198 | |
199 | g_array_append_val (keymap->cached_keys, key); |
200 | |
201 | keymap->cache = g_hash_table_new (hash_func: g_direct_hash, key_equal_func: g_direct_equal); |
202 | } |
203 | |
204 | /*< private > |
205 | * gdk_keymap_get_display: |
206 | * @keymap: a `GdkKeymap` |
207 | * |
208 | * Retrieves the `GdkDisplay` associated to the @keymap. |
209 | * |
210 | * Returns: (transfer none): a `GdkDisplay` |
211 | */ |
212 | GdkDisplay * |
213 | gdk_keymap_get_display (GdkKeymap *keymap) |
214 | { |
215 | g_return_val_if_fail (GDK_IS_KEYMAP (keymap), NULL); |
216 | |
217 | return keymap->display; |
218 | } |
219 | |
220 | /* Other key-handling stuff |
221 | */ |
222 | |
223 | /** |
224 | * gdk_keyval_to_upper: |
225 | * @keyval: a key value. |
226 | * |
227 | * Converts a key value to upper case, if applicable. |
228 | * |
229 | * Returns: the upper case form of @keyval, or @keyval itself if it is already |
230 | * in upper case or it is not subject to case conversion. |
231 | */ |
232 | guint |
233 | gdk_keyval_to_upper (guint keyval) |
234 | { |
235 | guint result; |
236 | |
237 | gdk_keyval_convert_case (symbol: keyval, NULL, upper: &result); |
238 | |
239 | return result; |
240 | } |
241 | |
242 | /** |
243 | * gdk_keyval_to_lower: |
244 | * @keyval: a key value. |
245 | * |
246 | * Converts a key value to lower case, if applicable. |
247 | * |
248 | * Returns: the lower case form of @keyval, or @keyval itself if it is already |
249 | * in lower case or it is not subject to case conversion. |
250 | */ |
251 | guint |
252 | gdk_keyval_to_lower (guint keyval) |
253 | { |
254 | guint result; |
255 | |
256 | gdk_keyval_convert_case (symbol: keyval, lower: &result, NULL); |
257 | |
258 | return result; |
259 | } |
260 | |
261 | /** |
262 | * gdk_keyval_is_upper: |
263 | * @keyval: a key value. |
264 | * |
265 | * Returns %TRUE if the given key value is in upper case. |
266 | * |
267 | * Returns: %TRUE if @keyval is in upper case, or if @keyval is not subject to |
268 | * case conversion. |
269 | */ |
270 | gboolean |
271 | gdk_keyval_is_upper (guint keyval) |
272 | { |
273 | if (keyval) |
274 | { |
275 | guint upper_val = 0; |
276 | |
277 | gdk_keyval_convert_case (symbol: keyval, NULL, upper: &upper_val); |
278 | return upper_val == keyval; |
279 | } |
280 | return FALSE; |
281 | } |
282 | |
283 | /** |
284 | * gdk_keyval_is_lower: |
285 | * @keyval: a key value. |
286 | * |
287 | * Returns %TRUE if the given key value is in lower case. |
288 | * |
289 | * Returns: %TRUE if @keyval is in lower case, or if @keyval is not |
290 | * subject to case conversion. |
291 | */ |
292 | gboolean |
293 | gdk_keyval_is_lower (guint keyval) |
294 | { |
295 | if (keyval) |
296 | { |
297 | guint lower_val = 0; |
298 | |
299 | gdk_keyval_convert_case (symbol: keyval, lower: &lower_val, NULL); |
300 | return lower_val == keyval; |
301 | } |
302 | return FALSE; |
303 | } |
304 | |
305 | /*< private > |
306 | * gdk_keymap_get_direction: |
307 | * @keymap: a `GdkKeymap` |
308 | * |
309 | * Returns the direction of effective layout of the keymap. |
310 | * |
311 | * The direction of a layout is the direction of the majority of its |
312 | * symbols. See pango_unichar_direction(). |
313 | * |
314 | * Returns: %PANGO_DIRECTION_LTR or %PANGO_DIRECTION_RTL |
315 | * if it can determine the direction. %PANGO_DIRECTION_NEUTRAL |
316 | * otherwise. |
317 | */ |
318 | PangoDirection |
319 | gdk_keymap_get_direction (GdkKeymap *keymap) |
320 | { |
321 | g_return_val_if_fail (GDK_IS_KEYMAP (keymap), PANGO_DIRECTION_LTR); |
322 | |
323 | return GDK_KEYMAP_GET_CLASS (keymap)->get_direction (keymap); |
324 | } |
325 | |
326 | /*< private > |
327 | * gdk_keymap_have_bidi_layouts: |
328 | * @keymap: a `GdkKeymap` |
329 | * |
330 | * Determines if keyboard layouts for both right-to-left and left-to-right |
331 | * languages are in use. |
332 | * |
333 | * Returns: %TRUE if there are layouts in both directions, %FALSE otherwise |
334 | */ |
335 | gboolean |
336 | gdk_keymap_have_bidi_layouts (GdkKeymap *keymap) |
337 | { |
338 | g_return_val_if_fail (GDK_IS_KEYMAP (keymap), FALSE); |
339 | |
340 | return GDK_KEYMAP_GET_CLASS (keymap)->have_bidi_layouts (keymap); |
341 | } |
342 | |
343 | /*< private > |
344 | * gdk_keymap_get_caps_lock_state: |
345 | * @keymap: a `GdkKeymap` |
346 | * |
347 | * Returns whether the Caps Lock modifier is locked. |
348 | * |
349 | * Returns: %TRUE if Caps Lock is on |
350 | */ |
351 | gboolean |
352 | gdk_keymap_get_caps_lock_state (GdkKeymap *keymap) |
353 | { |
354 | g_return_val_if_fail (GDK_IS_KEYMAP (keymap), FALSE); |
355 | |
356 | return GDK_KEYMAP_GET_CLASS (keymap)->get_caps_lock_state (keymap); |
357 | } |
358 | |
359 | /*< private > |
360 | * gdk_keymap_get_num_lock_state: |
361 | * @keymap: a `GdkKeymap` |
362 | * |
363 | * Returns whether the Num Lock modifier is locked. |
364 | * |
365 | * Returns: %TRUE if Num Lock is on |
366 | */ |
367 | gboolean |
368 | gdk_keymap_get_num_lock_state (GdkKeymap *keymap) |
369 | { |
370 | g_return_val_if_fail (GDK_IS_KEYMAP (keymap), FALSE); |
371 | |
372 | return GDK_KEYMAP_GET_CLASS (keymap)->get_num_lock_state (keymap); |
373 | } |
374 | |
375 | /*< private > |
376 | * gdk_keymap_get_scroll_lock_state: |
377 | * @keymap: a `GdkKeymap` |
378 | * |
379 | * Returns whether the Scroll Lock modifier is locked. |
380 | * |
381 | * Returns: %TRUE if Scroll Lock is on |
382 | */ |
383 | gboolean |
384 | gdk_keymap_get_scroll_lock_state (GdkKeymap *keymap) |
385 | { |
386 | g_return_val_if_fail (GDK_IS_KEYMAP (keymap), FALSE); |
387 | |
388 | return GDK_KEYMAP_GET_CLASS (keymap)->get_scroll_lock_state (keymap); |
389 | } |
390 | |
391 | /*< private > |
392 | * gdk_keymap_get_modifier_state: |
393 | * @keymap: a `GdkKeymap` |
394 | * |
395 | * Returns the current modifier state. |
396 | * |
397 | * Returns: the current modifier state. |
398 | */ |
399 | guint |
400 | gdk_keymap_get_modifier_state (GdkKeymap *keymap) |
401 | { |
402 | g_return_val_if_fail (GDK_IS_KEYMAP (keymap), FALSE); |
403 | |
404 | if (GDK_KEYMAP_GET_CLASS (keymap)->get_modifier_state) |
405 | return GDK_KEYMAP_GET_CLASS (keymap)->get_modifier_state (keymap); |
406 | |
407 | return 0; |
408 | } |
409 | |
410 | /*< private > |
411 | * gdk_keymap_get_entries_for_keyval: |
412 | * @keymap: a `GdkKeymap` |
413 | * @keyval: a keyval, such as %GDK_KEY_a, %GDK_KEY_Up, %GDK_KEY_Return, etc. |
414 | * @keys: (out) (array length=n_keys) (transfer full): return location |
415 | * for an array of `GdkKeymapKey` |
416 | * @n_keys: return location for number of elements in returned array |
417 | * |
418 | * Obtains a list of keycode/group/level combinations that will |
419 | * generate @keyval. Groups and levels are two kinds of keyboard mode; |
420 | * in general, the level determines whether the top or bottom symbol |
421 | * on a key is used, and the group determines whether the left or |
422 | * right symbol is used. On US keyboards, the shift key changes the |
423 | * keyboard level, and there are no groups. A group switch key might |
424 | * convert a keyboard between Hebrew to English modes, for example. |
425 | * `GdkEventKey` contains a %group field that indicates the active |
426 | * keyboard group. The level is computed from the modifier mask. |
427 | * The returned array should be freed |
428 | * with g_free(). |
429 | * |
430 | * Returns: %TRUE if keys were found and returned |
431 | **/ |
432 | gboolean |
433 | gdk_keymap_get_entries_for_keyval (GdkKeymap *keymap, |
434 | guint keyval, |
435 | GdkKeymapKey **keys, |
436 | int *n_keys) |
437 | { |
438 | GArray *array; |
439 | |
440 | g_return_val_if_fail (GDK_IS_KEYMAP (keymap), FALSE); |
441 | g_return_val_if_fail (keys != NULL, FALSE); |
442 | g_return_val_if_fail (n_keys != NULL, FALSE); |
443 | g_return_val_if_fail (keyval != 0, FALSE); |
444 | |
445 | array = g_array_new (FALSE, FALSE, element_size: sizeof (GdkKeymapKey)); |
446 | |
447 | GDK_KEYMAP_GET_CLASS (keymap)->get_entries_for_keyval (keymap, keyval, array); |
448 | |
449 | *n_keys = array->len; |
450 | *keys = (GdkKeymapKey *)g_array_free (array, FALSE); |
451 | |
452 | return TRUE; |
453 | } |
454 | |
455 | void |
456 | gdk_keymap_get_cached_entries_for_keyval (GdkKeymap *keymap, |
457 | guint keyval, |
458 | GdkKeymapKey **keys, |
459 | guint *n_keys) |
460 | { |
461 | guint cached; |
462 | guint offset; |
463 | guint len; |
464 | |
465 | /* avoid using the first entry in cached_keys, so we can |
466 | * use 0 to mean 'not cached' |
467 | */ |
468 | cached = GPOINTER_TO_UINT (g_hash_table_lookup (keymap->cache, GUINT_TO_POINTER (keyval))); |
469 | if (cached == 0) |
470 | { |
471 | offset = keymap->cached_keys->len; |
472 | |
473 | GDK_KEYMAP_GET_CLASS (keymap)->get_entries_for_keyval (keymap, keyval, keymap->cached_keys); |
474 | |
475 | len = keymap->cached_keys->len - offset; |
476 | g_assert (len <= 255); |
477 | |
478 | cached = (offset << 8) | len; |
479 | |
480 | g_hash_table_insert (hash_table: keymap->cache, GUINT_TO_POINTER (keyval), GUINT_TO_POINTER (cached)); |
481 | } |
482 | else |
483 | { |
484 | len = cached & 255; |
485 | offset = cached >> 8; |
486 | } |
487 | |
488 | *n_keys = len; |
489 | *keys = (GdkKeymapKey *)&g_array_index (keymap->cached_keys, GdkKeymapKey, offset); |
490 | } |
491 | |
492 | /*< private > |
493 | * gdk_keymap_get_entries_for_keycode: |
494 | * @keymap: a `GdkKeymap` |
495 | * @hardware_keycode: a keycode |
496 | * @keys: (out) (array length=n_entries) (transfer full) (optional): return |
497 | * location for array of `GdkKeymapKey` |
498 | * @keyvals: (out) (array length=n_entries) (transfer full) (optional): return |
499 | * location for array of keyvals |
500 | * @n_entries: length of @keys and @keyvals |
501 | * |
502 | * Returns the keyvals bound to @hardware_keycode. |
503 | * The Nth `GdkKeymapKey` in @keys is bound to the Nth |
504 | * keyval in @keyvals. Free the returned arrays with g_free(). |
505 | * When a keycode is pressed by the user, the keyval from |
506 | * this list of entries is selected by considering the effective |
507 | * keyboard group and level. See gdk_keymap_translate_keyboard_state(). |
508 | * |
509 | * Returns: %TRUE if there were any entries |
510 | **/ |
511 | gboolean |
512 | gdk_keymap_get_entries_for_keycode (GdkKeymap *keymap, |
513 | guint hardware_keycode, |
514 | GdkKeymapKey **keys, |
515 | guint **keyvals, |
516 | int *n_entries) |
517 | { |
518 | g_return_val_if_fail (GDK_IS_KEYMAP (keymap), FALSE); |
519 | g_return_val_if_fail (n_entries != NULL, FALSE); |
520 | |
521 | return GDK_KEYMAP_GET_CLASS (keymap)->get_entries_for_keycode (keymap, hardware_keycode, |
522 | keys, keyvals, n_entries); |
523 | } |
524 | |
525 | /*< private > |
526 | * gdk_keymap_lookup_key: |
527 | * @keymap: a `GdkKeymap` |
528 | * @key: a `GdkKeymapKey` with keycode, group, and level initialized |
529 | * |
530 | * Looks up the keyval mapped to a keycode/group/level triplet. |
531 | * If no keyval is bound to @key, returns 0. For normal user input, |
532 | * you want to use gdk_keymap_translate_keyboard_state() instead of |
533 | * this function, since the effective group/level may not be |
534 | * the same as the current keyboard state. |
535 | * |
536 | * Returns: a keyval, or 0 if none was mapped to the given @key |
537 | **/ |
538 | guint |
539 | gdk_keymap_lookup_key (GdkKeymap *keymap, |
540 | const GdkKeymapKey *key) |
541 | { |
542 | g_return_val_if_fail (GDK_IS_KEYMAP (keymap), 0); |
543 | g_return_val_if_fail (key != NULL, 0); |
544 | |
545 | return GDK_KEYMAP_GET_CLASS (keymap)->lookup_key (keymap, key); |
546 | } |
547 | |
548 | /*< private > |
549 | * gdk_keymap_translate_keyboard_state: |
550 | * @keymap: a `GdkKeymap` |
551 | * @hardware_keycode: a keycode |
552 | * @state: a modifier state |
553 | * @group: active keyboard group |
554 | * @keyval: (out) (optional): return location for keyval |
555 | * @effective_group: (out) (optional): return location for effective group |
556 | * @level: (out) (optional): return location for level |
557 | * @consumed_modifiers: (out) (optional): return location for modifiers |
558 | * that were used to determine the group or level |
559 | * |
560 | * Translates the contents of a `GdkEventKey` into a keyval, effective |
561 | * group, and level. Modifiers that affected the translation and |
562 | * are thus unavailable for application use are returned in |
563 | * @consumed_modifiers. |
564 | * See [Groups][key-group-explanation] for an explanation of |
565 | * groups and levels. The @effective_group is the group that was |
566 | * actually used for the translation; some keys such as Enter are not |
567 | * affected by the active keyboard group. The @level is derived from |
568 | * @state. For convenience, `GdkEventKey` already contains the translated |
569 | * keyval, so this function isn’t as useful as you might think. |
570 | * |
571 | * @consumed_modifiers gives modifiers that should be masked outfrom @state |
572 | * when comparing this key press to a hot key. For instance, on a US keyboard, |
573 | * the `plus` symbol is shifted, so when comparing a key press to a |
574 | * `<Control>plus` accelerator `<Shift>` should be masked out. |
575 | * |
576 | * |[<!-- language="C" --> |
577 | * // We want to ignore irrelevant modifiers like ScrollLock |
578 | * #define ALL_ACCELS_MASK (GDK_CONTROL_MASK | GDK_SHIFT_MASK | GDK_ALT_MASK) |
579 | * state = gdk_event_get_modifier_state (event); |
580 | * gdk_keymap_translate_keyboard_state (keymap, |
581 | * gdk_key_event_get_keycode (event), |
582 | * state, |
583 | * gdk_key_event_get_group (event), |
584 | * &keyval, NULL, NULL, &consumed); |
585 | * if (keyval == GDK_PLUS && |
586 | * (state & ~consumed & ALL_ACCELS_MASK) == GDK_CONTROL_MASK) |
587 | * // Control was pressed |
588 | * ]| |
589 | * |
590 | * An older interpretation @consumed_modifiers was that it contained |
591 | * all modifiers that might affect the translation of the key; |
592 | * this allowed accelerators to be stored with irrelevant consumed |
593 | * modifiers, by doing: |
594 | * |[<!-- language="C" --> |
595 | * // XXX Don’t do this XXX |
596 | * if (keyval == accel_keyval && |
597 | * (state & ~consumed & ALL_ACCELS_MASK) == (accel_mods & ~consumed)) |
598 | * // Accelerator was pressed |
599 | * ]| |
600 | * |
601 | * However, this did not work if multi-modifier combinations were |
602 | * used in the keymap, since, for instance, `<Control>` would be |
603 | * masked out even if only `<Control><Alt>` was used in the keymap. |
604 | * To support this usage as well as well as possible, all single |
605 | * modifier combinations that could affect the key for any combination |
606 | * of modifiers will be returned in @consumed_modifiers; multi-modifier |
607 | * combinations are returned only when actually found in @state. When |
608 | * you store accelerators, you should always store them with consumed |
609 | * modifiers removed. Store `<Control>plus`, not `<Control><Shift>plus`, |
610 | * |
611 | * Returns: %TRUE if there was a keyval bound to the keycode/state/group |
612 | **/ |
613 | gboolean |
614 | gdk_keymap_translate_keyboard_state (GdkKeymap *keymap, |
615 | guint hardware_keycode, |
616 | GdkModifierType state, |
617 | int group, |
618 | guint *keyval, |
619 | int *effective_group, |
620 | int *level, |
621 | GdkModifierType *consumed_modifiers) |
622 | { |
623 | g_return_val_if_fail (GDK_IS_KEYMAP (keymap), FALSE); |
624 | |
625 | return GDK_KEYMAP_GET_CLASS (keymap)->translate_keyboard_state (keymap, |
626 | hardware_keycode, |
627 | state, |
628 | group, |
629 | keyval, |
630 | effective_group, |
631 | level, |
632 | consumed_modifiers); |
633 | } |
634 | |
635 | #include "gdkkeynames.c" |
636 | |
637 | /** |
638 | * gdk_keyval_name: |
639 | * @keyval: a key value |
640 | * |
641 | * Converts a key value into a symbolic name. |
642 | * |
643 | * The names are the same as those in the |
644 | * `gdk/gdkkeysyms.h` header file |
645 | * but without the leading “GDK_KEY_”. |
646 | * |
647 | * Returns: (nullable) (transfer none): a string containing the name |
648 | * of the key |
649 | */ |
650 | const char * |
651 | gdk_keyval_name (guint keyval) |
652 | { |
653 | return _gdk_keyval_name (keyval); |
654 | } |
655 | |
656 | /** |
657 | * gdk_keyval_from_name: |
658 | * @keyval_name: a key name |
659 | * |
660 | * Converts a key name to a key value. |
661 | * |
662 | * The names are the same as those in the |
663 | * `gdk/gdkkeysyms.h` header file |
664 | * but without the leading “GDK_KEY_”. |
665 | * |
666 | * Returns: the corresponding key value, or %GDK_KEY_VoidSymbol |
667 | * if the key name is not a valid key |
668 | */ |
669 | guint |
670 | gdk_keyval_from_name (const char *keyval_name) |
671 | { |
672 | return _gdk_keyval_from_name (keyval_name); |
673 | } |
674 | |
675 | /** |
676 | * gdk_keyval_convert_case: |
677 | * @symbol: a keyval |
678 | * @lower: (out): return location for lowercase version of @symbol |
679 | * @upper: (out): return location for uppercase version of @symbol |
680 | * |
681 | * Obtains the upper- and lower-case versions of the keyval @symbol. |
682 | * |
683 | * Examples of keyvals are `GDK_KEY_a`, `GDK_KEY_Enter`, `GDK_KEY_F1`, etc. |
684 | */ |
685 | void |
686 | gdk_keyval_convert_case (guint symbol, |
687 | guint *lower, |
688 | guint *upper) |
689 | { |
690 | guint xlower, xupper; |
691 | |
692 | xlower = symbol; |
693 | xupper = symbol; |
694 | |
695 | /* Check for directly encoded 24-bit UCS characters: */ |
696 | if ((symbol & 0xff000000) == 0x01000000) |
697 | { |
698 | if (lower) |
699 | *lower = gdk_unicode_to_keyval (wc: g_unichar_tolower (c: symbol & 0x00ffffff)); |
700 | if (upper) |
701 | *upper = gdk_unicode_to_keyval (wc: g_unichar_toupper (c: symbol & 0x00ffffff)); |
702 | return; |
703 | } |
704 | |
705 | switch (symbol >> 8) |
706 | { |
707 | case 0: /* Latin 1 */ |
708 | if ((symbol >= GDK_KEY_A) && (symbol <= GDK_KEY_Z)) |
709 | xlower += (GDK_KEY_a - GDK_KEY_A); |
710 | else if ((symbol >= GDK_KEY_a) && (symbol <= GDK_KEY_z)) |
711 | xupper -= (GDK_KEY_a - GDK_KEY_A); |
712 | else if ((symbol >= GDK_KEY_Agrave) && (symbol <= GDK_KEY_Odiaeresis)) |
713 | xlower += (GDK_KEY_agrave - GDK_KEY_Agrave); |
714 | else if ((symbol >= GDK_KEY_agrave) && (symbol <= GDK_KEY_odiaeresis)) |
715 | xupper -= (GDK_KEY_agrave - GDK_KEY_Agrave); |
716 | else if ((symbol >= GDK_KEY_Ooblique) && (symbol <= GDK_KEY_Thorn)) |
717 | xlower += (GDK_KEY_oslash - GDK_KEY_Ooblique); |
718 | else if ((symbol >= GDK_KEY_oslash) && (symbol <= GDK_KEY_thorn)) |
719 | xupper -= (GDK_KEY_oslash - GDK_KEY_Ooblique); |
720 | break; |
721 | |
722 | case 1: /* Latin 2 */ |
723 | /* Assume the KeySym is a legal value (ignore discontinuities) */ |
724 | if (symbol == GDK_KEY_Aogonek) |
725 | xlower = GDK_KEY_aogonek; |
726 | else if (symbol >= GDK_KEY_Lstroke && symbol <= GDK_KEY_Sacute) |
727 | xlower += (GDK_KEY_lstroke - GDK_KEY_Lstroke); |
728 | else if (symbol >= GDK_KEY_Scaron && symbol <= GDK_KEY_Zacute) |
729 | xlower += (GDK_KEY_scaron - GDK_KEY_Scaron); |
730 | else if (symbol >= GDK_KEY_Zcaron && symbol <= GDK_KEY_Zabovedot) |
731 | xlower += (GDK_KEY_zcaron - GDK_KEY_Zcaron); |
732 | else if (symbol == GDK_KEY_aogonek) |
733 | xupper = GDK_KEY_Aogonek; |
734 | else if (symbol >= GDK_KEY_lstroke && symbol <= GDK_KEY_sacute) |
735 | xupper -= (GDK_KEY_lstroke - GDK_KEY_Lstroke); |
736 | else if (symbol >= GDK_KEY_scaron && symbol <= GDK_KEY_zacute) |
737 | xupper -= (GDK_KEY_scaron - GDK_KEY_Scaron); |
738 | else if (symbol >= GDK_KEY_zcaron && symbol <= GDK_KEY_zabovedot) |
739 | xupper -= (GDK_KEY_zcaron - GDK_KEY_Zcaron); |
740 | else if (symbol >= GDK_KEY_Racute && symbol <= GDK_KEY_Tcedilla) |
741 | xlower += (GDK_KEY_racute - GDK_KEY_Racute); |
742 | else if (symbol >= GDK_KEY_racute && symbol <= GDK_KEY_tcedilla) |
743 | xupper -= (GDK_KEY_racute - GDK_KEY_Racute); |
744 | break; |
745 | |
746 | case 2: /* Latin 3 */ |
747 | /* Assume the KeySym is a legal value (ignore discontinuities) */ |
748 | if (symbol >= GDK_KEY_Hstroke && symbol <= GDK_KEY_Hcircumflex) |
749 | xlower += (GDK_KEY_hstroke - GDK_KEY_Hstroke); |
750 | else if (symbol >= GDK_KEY_Gbreve && symbol <= GDK_KEY_Jcircumflex) |
751 | xlower += (GDK_KEY_gbreve - GDK_KEY_Gbreve); |
752 | else if (symbol >= GDK_KEY_hstroke && symbol <= GDK_KEY_hcircumflex) |
753 | xupper -= (GDK_KEY_hstroke - GDK_KEY_Hstroke); |
754 | else if (symbol >= GDK_KEY_gbreve && symbol <= GDK_KEY_jcircumflex) |
755 | xupper -= (GDK_KEY_gbreve - GDK_KEY_Gbreve); |
756 | else if (symbol >= GDK_KEY_Cabovedot && symbol <= GDK_KEY_Scircumflex) |
757 | xlower += (GDK_KEY_cabovedot - GDK_KEY_Cabovedot); |
758 | else if (symbol >= GDK_KEY_cabovedot && symbol <= GDK_KEY_scircumflex) |
759 | xupper -= (GDK_KEY_cabovedot - GDK_KEY_Cabovedot); |
760 | break; |
761 | |
762 | case 3: /* Latin 4 */ |
763 | /* Assume the KeySym is a legal value (ignore discontinuities) */ |
764 | if (symbol >= GDK_KEY_Rcedilla && symbol <= GDK_KEY_Tslash) |
765 | xlower += (GDK_KEY_rcedilla - GDK_KEY_Rcedilla); |
766 | else if (symbol >= GDK_KEY_rcedilla && symbol <= GDK_KEY_tslash) |
767 | xupper -= (GDK_KEY_rcedilla - GDK_KEY_Rcedilla); |
768 | else if (symbol == GDK_KEY_ENG) |
769 | xlower = GDK_KEY_eng; |
770 | else if (symbol == GDK_KEY_eng) |
771 | xupper = GDK_KEY_ENG; |
772 | else if (symbol >= GDK_KEY_Amacron && symbol <= GDK_KEY_Umacron) |
773 | xlower += (GDK_KEY_amacron - GDK_KEY_Amacron); |
774 | else if (symbol >= GDK_KEY_amacron && symbol <= GDK_KEY_umacron) |
775 | xupper -= (GDK_KEY_amacron - GDK_KEY_Amacron); |
776 | break; |
777 | |
778 | case 6: /* Cyrillic */ |
779 | /* Assume the KeySym is a legal value (ignore discontinuities) */ |
780 | if (symbol >= GDK_KEY_Serbian_DJE && symbol <= GDK_KEY_Serbian_DZE) |
781 | xlower -= (GDK_KEY_Serbian_DJE - GDK_KEY_Serbian_dje); |
782 | else if (symbol >= GDK_KEY_Serbian_dje && symbol <= GDK_KEY_Serbian_dze) |
783 | xupper += (GDK_KEY_Serbian_DJE - GDK_KEY_Serbian_dje); |
784 | else if (symbol >= GDK_KEY_Cyrillic_YU && symbol <= GDK_KEY_Cyrillic_HARDSIGN) |
785 | xlower -= (GDK_KEY_Cyrillic_YU - GDK_KEY_Cyrillic_yu); |
786 | else if (symbol >= GDK_KEY_Cyrillic_yu && symbol <= GDK_KEY_Cyrillic_hardsign) |
787 | xupper += (GDK_KEY_Cyrillic_YU - GDK_KEY_Cyrillic_yu); |
788 | break; |
789 | |
790 | case 7: /* Greek */ |
791 | /* Assume the KeySym is a legal value (ignore discontinuities) */ |
792 | if (symbol >= GDK_KEY_Greek_ALPHAaccent && symbol <= GDK_KEY_Greek_OMEGAaccent) |
793 | xlower += (GDK_KEY_Greek_alphaaccent - GDK_KEY_Greek_ALPHAaccent); |
794 | else if (symbol >= GDK_KEY_Greek_alphaaccent && symbol <= GDK_KEY_Greek_omegaaccent && |
795 | symbol != GDK_KEY_Greek_iotaaccentdieresis && |
796 | symbol != GDK_KEY_Greek_upsilonaccentdieresis) |
797 | xupper -= (GDK_KEY_Greek_alphaaccent - GDK_KEY_Greek_ALPHAaccent); |
798 | else if (symbol >= GDK_KEY_Greek_ALPHA && symbol <= GDK_KEY_Greek_OMEGA) |
799 | xlower += (GDK_KEY_Greek_alpha - GDK_KEY_Greek_ALPHA); |
800 | else if (symbol == GDK_KEY_Greek_finalsmallsigma) |
801 | xupper = GDK_KEY_Greek_SIGMA; |
802 | else if (symbol >= GDK_KEY_Greek_alpha && symbol <= GDK_KEY_Greek_omega) |
803 | xupper -= (GDK_KEY_Greek_alpha - GDK_KEY_Greek_ALPHA); |
804 | break; |
805 | |
806 | default: |
807 | break; |
808 | } |
809 | |
810 | if (lower) |
811 | *lower = xlower; |
812 | if (upper) |
813 | *upper = xupper; |
814 | } |
815 | |