下面的X11客户端在RECORD扩展的数据连接上看不到XKEYBOARD事件。
我已经成功地使用RECORD扩展来捕获X显示器上的光标移动和KeyPress事件。
现在,我想将KeyPress事件解码为正确的utf-8字符。这需要XKB,因为我使用的是xcb(无论如何,不赞成使用Xlib的XLookupString)。
因此,我使用类似以下内容来设置我的RECORD上下文:
xcb_record_range_t rr[] = {
//{.delivered_events = {XCB_KEY_PRESS, XCB_KEY_RELEASE}}, // 2-3
//{.delivered_events = {XCB_BUTTON_PRESS, XCB_BUTTON_RELEASE}}, // 4-5
//{.delivered_events = {XCB_SELECTION_NOTIFY, XCB_SELECTION_NOTIFY}}, // 31
//{.device_events = {XCB_MOTION_NOTIFY, XCB_MOTION_NOTIFY}}, // 6
// NOTE: variable xkb_base_event setup from XKB initialization.
// (there is only one XKB event, with several 'subtypes').
// Also, I don't know whether XKB events are 'delivered' or 'device events'.
{.delivered_events = {xkb_base_event, xkb_base_event}},
{.device_events = {xkb_base_event, xkb_base_event}},
// "Event codes 64 through 127 are reserved for extensions"
{.delivered_events = {64, 127}}, // all extensions.
{.device_events = {64, 127}}, // all extensions.
};
这是RECORD客户端:
// m0.c: RECORD client, reporting all extension events.
//
// compile with:
//
// cc -std=c99 -Wall -Wextra -g -O2 -fno-omit-frame-pointer -D_GNU_SOURCE -Wl,--as-needed m0.c -lxcb-record -lxcb-util -lxcb -o m0
//
#include <err.h>
#include <locale.h>
#include <poll.h>
#include <stdio.h>
#include <stdlib.h>
#include <xcb/xcb.h>
#include <xcb/record.h>
#include <xcb/xcb_util.h>
#define UNUSED(x) ((void)(x))
#define NELEMS(a) (sizeof(a) / sizeof(a[0]))
static void data_dump(size_t len, void* p)
{
if (len == 0)
return;
uint8_t* data = p;
for (size_t i = 0; i < len; i++) {
if (i && i % 2 == 0) printf(" ");
printf("%02X", data[i]);
}
printf("\n");
}
static size_t protocol_error_process(void* error)
{
xcb_generic_error_t* err = error;
// TODO: error for Tcl layer?
printf("-- %s:: error_code=%d sequence=%d major=%d minor=%d",
__func__, err->error_code, err->sequence, err->major_code, err->minor_code);
// TODO: if error from request:
// xcb_request_error_t* re = err;
// re->error_code
// re->sequence
// re->bad_value
// re->minor_opcode
// re->major_opcode
return sizeof(xcb_generic_error_t);
}
static size_t protocol_reply_process(void* reply)
{
// 0.
xcb_generic_reply_t* gr = reply;
size_t length_in_bytes = 32 + gr->length * 4;
if (1)
printf("-- %s: sequence=%d bytes=%zu\n",
__func__, gr->sequence, length_in_bytes);
return length_in_bytes;
}
static size_t protocol_event_process(xcb_generic_event_t* event)
{
uint8_t type = XCB_EVENT_RESPONSE_TYPE(event);
switch (type) {
case XCB_KEY_PRESS:
printf("-- %s: KeyPress\n", __func__);
break;
case XCB_KEY_RELEASE:
printf("-- %s: KeyRelease\n", __func__);
break;
case XCB_BUTTON_PRESS:
printf("-- %s: ButtonPress\n", __func__);
break;
case XCB_BUTTON_RELEASE:
printf("-- %s: ButtonRelease\n", __func__);
break;
case XCB_MOTION_NOTIFY:
printf("-- %s: MotionNotify\n", __func__);
break;
case XCB_SELECTION_NOTIFY:
printf("-- %s: SelectionNotify\n", __func__);
break;
default:
if (64 <= type && type <= 127) {
printf("-- %s: event %d from extension\n", __func__, type);
printf("\t");
data_dump(sizeof(event), event);
} else {
printf("unexpected event type=%s(%d) sequence=%d\n",
xcb_event_get_label(type), type, event->sequence);
}
}
return sizeof(xcb_raw_generic_event_t);
}
static void data_from_server_process(size_t length, uint8_t* data)
{
uint8_t* end = data + length;
while (data < end) {
xcb_generic_event_t* event = (xcb_generic_event_t*)data;
switch (XCB_EVENT_RESPONSE_TYPE(event)) {
case 0:
data += protocol_error_process(data);
break;
case 1:
data += protocol_reply_process(data);
break;
default:
data += protocol_event_process(event);
break;
}
}
}
int main(int argc, char* argv[])
{
UNUSED(argc);
if (!setlocale(LC_ALL, ""))
errx(1, "failed to set locale");
setlinebuf(stdout);
xcb_connection_t* c = xcb_connect(argv[1], 0);
if (xcb_connection_has_error(c))
errx(1, "failed to connect to display %s", argv[1]);
xcb_prefetch_extension_data(c, &xcb_record_id);
const xcb_query_extension_reply_t* reply = xcb_get_extension_data(c, &xcb_record_id);
if (!reply->present)
errx(1, "the RECORD extension is missing on display %s", argv[1]);
{
xcb_record_query_version_cookie_t cookie =
xcb_record_query_version(c,
XCB_RECORD_MAJOR_VERSION,
XCB_RECORD_MINOR_VERSION);
xcb_record_query_version_reply_t* reply =
xcb_record_query_version_reply(c, cookie, 0);
if (!reply)
errx(1, "failed to query version of RECORD extension");
free(reply);
}
xcb_record_context_t record_context = 0;
{
xcb_record_context_t rc = xcb_generate_id(c);
xcb_record_element_header_t h = XCB_RECORD_H_TYPE_FROM_SERVER_TIME
| XCB_RECORD_H_TYPE_FROM_CLIENT_SEQUENCE;
h = 0; // no header for now.
xcb_record_client_spec_t rcs[] = {XCB_RECORD_CS_ALL_CLIENTS};
xcb_record_range_t rr[] = {
//{.core_requests = {XCB_GET_PROPERTY, XCB_GET_PROPERTY}}, // 20
//{.core_replies = {XCB_GET_PROPERTY, XCB_GET_PROPERTY}},
{.delivered_events = {XCB_KEY_PRESS, XCB_KEY_RELEASE}}, // 2-3
{.delivered_events = {XCB_BUTTON_PRESS, XCB_BUTTON_RELEASE}}, // 4-5
//{.delivered_events = {XCB_SELECTION_NOTIFY, XCB_SELECTION_NOTIFY}}, // 31
// "Event codes 64 through 127 are reserved for extensions"
{.delivered_events = {64, 127}}, // all extensions.
{.device_events = {XCB_MOTION_NOTIFY, XCB_MOTION_NOTIFY}}, // 6
{.device_events = {64, 127}}, // all extensions.
};
xcb_void_cookie_t cookie =
xcb_record_create_context_checked(c, rc, h, NELEMS(rcs), NELEMS(rr), rcs, rr);
xcb_generic_error_t* error = xcb_request_check(c, cookie);
if (error)
errx(1, "failed to create RECORD context");
record_context = rc;
}
xcb_connection_t* d = xcb_connect(argv[1], 0);
if (xcb_connection_has_error(d))
errx(1, "failed to create data connection to display %s", argv[1]);
xcb_record_enable_context_cookie_t record_cookie =
xcb_record_enable_context(d, record_context);
for (;;) {
if (xcb_connection_has_error(d))
break;
xcb_record_enable_context_reply_t* reply =
xcb_record_enable_context_reply(d, record_cookie, 0);
if (!reply)
continue;
int len = xcb_record_enable_context_data_length(reply);
uint8_t* data = xcb_record_enable_context_data(reply);
switch (reply->category) {
case 0: // XRecordFromServer: errors, replies and events.
printf("XRecordFromServer: len=%d\n", len);
data_from_server_process(len, data);
break;
case 1: // XRecordFromClient: requests.
printf("XRecordFromClient\n");
break;
case 2: // XRecordClientStarted:
errx(1, "category ClientStarted should never happen");
break;
case 3: // XRecordClientDied:
errx(1, "category ClientDied should never happen");
break;
case 4: // XRecordStartOfData:
printf("XRecordStartOfData\n");
break;
case 5: // XRecordEndOfData:
printf("XRecordEndOfData\n");
break;
default:
errx(1, "unknown reply category %d", reply->category);
break;
}
free(reply);
}
}
要生成XKB事件,我使用了来自libxkbcommon的“ interactive-x11”测试程序(请参见测试目录)。
两个程序都在相同的$ DISPLAY上运行时,我希望看到RECORD客户端报告XKEYBOARD事件。
这不会发生。即使我看到XInputExtension事件,也没有XKEYBOARD事件。
注意:快速浏览 -xorg-server-1.19.1 / record / record.c -xorg-server-1.19.1 / dix / events.c 找不到任何能解释我问题的东西。
所以:我的RECORD扩展名设置是否正确,还是RECORD扩展名不能与XKEYBOARD一起使用?