【问题标题】:How does XCB's event handling detect the ESC key in C?XCB 的事件处理如何检测 C 中的 ESC 键?
【发布时间】:2017-05-30 19:42:15
【问题描述】:

我一直在学习 XCB 教程,但我被困在了这个教程上。在本例中,当您按下ESC 键时程序退出。但在示例代码中,我无法弄清楚“case 9”如何捕获ESC 键。我已经搜索并查看了 xcb.hxproto.h 以及 ASCII 表。

我以为我明白了,直到我遇到“案例 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;
}

谢谢

【问题讨论】:

    标签: c events key xcb keyrelease


    【解决方案1】:

    低级 X KeyCodes 位于 8..255 范围内,代表键盘的物理布局。大概在实践中,值 9(相对于范围开始的“1”,即左上角)是 Esc 键。

    话虽如此,像这样对特定于设备的知识进行硬编码而不是查找与 Esc KeySym 关联的键码似乎是一个非常糟糕的主意。

    这个链接似乎提供了一些有用的信息:

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

    【讨论】:

      【解决方案2】:

      我以为我明白了,直到我遇到“案例 9”。这是我完全迷失的地方。所以基本上,他们从哪里得到 9?又是怎么对应ESC的呢?

      如果你打开一个终端并运行:

      xev | grep keycode
      

      然后你在弹出的xev窗口上按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,
      

      历史上为什么 keycode 9 是 Escape 键?

      如果你运行:

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

      您会看到 Escape 映射到 ASCII 表上的 27。 同时抓取钥匙的“扫描码”:

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

      由于您在本教程中使用的是 xcb,并且只需要考虑 Xcb/X11,因此 Code 9 将始终是硬件 Escape 键。

      您可以使用setkeycodeskbd 包)设置扫描码以映射到 Linux 中的其他键码,但这些码不会被 X 拾取。

      根据您正在操作的层(USB 硬件/内核/X11),您需要为适当的密钥选择适当的标识符。


      我相信@s0s 所指的教程可以在线获取:

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2014-10-31
        • 2010-09-18
        • 2013-04-18
        • 2013-07-04
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多