简体   繁体   English

XCB 的事件处理如何检测 C 中的 ESC 键?

[英]How does XCB's event handling detect the ESC key in C?

I've been studying an XCB tutorial, but I'm stuck on this one.我一直在学习 XCB 教程,但我一直坚持这个教程。 In this example, the program quits when you press the ESC key.在本例中,当您按ESC键时程序退出。 But in the example code, I can't figure out how "case 9" catches the ESC key.但是在示例代码中,我无法弄清楚“case 9”如何捕获ESC键。 I've searched and looked all through xcb.h and xproto.h , and the ASCII table.我已经搜索并查看了xcb.hxproto.h以及 ASCII 表。

I thought I understood it, until I got to "case 9".我以为我明白了,直到我到达“案例 9”。 This was where I got totally lost.这是我完全迷失的地方。 So basically, where do they get 9 from?所以基本上,他们从哪里得到 9? And how does that correspond to ESC ?这与ESC有何对应?

Here's the example code I was studying:这是我正在研究的示例代码:

#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;
}

Thanks谢谢

Low-level X KeyCode s lie in the range 8..255 and represent the physical layout of the keyboard.低级 X KeyCode位于 8..255 范围内,代表键盘的物理布局。 Presumably in practice the value 9 ("1" relative to the start of the range, ie upper-left) is the Esc key.大概在实践中值 9(“1”相对于范围的开始,即左上角)是Esc键。

With that said, it seems like a really bad idea to hard-code device-specific knowledge like this rather than looking up which keycode is associated with the Esc KeySym .话虽如此,像这样对特定于设备的知识进行硬编码而不是查找哪个键码与 Esc KeySym相关联,这似乎是一个非常糟糕的主意。

This link seems to provide some useful information:此链接似乎提供了一些有用的信息:

https://tronche.com/gui/x/xlib/input/keyboard-encoding.html https://tronche.com/gui/x/xlib/input/keyboard-encoding.html

I thought I understood it, until I got to "case 9".我以为我明白了,直到我到达“案例 9”。 This was where I got totally lost.这是我完全迷失的地方。 So basically, where do they get 9 from?所以基本上,他们从哪里得到 9? And how does that correspond to ESC?这与 ESC 有何对应关系?

If you open a terminal and run:如果您打开终端并运行:

xev | grep keycode

Then you press the Esc key on the xev window that pops up, you will see:然后你在弹出的 xev 窗口上按 Esc 键,你会看到:

    state 0x0, keycode 9 (keysym 0xff1b, Escape), same_screen YES,
    state 0x0, keycode 9 (keysym 0xff1b, Escape), same_screen YES,

You could do crazy stuff like use xmodmap to remap your escape key, but it would still be keycode 9 , even though you mapped it to something else... Using xmodmap I reset keycode 9 to be F1, but xev can still see that I'm really using the Escape key (keycode 9)你可以做一些疯狂的事情,比如使用 xmodmap 重新映射你的转义键,但它仍然是 keycode 9 ,即使你将它映射到其他东西......使用 xmodmap 我将 keycode 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,

Historically WHY is keycode 9 the Escape key?从历史上看,为什么键码 9 是 Escape 键?

If you run:如果你运行:

showkey --ascii
# press the Escape key
^[  27 0033 0x1b

You see that Escape maps to 27 on the ASCII table.您会看到 Escape 映射到 ASCII 表上的27 Meanwhile to grab the key's "Scancode":同时获取密钥的“扫描码”:

sudo showkey --scancodes
# press the Escape key
^[  0x01 0x81

Since you're working with xcb in this tutorial and only Xcb/X11 must be considered, Code 9 will always be the hardware Escape key.由于您在本教程中使用的是 xcb 并且只需要考虑 Xcb/X11,因此 Code 9 将始终是硬件 Escape 键。

You can use the setkeycodes ( kbd package) to set scancodes to map to other keycodes in Linux, but these codes WILL NOT be picked up by X.您可以使用setkeycodeskbd包)设置扫描码以映射到 Linux 中的其他键码,但这些代码不会被 X 获取。

Depending on the layer (USB hardware/kernel/X11) that you're operating at, you'll need to choose the appropriate identifier for the appropriate key.根据您操作的层(USB 硬件/内核/X11),您需要为适当的密钥选择适当的标识符。


I believe the tutorial that @s0s was referring to is available online at:我相信@s0s 所指的教程可在线获取:

https://www.x.org/releases/X11R7.5/doc/libxcb/tutorial/ https://www.x.org/releases/X11R7.5/doc/libxcb/tutorial/

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM