利用XCB编写X Window措施(三) 捕捉并响应事件(Event)
当前位置:以往代写 > C/C++ 教程 >利用XCB编写X Window措施(三) 捕捉并响应事件(Event)
2019-06-13

利用XCB编写X Window措施(三) 捕捉并响应事件(Event)

利用XCB编写X Window措施(三) 捕捉并响应事件(Event)

副标题#e#

GUI措施都是事件驱动的,今朝这已经是各人的共鸣,X Window也不破例。在这一篇中,将展示X焦点协议中有哪些事件,以及怎么利用XCB来捕捉并响应事件。首先照旧先给出一份完整的代码及其运行结果,然后再做具体的表明。代码如下:

1     #include <stdlib.h>
2 #include <stdio.h>
3 #include <inttypes.h>
4
5 #include <xcb/xcb.h>
6
7 /* print names of modifiers present in mask */
8 void
9 print_modifiers (uint32_t mask)
10 {
11 const char *MODIFIERS[] = {
12 "Shift", "Lock", "Ctrl", "Alt",
13 "Mod2", "Mod3", "Mod4", "Mod5",
14 "Button1", "Button2", "Button3", "Button4", "Button5"
15 };
16
17 printf ("Modifier mask: ");
18 for (const char **modifier = MODIFIERS ; mask; mask >>= 1, ++modifier) {
19 if (mask & 1) {
20 printf (*modifier);
21 }
22 }
23 printf ("\n");
24 }
25
26 int
27 main ()
28 {
29 /* Open the connection to the X server */
30 xcb_connection_t *connection = xcb_connect (NULL, NULL);
31
32 /* Get the first screen */
33 xcb_screen_t *screen = xcb_setup_roots_iterator (xcb_get_setup (connection)).data;
34
35
36 /* Create the window */
37 xcb_window_t window = xcb_generate_id (connection);
38
39 uint32_t mask = XCB_CW_BACK_PIXEL | XCB_CW_EVENT_MASK;
40 uint32_t values[2] = {screen->white_pixel,
41 XCB_EVENT_MASK_EXPOSURE | XCB_EVENT_MASK_BUTTON_PRESS |
42 XCB_EVENT_MASK_BUTTON_RELEASE | XCB_EVENT_MASK_POINTER_MOTION |
43 XCB_EVENT_MASK_ENTER_WINDOW | XCB_EVENT_MASK_LEAVE_WINDOW |
44 XCB_EVENT_MASK_KEY_PRESS | XCB_EVENT_MASK_KEY_RELEASE };
45
46 xcb_create_window (connection,
47 0, /* depth */
48 window,
49 screen->root, /* parent window */
50 0, 0, /* x, y */
51 600, 400, /* width, height */
52 10, /* border_width */
53 XCB_WINDOW_CLASS_INPUT_OUTPUT, /* class */
54 screen->root_visual, /* visual */
55 mask, values ); /* masks */
56
57 /* Map the window on the screen */
58 xcb_map_window (connection, window);
59
60 xcb_flush (connection);
61
62 xcb_generic_event_t *event;
63 while ( (event = xcb_wait_for_event (connection)) ) {
64 switch (event->response_type & ~0x80) {
65 case XCB_EXPOSE: {
66 xcb_expose_event_t *expose = (xcb_expose_event_t *)event;
67
68 printf ("Window %"PRIu32" exposed. Region to be redrawn at location (%"PRIu16",%"PRIu16"), with dimension (%"PRIu16",%"PRIu16")\n",
69 expose->window, expose->x, expose->y, expose->width, expose->height );
70 break;
71 }
72 case XCB_BUTTON_PRESS: {
73 xcb_button_press_event_t *bp = (xcb_button_press_event_t *)event;
74 print_modifiers (bp->state);
75
76 switch (bp->detail) {
77 case 4:
78 printf ("Wheel Button up in window %"PRIu32", at coordinates (%"PRIi16",%"PRIi16")\n",
79 bp->event, bp->event_x, bp->event_y );
80 break;
81 case 5:
82 printf ("Wheel Button down in window %"PRIu32", at coordinates (%"PRIi16",%"PRIi16")\n",
83 bp->event, bp->event_x, bp->event_y );
84 break;
85 default:
86 printf ("Button %"PRIu8" pressed in window %"PRIu32", at coordinates (%"PRIi16",%"PRIi16")\n",
87 bp->detail, bp->event, bp->event_x, bp->event_y );
88 break;
89 }
90 break;
91 }
92 case XCB_BUTTON_RELEASE: {
93 xcb_button_release_event_t *br = (xcb_button_release_event_t *)event;
94 print_modifiers(br->state);
95
96 printf ("Button %"PRIu8" released in window %"PRIu32", at coordinates (%"PRIi16",%"PRIi16")\n",
97 br->detail, br->event, br->event_x, br->event_y );
98 break;
99 }
100 case XCB_MOTION_NOTIFY: {
101 xcb_motion_notify_event_t *motion = (xcb_motion_notify_event_t *)event;
102
103 printf ("Mouse moved in window %"PRIu32", at coordinates (%"PRIi16",%"PRIi16")\n",
104 motion->event, motion->event_x, motion->event_y );
105 break;
106 }
107 case XCB_ENTER_NOTIFY: {
108 xcb_enter_notify_event_t *enter = (xcb_enter_notify_event_t *)event;
109
110 printf ("Mouse entered window %"PRIu32", at coordinates (%"PRIi16",%"PRIi16")\n",
111 enter->event, enter->event_x, enter->event_y );
112 break;
113 }
114 case XCB_LEAVE_NOTIFY: {
115 xcb_leave_notify_event_t *leave = (xcb_leave_notify_event_t *)event;
116
117 printf ("Mouse left window %"PRIu32", at coordinates (%"PRIi16",%"PRIi16")\n",
118 leave->event, leave->event_x, leave->event_y );
119 break;
120 }
121 case XCB_KEY_PRESS: {
122 xcb_key_press_event_t *kp = (xcb_key_press_event_t *)event;
123 print_modifiers(kp->state);
124
125 printf ("Key pressed in window %"PRIu32"\n",
126 kp->event);
127 break;
128 }
129 case XCB_KEY_RELEASE: {
130 xcb_key_release_event_t *kr = (xcb_key_release_event_t *)event;
131 print_modifiers(kr->state);
132
133 printf ("Key released in window %"PRIu32"\n",
134 kr->event);
135 break;
136 }
137 default:
138 /* Unknown event type, ignore it */
139 printf ("Unknown event: %"PRIu8"\n",
140 event->response_type);
141 break;
142 }
143
144 free (event);
145 }
146
147 return 0;
148 }


#p#副标题#e#

措施运行结果如下图:

操作XCB编写X Window法子(三) 捕获并响应事件(Event)

#p#副标题#e#

X Window措施处理惩罚事件遵循以下流程:

#p#分页标题#e#

1、建设窗口的时候向X处事器注册该措施需要处理惩罚哪些事件。这是为了效率方面的思量,对付本措施不体贴的事件,X Server就不消发过来了。在前面一篇建设gcontext的时候提到XCB利用一种非凡的mask、value数组的方法来向X Server指定gcontext的属性,建设window的时候也是利用这样一个mask、value数组的机制,只是mask和value的取值和gcontext纷歧样罢了;

2、在措施中利用一个while轮回,在轮回中挪用xcb_wait_for_event()函数来接管事件,也可以利用xcb_poll_for_event()函数来主动向X Server查询事件,接管到事件后,利用一个switch…case…来按照事件的范例处理惩罚相应的事件。假如接管到quit事件,则竣事while轮回,退出措施。

流程就是这么简朴,主要是一些细节。好比,建设窗口时,mask的取值可以是下面这些值的组合:

typedef enum {
        XCB_CW_BACK_PIXMAP       = 1L<<0,
        XCB_CW_BACK_PIXEL        = 1L<<1,
        XCB_CW_BORDER_PIXMAP     = 1L<<2,
        XCB_CW_BORDER_PIXEL      = 1L<<3,
        XCB_CW_BIT_GRAVITY       = 1L<<4,
        XCB_CW_WIN_GRAVITY       = 1L<<5,
        XCB_CW_BACKING_STORE     = 1L<<6,
        XCB_CW_BACKING_PLANES    = 1L<<7,
        XCB_CW_BACKING_PIXEL     = 1L<<8,
        XCB_CW_OVERRIDE_REDIRECT = 1L<<9,
        XCB_CW_SAVE_UNDER        = 1L<<10,
        XCB_CW_EVENT_MASK        = 1L<<11,
        XCB_CW_DONT_PROPAGATE    = 1L<<12,
        XCB_CW_COLORMAP          = 1L<<13,
        XCB_CW_CURSOR            = 1L<<14
    } xcb_cw_t;

当在mask中指定了XCB_CW_EVENT_MASK后,就需要在value数组中对应的项填写措施体贴的事件。措施存眷的事件可以是以下值的组合:

操作XCB编写X Window法子(三) 捕获并响应事件(Event)

#p#副标题#e#

这些列举值的界说都是很明晰的,所以这里不多做表明。

#p#分页标题#e#

对付事件对应的数据布局。假如抽闲到X.org翻看一下X11协议,会发明焦点协议中对事件的界说很简朴。所有事件的长度都是32字节,并且其第1个字节代表了事件的范例。所以,在措施中可以利用xcb_generic_event_t指针来生存从xcb_wait_for_event()函数返回的事件,然后按照event->response_type来抉择事件的范例,然后再将这个指针强制转型为其它事件的指针。

假如想相识各个事件的详细的数据布局,在Vim中只需要一个Ctrl+]就能跳到相应的界说处,如下图:

操作XCB编写X Window法子(三) 捕获并响应事件(Event)

最后,尚有一个处所需要说明,那就是措施中的 switch (event->response_type & ~0x80) 这一句,为什么response_type要和~0x80按位与呢?同样,翻一下X11协议就可以得到谜底。因为假如response_type的最高位为1,也就是事件号128~255代表该事件是其它措施利用SendEvent发送过来的。假如response_type的最高位为0,也就是事件号0~127代表该事件是X Server发送过来的。很显然,我们并不体贴事件的来历,只体贴事件的范例,所以,只需要知道response_type的低7位即可。别的,对付0~127这些数字,X焦点协议最多只会利用0~63,而64~127是为其它扩展保存的。再别的,XCB教程中说今朝只有33个事件需要处理惩罚,是不是很简朴呢?

作者:cnblogs 京山游侠

    关键字:

在线提交作业