XCB的事件处理如何检测C中的ESC键?
How does XCB's event handling detect the ESC key in C?
我一直在学习 XCB 教程,但我一直卡在这个教程上。在此示例中,程序在您按下 ESC
键时退出。但是在示例代码中,我无法弄清楚 "case 9" 是如何捕获 ESC
键的。我搜索并查看了 xcb.h
和 xproto.h
,以及 ASCII table.
我以为我明白了,直到我"case 9"。这是我完全迷路的地方。所以基本上,他们从哪里得到 9?那如何对应 ESC
?
这是我正在研究的示例代码:
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <xcb/xcb.h>
#define WIDTH 300
#define HEIGHT 100
static xcb_gc_t gc_font_get (xcb_connection_t *c,
xcb_screen_t *screen,
xcb_window_t window,
const char *font_name);
static void text_draw (xcb_connection_t *c,
xcb_screen_t *screen,
xcb_window_t window,
int16_t x1,
int16_t y1,
const char *label)
{
xcb_void_cookie_t cookie_gc;
xcb_void_cookie_t cookie_text;
xcb_generic_error_t *error;
xcb_gcontext_t gc;
uint8_t length;
length = strlen (label);
gc = gc_font_get(c, screen, window, "7x13");
cookie_text = xcb_image_text_8_checked (c, length, window, gc,
x1,
y1, label);
error = xcb_request_check (c, cookie_text);
if (error) {
fprintf (stderr, "ERROR: can't paste text : %d\n", error->error_code);
xcb_disconnect (c);
exit (-1);
}
cookie_gc = xcb_free_gc (c, gc);
error = xcb_request_check (c, cookie_gc);
if (error) {
fprintf (stderr, "ERROR: can't free gc : %d\n", error->error_code);
xcb_disconnect (c);
exit (-1);
}
}
static xcb_gc_t gc_font_get (xcb_connection_t *c,
xcb_screen_t *screen,
xcb_window_t window,
const char *font_name)
{
uint32_t value_list[3];
xcb_void_cookie_t cookie_font;
xcb_void_cookie_t cookie_gc;
xcb_generic_error_t *error;
xcb_font_t font;
xcb_gcontext_t gc;
uint32_t mask;
font = xcb_generate_id (c);
cookie_font = xcb_open_font_checked (c, font,
strlen (font_name),
font_name);
error = xcb_request_check (c, cookie_font);
if (error) {
fprintf (stderr, "ERROR: can't open font : %d\n", error->error_code);
xcb_disconnect (c);
return -1;
}
gc = xcb_generate_id (c);
mask = XCB_GC_FOREGROUND | XCB_GC_BACKGROUND | XCB_GC_FONT;
value_list[0] = screen->black_pixel;
value_list[1] = screen->white_pixel;
value_list[2] = font;
cookie_gc = xcb_create_gc_checked (c, gc, window, mask, value_list);
error = xcb_request_check (c, cookie_gc);
if (error) {
fprintf (stderr, "ERROR: can't create gc : %d\n", error->error_code);
xcb_disconnect (c);
exit (-1);
}
cookie_font = xcb_close_font_checked (c, font);
error = xcb_request_check (c, cookie_font);
if (error) {
fprintf (stderr, "ERROR: can't close font : %d\n", error->error_code);
xcb_disconnect (c);
exit (-1);
}
return gc;
}
int main ()
{
xcb_screen_iterator_t screen_iter;
xcb_connection_t *c;
const xcb_setup_t *setup;
xcb_screen_t *screen;
xcb_generic_event_t *e;
xcb_generic_error_t *error;
xcb_void_cookie_t cookie_window;
xcb_void_cookie_t cookie_map;
xcb_window_t window;
uint32_t mask;
uint32_t values[2];
int screen_number;
/* getting the connection */
c = xcb_connect (NULL, &screen_number);
if (!c) {
fprintf (stderr, "ERROR: can't connect to an X server\n");
return -1;
}
/* getting the current screen */
setup = xcb_get_setup (c);
screen = NULL;
screen_iter = xcb_setup_roots_iterator (setup);
for (; screen_iter.rem != 0; --screen_number, xcb_screen_next (&screen_iter))
if (screen_number == 0)
{
screen = screen_iter.data;
break;
}
if (!screen) {
fprintf (stderr, "ERROR: can't get the current screen\n");
xcb_disconnect (c);
return -1;
}
/* creating the window */
window = xcb_generate_id (c);
mask = XCB_CW_BACK_PIXEL | XCB_CW_EVENT_MASK;
values[0] = screen->white_pixel;
values[1] =
XCB_EVENT_MASK_KEY_RELEASE |
XCB_EVENT_MASK_BUTTON_PRESS |
XCB_EVENT_MASK_EXPOSURE |
XCB_EVENT_MASK_POINTER_MOTION;
cookie_window = xcb_create_window_checked (c,
screen->root_depth,
window, screen->root,
20, 200, WIDTH, HEIGHT,
0, XCB_WINDOW_CLASS_INPUT_OUTPUT,
screen->root_visual,
mask, values);
cookie_map = xcb_map_window_checked (c, window);
/* error managing */
error = xcb_request_check (c, cookie_window);
if (error) {
fprintf (stderr, "ERROR: can't create window : %d\n", error->error_code);
xcb_disconnect (c);
return -1;
}
error = xcb_request_check (c, cookie_map);
if (error) {
fprintf (stderr, "ERROR: can't map window : %d\n", error->error_code);
xcb_disconnect (c);
return -1;
}
xcb_flush(c);
while (1) {
e = xcb_poll_for_event(c);
if (e) {
switch (e->response_type & ~0x80) {
case XCB_EXPOSE: {
char *text;
text = "Press ESC key to exit...";
text_draw (c, screen, window, 10, HEIGHT - 10, text);
break;
}
case XCB_KEY_RELEASE: {
xcb_key_release_event_t *ev;
ev = (xcb_key_release_event_t *)e;
switch (ev->detail) {
/* ESC */
case 9:
free (e);
xcb_disconnect (c);
return 0;
}
}
}
free (e);
}
}
return 0;
}
谢谢
Low-level X KeyCode
s 位于 8..255 范围内,代表键盘的物理布局。大概在实践中值 9(“1”相对于范围的开始,即 upper-left)是 Esc 键。
话虽如此,hard-code device-specific 这样的知识而不是查找与 Esc KeySym
.[=13 相关联的键码似乎是一个非常糟糕的主意=]
这个link似乎提供了一些有用的信息:
I thought I understood it, until I got to "case 9". This was where I got totally lost. So basically, where do they get 9 from? And how does that correspond to ESC?
如果您打开终端 运行:
xev | grep keycode
然后你在弹出的xevwindow上按Esc键,你会看到:
state 0x0, keycode 9 (keysym 0xff1b, Escape), same_screen YES,
state 0x0, keycode 9 (keysym 0xff1b, Escape), same_screen YES,
你可以做一些疯狂的事情,比如使用 xmodmap 重新映射你的转义键,但它仍然是键码 9
,即使你将它映射到其他东西......使用 xmodmap 我将键码 9 重置为F1,但 xev 仍然可以看到我真的在使用 Escape 键(键码 9)
state 0x0, keycode 9 (keysym 0xffbe, F1), same_screen YES,
state 0x0, keycode 9 (keysym 0xffbe, F1), same_screen YES,
历史上为什么键码 9 是 Escape 键?
如果你运行:
showkey --ascii
# press the Escape key
^[ 27 0033 0x1b
您看到 Escape 映射到 ASCII table 上的 27
。
同时获取钥匙的“扫描码”:
sudo showkey --scancodes
# press the Escape key
^[ 0x01 0x81
由于您在本教程中使用的是 xcb,并且必须考虑的只有 Xcb/X11,因此代码 9 将始终是硬件退出键。
您可以使用 setkeycodes
(kbd
包)设置扫描码以映射到 Linux 中的其他键码,但这些代码不会被 X 拾取。
根据您正在操作的层 (USB hardware/kernel/X11),您需要为适当的密钥选择适当的标识符。
我相信@s0s 所指的教程可在线获取:
我一直在学习 XCB 教程,但我一直卡在这个教程上。在此示例中,程序在您按下 ESC
键时退出。但是在示例代码中,我无法弄清楚 "case 9" 是如何捕获 ESC
键的。我搜索并查看了 xcb.h
和 xproto.h
,以及 ASCII table.
我以为我明白了,直到我"case 9"。这是我完全迷路的地方。所以基本上,他们从哪里得到 9?那如何对应 ESC
?
这是我正在研究的示例代码:
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <xcb/xcb.h>
#define WIDTH 300
#define HEIGHT 100
static xcb_gc_t gc_font_get (xcb_connection_t *c,
xcb_screen_t *screen,
xcb_window_t window,
const char *font_name);
static void text_draw (xcb_connection_t *c,
xcb_screen_t *screen,
xcb_window_t window,
int16_t x1,
int16_t y1,
const char *label)
{
xcb_void_cookie_t cookie_gc;
xcb_void_cookie_t cookie_text;
xcb_generic_error_t *error;
xcb_gcontext_t gc;
uint8_t length;
length = strlen (label);
gc = gc_font_get(c, screen, window, "7x13");
cookie_text = xcb_image_text_8_checked (c, length, window, gc,
x1,
y1, label);
error = xcb_request_check (c, cookie_text);
if (error) {
fprintf (stderr, "ERROR: can't paste text : %d\n", error->error_code);
xcb_disconnect (c);
exit (-1);
}
cookie_gc = xcb_free_gc (c, gc);
error = xcb_request_check (c, cookie_gc);
if (error) {
fprintf (stderr, "ERROR: can't free gc : %d\n", error->error_code);
xcb_disconnect (c);
exit (-1);
}
}
static xcb_gc_t gc_font_get (xcb_connection_t *c,
xcb_screen_t *screen,
xcb_window_t window,
const char *font_name)
{
uint32_t value_list[3];
xcb_void_cookie_t cookie_font;
xcb_void_cookie_t cookie_gc;
xcb_generic_error_t *error;
xcb_font_t font;
xcb_gcontext_t gc;
uint32_t mask;
font = xcb_generate_id (c);
cookie_font = xcb_open_font_checked (c, font,
strlen (font_name),
font_name);
error = xcb_request_check (c, cookie_font);
if (error) {
fprintf (stderr, "ERROR: can't open font : %d\n", error->error_code);
xcb_disconnect (c);
return -1;
}
gc = xcb_generate_id (c);
mask = XCB_GC_FOREGROUND | XCB_GC_BACKGROUND | XCB_GC_FONT;
value_list[0] = screen->black_pixel;
value_list[1] = screen->white_pixel;
value_list[2] = font;
cookie_gc = xcb_create_gc_checked (c, gc, window, mask, value_list);
error = xcb_request_check (c, cookie_gc);
if (error) {
fprintf (stderr, "ERROR: can't create gc : %d\n", error->error_code);
xcb_disconnect (c);
exit (-1);
}
cookie_font = xcb_close_font_checked (c, font);
error = xcb_request_check (c, cookie_font);
if (error) {
fprintf (stderr, "ERROR: can't close font : %d\n", error->error_code);
xcb_disconnect (c);
exit (-1);
}
return gc;
}
int main ()
{
xcb_screen_iterator_t screen_iter;
xcb_connection_t *c;
const xcb_setup_t *setup;
xcb_screen_t *screen;
xcb_generic_event_t *e;
xcb_generic_error_t *error;
xcb_void_cookie_t cookie_window;
xcb_void_cookie_t cookie_map;
xcb_window_t window;
uint32_t mask;
uint32_t values[2];
int screen_number;
/* getting the connection */
c = xcb_connect (NULL, &screen_number);
if (!c) {
fprintf (stderr, "ERROR: can't connect to an X server\n");
return -1;
}
/* getting the current screen */
setup = xcb_get_setup (c);
screen = NULL;
screen_iter = xcb_setup_roots_iterator (setup);
for (; screen_iter.rem != 0; --screen_number, xcb_screen_next (&screen_iter))
if (screen_number == 0)
{
screen = screen_iter.data;
break;
}
if (!screen) {
fprintf (stderr, "ERROR: can't get the current screen\n");
xcb_disconnect (c);
return -1;
}
/* creating the window */
window = xcb_generate_id (c);
mask = XCB_CW_BACK_PIXEL | XCB_CW_EVENT_MASK;
values[0] = screen->white_pixel;
values[1] =
XCB_EVENT_MASK_KEY_RELEASE |
XCB_EVENT_MASK_BUTTON_PRESS |
XCB_EVENT_MASK_EXPOSURE |
XCB_EVENT_MASK_POINTER_MOTION;
cookie_window = xcb_create_window_checked (c,
screen->root_depth,
window, screen->root,
20, 200, WIDTH, HEIGHT,
0, XCB_WINDOW_CLASS_INPUT_OUTPUT,
screen->root_visual,
mask, values);
cookie_map = xcb_map_window_checked (c, window);
/* error managing */
error = xcb_request_check (c, cookie_window);
if (error) {
fprintf (stderr, "ERROR: can't create window : %d\n", error->error_code);
xcb_disconnect (c);
return -1;
}
error = xcb_request_check (c, cookie_map);
if (error) {
fprintf (stderr, "ERROR: can't map window : %d\n", error->error_code);
xcb_disconnect (c);
return -1;
}
xcb_flush(c);
while (1) {
e = xcb_poll_for_event(c);
if (e) {
switch (e->response_type & ~0x80) {
case XCB_EXPOSE: {
char *text;
text = "Press ESC key to exit...";
text_draw (c, screen, window, 10, HEIGHT - 10, text);
break;
}
case XCB_KEY_RELEASE: {
xcb_key_release_event_t *ev;
ev = (xcb_key_release_event_t *)e;
switch (ev->detail) {
/* ESC */
case 9:
free (e);
xcb_disconnect (c);
return 0;
}
}
}
free (e);
}
}
return 0;
}
谢谢
Low-level X KeyCode
s 位于 8..255 范围内,代表键盘的物理布局。大概在实践中值 9(“1”相对于范围的开始,即 upper-left)是 Esc 键。
话虽如此,hard-code device-specific 这样的知识而不是查找与 Esc KeySym
.[=13 相关联的键码似乎是一个非常糟糕的主意=]
这个link似乎提供了一些有用的信息:
I thought I understood it, until I got to "case 9". This was where I got totally lost. So basically, where do they get 9 from? And how does that correspond to ESC?
如果您打开终端 运行:
xev | grep keycode
然后你在弹出的xevwindow上按Esc键,你会看到:
state 0x0, keycode 9 (keysym 0xff1b, Escape), same_screen YES,
state 0x0, keycode 9 (keysym 0xff1b, Escape), same_screen YES,
你可以做一些疯狂的事情,比如使用 xmodmap 重新映射你的转义键,但它仍然是键码 9
,即使你将它映射到其他东西......使用 xmodmap 我将键码 9 重置为F1,但 xev 仍然可以看到我真的在使用 Escape 键(键码 9)
state 0x0, keycode 9 (keysym 0xffbe, F1), same_screen YES,
state 0x0, keycode 9 (keysym 0xffbe, F1), same_screen YES,
历史上为什么键码 9 是 Escape 键?
如果你运行:
showkey --ascii
# press the Escape key
^[ 27 0033 0x1b
您看到 Escape 映射到 ASCII table 上的 27
。
同时获取钥匙的“扫描码”:
sudo showkey --scancodes
# press the Escape key
^[ 0x01 0x81
由于您在本教程中使用的是 xcb,并且必须考虑的只有 Xcb/X11,因此代码 9 将始终是硬件退出键。
您可以使用 setkeycodes
(kbd
包)设置扫描码以映射到 Linux 中的其他键码,但这些代码不会被 X 拾取。
根据您正在操作的层 (USB hardware/kernel/X11),您需要为适当的密钥选择适当的标识符。
我相信@s0s 所指的教程可在线获取: