键盘代码、组和修饰符 [src]
用于操作键盘代码的函数
键值是每当某个键被按下或释放时发送的代码。它们包含在 `GdkEvent` 的按键或释放中。键值列表可以在 `gdk/gdkkeysyms.h` 头文件里找到。
键值会定期从上游 X.org X11 实现更新,所以会定期添加新值。它们将带有 `GDK_KEY_` 前缀,而不是 `XF86XK_` 或 `XK_`(对于较旧的符号)。
键值可以使用 `gdk_keyval_name()` 转换成字符串表示形式。相反的函数(将字符串转换成键值)由 `gdk_keyval_from_name()` 提供。
键值的大小写可以使用 `gdk_keyval_is_upper()` 和 `gdk_keyval_is_lower()` 来判断。键值可以使用 `gdk_keyval_to_upper()` 和 `gdk_keyval_to_lower()` 转换成大写或小写。
如有必要,键值可以使用 `gdk_keyval_to_unicode()` 和 `gdk_unicode_to_keyval()` 转换成 Unicode 字符和从 Unicode 字符反转。
键组
在最低层,键盘上的物理键由数字键码表示,而 GDK 根据配置的键盘布局和键盘的当前状态知道如何将这些键码转换成键值。在 GDK api 中,键码到键值的映射可以通过 `gdk_display_map_keycode()` 获得,而反向映射可以通过 `gdk_display_map_keyval()` 获得。这些函数的结果以 `GdkKeymapKey` 结构返回。
你可以把 `GdkKeymapKey` 视为打印在物理键盘键上的一个符号的表示。也就是说,它包含三部分信息
- 首先,它包含硬件键码;这是物理键的识别号
- 其次,它包含键的“级别”。级别指示在垂直方向上将使用键上的哪个符号。因此,在标准 US 键盘上,键上的 “1” 也有感叹号(“!”)字符。级别指示是使用“1”还是“!”符号。字母键的 0 级被认为是小写字母,1 级被认为是大写字母,虽然通常只有大写字母印在键上
- 第三,`GdkKeymapKey` 包含一个组;标准 US 键盘不使用组,但是在许多其他国家中使用。在带有组的键盘上,一个键上可以打印 3 或 4 个符号。组指示水平方向上的移动。通常,组用于两种不同的语言。在第 0 组中,一个键可能有两个英文字符,在第 1 组中,它可能有两个希伯来文字符。希伯来文字符将印在键旁边的英文字符旁边。
当 GDK 创建一个按键事件来传递一个按键按下或抬起时,它首先将当前键盘状态转换为一个有效的组和层次。这是通过一组规则完成的,这些规则因键盘类型和用户配置的不同而有所不同。此转换的输入包括按下的硬件键码、活动修饰符和活动组。然后它应用适当的规则,并返回用于索引键映射的组/层次,以及不影响组和层次的修饰符。即返回“未使用的修饰符”。键盘组可能与用于查找的有效组不同,因为某些键没有多个组——例如,无论键盘状态如何,Enter 键始终在组 0 中。
转换结果,包括键值,都包含在按键事件中,可以通过 GdkKeyEvent
获取器获取它们。
使用的修饰符
按键事件中的 consumed_modifiers
是与热键比较此按键按下时应当从 state
中屏蔽的修饰符。例如,在 US 键盘上,+
符号已移位,因此在将按键按下与 <Control>+
加速器进行比较时,应当屏蔽 Shift。
// We want to ignore irrelevant modifiers like ScrollLock
#define ALL_ACCELS_MASK (GDK_CONTROL_MASK | GDK_SHIFT_MASK | GDK_ALT_MASK)
state = gdk_event_get_modifier_state (event);
gdk_keymap_translate_keyboard_state (keymap,
gdk_key_event_get_keycode (event),
state,
gdk_key_event_get_group (event),
&keyval, NULL, NULL, &consumed);
if (keyval == GDK_PLUS &&
(state & ~consumed & ALL_ACCELS_MASK) == GDK_CONTROL_MASK)
// Control was pressed
consumed_modifiers
的旧解释是,它包含所有可能影响按键翻译的修饰符;它允许通过执行以下操作将加速器存储为具有不相关使用修饰符
// XXX Don’t do this XXX
if (keyval == accel_keyval &&
(state & ~consumed & ALL_ACCELS_MASK) == (accel_mods & ~consumed))
// Accelerator was pressed
但是,如果在键映射中使用多个修饰符组合,此方法将不起作用,因为 <Control>
将被屏蔽,即使仅在键映射中使用了 <Control><Alt>
。为了支持这种用法以及尽可能的支持,所有可能的任何修饰符组合都将返回 consumed_modifiers
中,以影响按键;仅在 state
中实际找到多修饰符组合时才返回它们。存储加速器时,您应当始终使用移除使用修饰符的方式存储它们。存储 <Control>+
,而不是 <Control><Shift>+
。