切换布局时,如何在xcb-xkb中跟踪键盘的变化?
当我使用 setxkbmap -layout us,gr -option grp:alt_shift_toggle 时,我可以使用 Alt + Shift 在美式布局和希腊布局之间切换。现在我尝试了下面的代码(属于一个更大项目的一部分)来检测这种变化。我原本以为会得到一个 NewKeyboardNotify 事件(就像手动执行 setxkbmap -layout us 和 setxkbmap -layout gr 一样)。然而,每次布局切换时,我会收到一对事件:一个IndicatorStateNotify事件和一个ExtensionDeviceNotify事件。这对我来说似乎有点奇怪。
cc *.c -lxcb -lxcb-xkb -lxkbcommon -lxkbcommon-x11
#include <stdio.h>
#include <stdlib.h>
#include <xcb/xcb.h>
#include <xcb/xkb.h>
struct display {
xcb_connection_t *xcb;
uint8_t xkb_base_event, xkb_base_error;
int32_t keyboard_device_id;
} display;
void open_display(void)
{
int connection_error;
xcb_xkb_use_extension_cookie_t xkb_cookie;
xcb_xkb_get_device_info_cookie_t device_cookie;
const xcb_query_extension_reply_t *extension_reply;
xcb_xkb_use_extension_reply_t *xkb_reply;
xcb_xkb_get_device_info_reply_t *device_reply;
xcb_generic_error_t *error;
display.xcb = xcb_connect(NULL, NULL);
xcb_prefetch_extension_data(display.xcb, &xcb_xkb_id);
xkb_cookie = xcb_xkb_use_extension(display.xcb,
XCB_XKB_MAJOR_VERSION, XCB_XKB_MINOR_VERSION);
device_cookie = xcb_xkb_get_device_info(display.xcb,
XCB_XKB_ID_USE_CORE_KBD, 0, 0, 0, 0, 0, 0);
extension_reply = xcb_get_extension_data(display.xcb, &xcb_xkb_id);
display.xkb_base_event = extension_reply->first_event;
display.xkb_base_error = extension_reply->first_error;
xkb_reply = xcb_xkb_use_extension_reply(display.xcb, xkb_cookie, &error);
free(xkb_reply);
device_reply = xcb_xkb_get_device_info_reply(display.xcb, device_cookie,
NULL);
display.keyboard_device_id = device_reply->deviceID;
free(device_reply);
xcb_xkb_select_events(display.xcb, display.keyboard_device_id,
~0, 0, ~0, ~0, ~0, NULL);
}
static void handle_xkb_event(xcb_generic_event_t *generic_event)
{
switch (((xcb_xkb_new_keyboard_notify_event_t*) generic_event)->xkbType) {
default:
printf("xkb: %u\n",((xcb_xkb_new_keyboard_notify_event_t*) generic_event)->xkbType);
break;
case XCB_XKB_NEW_KEYBOARD_NOTIFY: {
xcb_xkb_new_keyboard_notify_event_t *event;
event = (xcb_xkb_new_keyboard_notify_event_t*) generic_event;
if (event->oldDeviceID == display.keyboard_device_id) {
printf("xkb: NEW_KEYBOARD_NOTIFY\n");
display.keyboard_device_id = event->deviceID;
}
break;
}
case XCB_XKB_MAP_NOTIFY: {
xcb_xkb_map_notify_event_t *event;
event = (xcb_xkb_map_notify_event_t*) generic_event;
printf("xkb: MAP_NOTIFY\n");
break;
}
case XCB_XKB_STATE_NOTIFY: {
xcb_xkb_state_notify_event_t *event;
event = (xcb_xkb_state_notify_event_t*) generic_event;
printf("xkb: STATE_NOTIFY\n");
break;
}
case XCB_XKB_INDICATOR_STATE_NOTIFY: {
xcb_xkb_indicator_state_notify_event_t *event;
event = (xcb_xkb_indicator_state_notify_event_t*) generic_event;
printf("xkb: INDICATOR_STATE_NOTIFY\n");
break;
}
case XCB_XKB_EXTENSION_DEVICE_NOTIFY: {
xcb_xkb_extension_device_notify_event_t *event;
event = (xcb_xkb_extension_device_notify_event_t*) generic_event;
printf("xkb: EXTENSION_DEVICE_NOTIFY\n");
break;
}
}
}
int main(void)
{
xcb_generic_event_t *event;
open_display();
xcb_flush(display.xcb);
while (event = xcb_wait_for_event(display.xcb), event != NULL) {
if (event->response_type == display.xkb_base_event) {
handle_xkb_event(event);
}
free(event);
}
return 0;
}
为什么服务器没有发送一个NewKeyboardNotify之类的事件?我应该理解这些事件吗?应该怎么理解?
解决方案
-layout us,gr 只需要一个keymap,它同时存储两种布局。这就是在切换布局时不会发送 NewKeyboardNotify/MapNotify 的原因。相反,简单的 StateNotify 事件表示布局已经改变:
case XCB_XKB_STATE_NOTIFY: {
xcb_xkb_state_notify_event_t *event;
event = (xcb_xkb_state_notify_event_t*) generic_event;
printf("xkb: STATE_NOTIFY\n");
printf("Change: %u\n", event->changed);
if ((event->changed & XCB_XKB_STATE_PART_GROUP_STATE)) {
printf("Layout changed\n");
}
break;
}
站内所有文章版权归属LeftHeroAI导航站,无授权禁止任何主体转载、抄袭、复制内容,亦不得私自架设镜像站点。一经侵权,本站将通过法律途径追责。