首页 文章

XCB获取所有窗口X.Org的事件

提问于
浏览
4

我目前正在为Linux进行延迟测试 . 为了最大限度地减少副作用,我尝试编写一个C程序,它直接使用XCB访问X-Server . 因为没有任何C语言经验,只有Java,也没有XCB,我遇到了一些困难 .

应用程序应该做的一切就是显示一个白框,如果在任何时候(窗口外)按下鼠标按钮,它应该瞬间变为黑色 . 测试应用程序不一定非常漂亮或安全,但只能快速反应 . 它仅用于这一项测试(请不要判断我的糟糕风格;-)) .

鼠标不能在同一窗口中,因为还有另一个独立的应用程序,它也需要处理事件(测量延迟的事件) .


阅读the XCB tutorial后,我修改了示例代码以打开一个窗口并在窗口内记录鼠标单击:

#include <stdio.h>
#include <xcb/xcb.h>

main ()
{
    /* Open the connection to the X server */
    xcb_connection_t *connection = xcb_connect (NULL, NULL);

    /* Get the first screen */
    xcb_screen_t *screen = xcb_setup_roots_iterator (xcb_get_setup (connection)).data;

    /* Create black (foreground) graphic context */
    xcb_drawable_t  window;
    uint32_t        mask;
    uint32_t        values[2];

    /* Create a window */
    window = xcb_generate_id (connection);

    mask = XCB_CW_BACK_PIXEL | XCB_CW_EVENT_MASK;
    values[0] = screen->white_pixel;
    values[1] = XCB_EVENT_MASK_BUTTON_PRESS;

    xcb_create_window (connection, XCB_COPY_FROM_PARENT, window, screen->root, 0, 0, 500, 500, 10, XCB_WINDOW_CLASS_INPUT_OUTPUT, screen->root_visual, mask, values );

    /* Map the window on the screen and flush*/
    xcb_map_window (connection, window);
    xcb_flush (connection);

    /* Get XCB_EVENT_MASK_BUTTON_PRESS event */
    xcb_generic_event_t *event;
    while ((event = xcb_wait_for_event (connection))) {
        switch (event ->response_type & ~0x80) {
        case XCB_EVENT_MASK_BUTTON_PRESS:
            printf("Button pressed!\n");
            break;
        default: 
            /* Unknown event type */
            printf("Unknown event!\n");
            break;
        }
        /* free (event); */
    }
    return 0;
}

为了获取所有窗口的事件,我想我必须将 window 变量更改为根窗口 . 但是我尝试的任何东西都会产生分段错误,或者根本不起作用 .

也许root的孩子(我的申请)没有足够的权利来获取它的父母的事件?但是 xwininfo -root 如何工作呢?最佳尝试:

xcb_connection_t *connection = xcb_connect (NULL, NULL);
xcb_screen_t *screen = xcb_setup_roots_iterator (xcb_get_setup (connection)).data;
xcb_drawable_t window = screen->root; /* !!! */
uint32_t mask = XCB_CW_BACK_PIXEL | XCB_CW_EVENT_MASK;
uint32_t values[2];
values[0] = screen->white_pixel;
values[1] = XCB_EVENT_MASK_BUTTON_PRESS;
xcb_change_window_attributes (connection, window, mask, values); /* !!! */
xcb_map_window (connection, window);
xcb_flush (connection);

How do I have to change the above code to react to all BUTTON_PRESS events on the whole X.Org-Server?

1 回答

  • 5

    因此,如果您想捕获所有按钮事件,我只有一个解决方案,但我不知道这是否适合您的需求 .

    它像一个小窗口管理器这里是4个文件:

    • simple_window_manager.c

    • events.c

    • events.h

    • Makefile

    simple_window_manager.c

    #include <xcb/xcb.h>
    #include <xcb/xcb_event.h>
    #include <xcb/xcb_aux.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include "events.h"
    
    xcb_connection_t * connection;
    
    int main (int argc, char **argv)
    {
      xcb_screen_t      *screen;
    
      /*open connection and check for error*/
      connection = xcb_connect( NULL, NULL);
    
      printf("launch connection");
    
        if (xcb_connection_has_error(connection))
      {
        perror("cannot open display\n");
        exit(1);
      }
    
      /*get first screen*/
      screen = xcb_setup_roots_iterator(xcb_get_setup(connection)).data;
    
      /*define the application as window manager*/
        const uint32_t select_input_val[] =
        {
            XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT | XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY
            | XCB_EVENT_MASK_ENTER_WINDOW | XCB_EVENT_MASK_LEAVE_WINDOW
            | XCB_EVENT_MASK_STRUCTURE_NOTIFY | XCB_EVENT_MASK_PROPERTY_CHANGE
            | XCB_EVENT_MASK_BUTTON_PRESS | XCB_EVENT_MASK_BUTTON_RELEASE
            | XCB_EVENT_MASK_FOCUS_CHANGE
        };
        xcb_change_window_attributes(connection,
                                     screen->root,
                                     XCB_CW_EVENT_MASK, select_input_val);
        /* Need to xcb_flush to validate error handler */
      xcb_aux_sync(connection);
    
        if (xcb_poll_for_event(connection) != NULL)
        {
            perror("another window manager is already running");
            exit(1);
        };
    
      /*flush all request*/
      xcb_flush(connection);
    
      xcb_generic_event_t *the_events;
      int done; 
    
        /*enter the main loop*/
      done = 0;
      while (!done && (the_events = xcb_wait_for_event(connection)))
      {
        switch(the_events->response_type)
        {
          /*(re)draw the window*/
          case XCB_EXPOSE:
            printf ("EXPOSE\n");
            break;
          /*exit on keypress*/
          case XCB_KEY_PRESS:
            done = 1;
            break;
          default:
            event_management(the_events);
            printf("The events = %s\n",xcb_event_get_label(the_events->response_type));
        }
        free(the_events);
      }
      /*close connection to server*/
      xcb_disconnect(connection);
      return 0;
    }
    

    events.c

    #include <stdio.h>
    #include <stdlib.h>
    #include <xcb/xcb.h>
    #include <xcb/xcb_util.h>
    #include "events.h"
    
    
    static void button_press_management(xcb_button_press_event_t * event)
    {
        printf("event = %s\n",xcb_event_get_label(event->response_type));   
    }
    static void button_release_management(xcb_button_release_event_t * event)
    {
        printf("event = %s\n",xcb_event_get_label(event->response_type));   
    }
    static void configure_request_management(xcb_configure_request_event_t * event)
    {
        uint16_t config_win_mask = 0;
      uint32_t config_win_vals[7];
      unsigned short i = 0;
    
    if(event->value_mask & XCB_CONFIG_WINDOW_X)
        {
            config_win_mask |= XCB_CONFIG_WINDOW_X;
            config_win_vals[i++] = 300;
            printf(" XCB_CONFIG_WINDOW_X\n");
        }
        if(event->value_mask & XCB_CONFIG_WINDOW_Y)
        {
            config_win_mask |= XCB_CONFIG_WINDOW_Y;
            config_win_vals[i++] = 300;
            printf(" XCB_CONFIG_WINDOW_Y\n");
        }
        if(event->value_mask & XCB_CONFIG_WINDOW_WIDTH)
        {
            config_win_mask |= XCB_CONFIG_WINDOW_WIDTH;
            config_win_vals[i++] = event->width;
            printf(" XCB_CONFIG_WINDOW_WIDTH\n");
        }
        if(event->value_mask & XCB_CONFIG_WINDOW_HEIGHT)
        {
            config_win_mask |= XCB_CONFIG_WINDOW_HEIGHT;
            config_win_vals[i++] = event->height;
            printf("XCB_CONFIG_WINDOW_HEIGHT");
        }
        if(event->value_mask & XCB_CONFIG_WINDOW_BORDER_WIDTH)
        {
            config_win_mask |= XCB_CONFIG_WINDOW_BORDER_WIDTH;
            config_win_vals[i++] = event->border_width;
            printf(" XCB_CONFIG_WINDOW_BORDER_WIDTH\n");
        }
        if(event->value_mask & XCB_CONFIG_WINDOW_SIBLING)
        {
            config_win_mask |= XCB_CONFIG_WINDOW_SIBLING;
            config_win_vals[i++] = event->sibling;
            printf(" XCB_CONFIG_WINDOW_SIBLING\n");
        }
        if(event->value_mask & XCB_CONFIG_WINDOW_STACK_MODE)
        {
            config_win_mask |= XCB_CONFIG_WINDOW_STACK_MODE;
            config_win_vals[i++] = event->stack_mode;
            printf(" XCB_CONFIG_WINDOW_STACK_MODE\n");
        }
    
      xcb_configure_window(connection, event->window, config_win_mask, config_win_vals);
      xcb_flush(connection);
        printf("event = %s\n",xcb_event_get_label(event->response_type));   
    }
    static void client_message_management(xcb_client_message_event_t * event)
    {
        printf("event = %s\n",xcb_event_get_label(event->response_type));   
    }
    static void expose_management(xcb_expose_event_t *event)
    {
            printf("event = %s\n",xcb_event_get_label(event->response_type));   
    }
    static void focus_in_management(xcb_focus_in_event_t *event)
    {
        printf("event = %s\n",xcb_event_get_label(event->response_type));   
    }
    static void key_press_management(xcb_key_press_event_t *event)
    {
    
        printf("event = %s\n",xcb_event_get_label(event->response_type));   
    }
    static void key_release_management(xcb_key_release_event_t *event)
    {
        printf("event = %s\n",xcb_event_get_label(event->response_type));   
    }
    static void motion_notify_management(xcb_motion_notify_event_t * event)
    {
        printf("event = %s\n",xcb_event_get_label(event->response_type));   
    }
    static void map_request_management(xcb_map_request_event_t * event)
    {
      xcb_map_window(connection, event->window);
      xcb_flush(connection);
      xcb_grab_button(connection,0, event->window,XCB_EVENT_MASK_BUTTON_PRESS, XCB_GRAB_MODE_ASYNC, XCB_GRAB_MODE_ASYNC, XCB_NONE, XCB_NONE, XCB_BUTTON_INDEX_ANY, XCB_MOD_MASK_ANY);
        printf("event = %s\n",xcb_event_get_label(event->response_type));   
    }
    static void mapping_notify_management(xcb_motion_notify_event_t * event)
    {
        printf("event = %s\n",xcb_event_get_label(event->response_type));   
    }
    static void reparent_notify_management(xcb_reparent_notify_event_t * event)
    {
    
        printf("event = %s\n",xcb_event_get_label(event->response_type));   
    }
    static void unmap_notify_management(xcb_unmap_notify_event_t * event)
    {
    
        printf("event = %s\n",xcb_event_get_label(event->response_type));   
    }
    static void enter_notify_management(xcb_enter_notify_event_t * event)
    {
        printf("event = %s\n",xcb_event_get_label(event->response_type));   
    }
    static void leave_notify_management(xcb_leave_notify_event_t * event)
    {
        printf("event = %s\n",xcb_event_get_label(event->response_type));   
    }
    
    void event_management(xcb_generic_event_t *event)
    {   
        uint8_t response_type = XCB_EVENT_RESPONSE_TYPE(event);
    
        if(response_type == 0)
            {
          /* This is an error, not a event */
          perror("response_type = 0");
          return;
          }
    
        switch(response_type)
            {
                case XCB_BUTTON_PRESS:
                    button_press_management((void *) event);
                    break;
                case XCB_BUTTON_RELEASE:
                    button_release_management((void *)event);
                    break;
                case XCB_CONFIGURE_REQUEST:
                    configure_request_management((void *)event);
                    break;
                case XCB_CLIENT_MESSAGE:
                    client_message_management((void *)event);
                    break;
                case XCB_EXPOSE:
                    expose_management((void *)event);
                    break;
                case XCB_FOCUS_IN:
                    focus_in_management((void *)event);
                    break;
                case XCB_KEY_PRESS:
                    key_press_management((void *)event);
                    break;
                case XCB_KEY_RELEASE:
                    key_release_management((void *)event);
                    break;
                case XCB_MAP_REQUEST:
                    map_request_management((void *)event);
                    break;
                case XCB_MAPPING_NOTIFY:
                    mapping_notify_management((void *)event);
                    break;case XCB_MOTION_NOTIFY:
                    motion_notify_management((void *)event);
                    break;
                case XCB_REPARENT_NOTIFY:
                    reparent_notify_management((void *)event);
                    break;
                case XCB_UNMAP_NOTIFY:
                    unmap_notify_management((void *)event);
                    break;
                case XCB_ENTER_NOTIFY:
                    enter_notify_management((void *)event);
                    break;
                case XCB_LEAVE_NOTIFY:
                    leave_notify_management((void *)event);
                    break;
                default:
                    printf("event = %s\n",xcb_event_get_label(event->response_type));   
                    printf("%d\n",response_type);
                    perror("this kind of event is not managed\n");
                    break;
            }
    }
    

    events.h

    #include <xcb/xcb.h>
    extern xcb_connection_t * connection;
    void event_management(xcb_generic_event_t *);
    

    Makefile文件

    CC = gcc 
    CFLAGS = -Wall
    EXEC_NAME = simple_window_manager 
    INCLUDES = 
    LIBS =-lxcb -lxcb-util
    OBJ_FILES = simple_window_manager.o events.o
    INSTALL_DIR = ./my_exec/
    
    all : $(EXEC_NAME)
    clean :
        rm $(EXEC_NAME) $(OBJ_FILES)
    
    $(EXEC_NAME) : $(OBJ_FILES)
        $(CC) -o $(EXEC_NAME) $(OBJ_FILES) $(LIBS)
    
    %.o: %.c
        $(CC) $(CFLAGS) $(INCLUDES) -o $@ -c $<
    
    install :
        cp $(EXEC_NAME) $(INSTALL_DIR)$(EXEC_NAME)
    

    复制这4个文件,运行

    Makefile
    

    然后在shell会话中尝试这个(我将解释为什么之后):

    Xephyr -br -noreset -screen "1024x640" :1&
    DISPLAY=:1.0 ./simple_window_manager&
    DISPLAY=:1.0 gnome-calculator #for example
    

    为了将所有事件都发送到根窗口,您必须配置根窗口,就像您的应用程序是窗口管理器一样 . 但它只能是一个窗口管理器,这就是为什么simple_window_manager不能在gnome或kde下运行的原因 . 你必须使用Xephyr进行测试 .

    这是我知道获得所有活动的唯一方式 . 我不是专家,我希望这可以帮到你 .

相关问题