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
32enum {
33 PROP_0,
34 PROP_DISPLAY,
35 LAST_PROP
36};
37
38enum {
39 DIRECTION_CHANGED,
40 KEYS_CHANGED,
41 STATE_CHANGED,
42 LAST_SIGNAL
43};
44
45static GParamSpec *props[LAST_PROP] = { NULL, };
46static guint signals[LAST_SIGNAL] = { 0 };
47
48G_DEFINE_TYPE (GdkKeymap, gdk_keymap, G_TYPE_OBJECT)
49
50static void
51gdk_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
68static void
69gdk_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
87static void
88gdk_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
98static void
99gdk_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
114static void
115gdk_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
188static void
189gdk_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 */
212GdkDisplay *
213gdk_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 */
232guint
233gdk_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 */
251guint
252gdk_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 */
270gboolean
271gdk_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 */
292gboolean
293gdk_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 */
318PangoDirection
319gdk_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 */
335gboolean
336gdk_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 */
351gboolean
352gdk_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 */
367gboolean
368gdk_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 */
383gboolean
384gdk_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 */
399guint
400gdk_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 **/
432gboolean
433gdk_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
455void
456gdk_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 **/
511gboolean
512gdk_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 **/
538guint
539gdk_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 **/
613gboolean
614gdk_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 */
650const char *
651gdk_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 */
669guint
670gdk_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 */
685void
686gdk_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

source code of gtk/gdk/gdkkeys.c