我目前正在为Linux进行延迟testing。 为了最大限度地减less副作用,我尝试写一个C程序,它可以直接用XCB访问X-Server。 因为在C语言方面没有任何经验,只有Java和XCB,所以遇到了一些困难。
应用程序应该做的所有事情是显示一个白色的框架,并且如果在任何时候(在窗口之外)按下鼠标的button,它应该瞬间变成黑色。 testing应用程序不必以任何方式美观或安全,只是反应快。 它只是用于这一个testing(请不要判断我的蹩脚的风格;-))。
鼠标不能在同一个窗口中,因为还有另一个独立的应用程序需要处理事件(测量延迟的事件)。
阅读XCB教程后,我修改了示例代码以打开一个窗口并在窗口中logging鼠标点击:
#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
variables更改为根窗口。 但是我尝试的任何东西都会产生分割错误,或者根本无法工作。
也许一个根(我的应用程序)的孩子没有足够的权利获得它的父母的事件? 但是,如何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);
我如何修改上面的代码来对整个X.Org-Server上的所有BUTTON_PRESS事件做出反应?
所以,如果你想捕捉所有的按钮事件,我只是一个解决方案,但我不知道这是否可以满足您的需求。
它像一个小窗口管理器这里是4个文件:
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进行测试。
这是我知道得到所有事件的唯一途径。 我不是专家,我希望这可以帮助你。