void key_button_event(xcb_generic_event_t *evt, uint8_t event_type) { xcb_keysym_t keysym = XCB_NO_SYMBOL; xcb_button_t button = XCB_NONE; bool replay_event = false; uint16_t modfield = 0; uint16_t lockfield = num_lock | caps_lock | scroll_lock; parse_event(evt, event_type, &keysym, &button, &modfield); modfield &= ~lockfield & MOD_STATE_FIELD; if (keysym != XCB_NO_SYMBOL || button != XCB_NONE) { hotkey_t *hk = find_hotkey(keysym, button, modfield, event_type, &replay_event); if (hk != NULL) { run(hk->command, hk->sync); if (status_fifo != NULL) put_status(COMMAND_PREFIX, hk->command); } } switch (event_type) { case XCB_BUTTON_PRESS: case XCB_BUTTON_RELEASE: if (replay_event) xcb_allow_events(dpy, XCB_ALLOW_REPLAY_POINTER, XCB_CURRENT_TIME); else xcb_allow_events(dpy, XCB_ALLOW_SYNC_POINTER, XCB_CURRENT_TIME); break; case XCB_KEY_PRESS: case XCB_KEY_RELEASE: if (replay_event) xcb_allow_events(dpy, XCB_ALLOW_REPLAY_KEYBOARD, XCB_CURRENT_TIME); else xcb_allow_events(dpy, XCB_ALLOW_SYNC_KEYBOARD, XCB_CURRENT_TIME); break; } xcb_flush(dpy); }
bool QxtGlobalShortcutPrivate::nativeEventFilter(const QByteArray &eventType, void *message, long *result) { Q_UNUSED(result); if (eventType != "xcb_generic_event_t") return false; xcb_generic_event_t *event = reinterpret_cast<xcb_generic_event_t*>(message); if ((event->response_type & ~0x80) != XCB_KEY_PRESS) return false; xcb_key_press_event_t *keyPressEvent = reinterpret_cast<xcb_key_press_event_t *>(event); // Avoid keyboard freeze xcb_connection_t *xcbConnection = QX11Info::connection(); xcb_allow_events(xcbConnection, XCB_ALLOW_REPLAY_KEYBOARD, keyPressEvent->time); xcb_flush(xcbConnection); unsigned int keycode = keyPressEvent->detail; unsigned int keystate = 0; if (keyPressEvent->state & XCB_MOD_MASK_1) keystate |= XCB_MOD_MASK_1; if (keyPressEvent->state & XCB_MOD_MASK_CONTROL) keystate |= XCB_MOD_MASK_CONTROL; if (keyPressEvent->state & XCB_MOD_MASK_4) keystate |= XCB_MOD_MASK_4; if (keyPressEvent->state & XCB_MOD_MASK_SHIFT) keystate |= XCB_MOD_MASK_SHIFT; return activateShortcut(keycode, keystate); }
/** Handle the ButtonPress event */ static void handle_button_press(xcb_button_press_event_t *e) { NIL_LOG("event: mouse %d pressed: event %d, child %d (%d,%d)", e->detail, e->event, e->child, e->event_x, e->event_y); if (e->event == bar_.win) { if (click_bar(e->event_x)) { xcb_flush(nil_.con); } return; } /* click on client with modkey */ if (MOD_MASK_(e->state) == cfg_.mod_key) { mouse_evt_.client = find_client(e->child, &mouse_evt_.ws); if (!mouse_evt_.client) { NIL_ERR("no client %d", e->child); goto end; } NIL_LOG("button on win=%d", mouse_evt_.client->win); switch (e->detail) { case XCB_BUTTON_INDEX_3: mouse_evt_.mode = CURSOR_RESIZE; /* warp pointer to lower right */ mouse_evt_.x1 = mouse_evt_.client->x + mouse_evt_.client->w; mouse_evt_.y1 = mouse_evt_.client->y + mouse_evt_.client->h; xcb_warp_pointer(nil_.con, XCB_NONE, mouse_evt_.client->win, 0, 0, 0, 0, mouse_evt_.x1, mouse_evt_.y1); break; case XCB_BUTTON_INDEX_1: default: mouse_evt_.mode = CURSOR_MOVE; mouse_evt_.x1 = e->event_x; mouse_evt_.y1 = e->event_y; break; } /* take control of the pointer in the root window */ xcb_grab_pointer(nil_.con, 0, nil_.scr->root, XCB_EVENT_MASK_BUTTON_RELEASE | XCB_EVENT_MASK_BUTTON_MOTION, XCB_GRAB_MODE_ASYNC, XCB_GRAB_MODE_ASYNC, XCB_NONE, nil_.cursor[mouse_evt_.mode], XCB_CURRENT_TIME); xcb_flush(nil_.con); return; } end: /* if unhandled, forward the click to the application */ xcb_allow_events(nil_.con, XCB_ALLOW_REPLAY_POINTER, e->time); }
/** The button press event handler. * \param data The type of mouse event. * \param connection The connection to the X server. * \param ev The event. */ static int event_handle_button(void *data, xcb_connection_t *connection, xcb_button_press_event_t *ev) { int screen; const int nb_screen = xcb_setup_roots_length(xcb_get_setup(connection)); client_t *c; wibox_t *wibox; if(event_handle_mousegrabber(ev->root_x, ev->root_y, 1 << (ev->detail - 1 + 8))) return 0; /* ev->state is * button status (8 bits) + modifiers status (8 bits) * we don't care for button status that we get, especially on release, so * drop them */ ev->state &= 0x00ff; if((wibox = wibox_getbywin(ev->event)) || (wibox = wibox_getbywin(ev->child))) { /* If the wibox is child, then x,y are * relative to root window */ if(wibox->window == ev->child) { ev->event_x -= wibox->geometry.x; ev->event_y -= wibox->geometry.y; } /* Push the wibox */ luaA_object_push(globalconf.L, wibox); /* Duplicate the wibox */ lua_pushvalue(globalconf.L, -1); /* Handle the button event on it */ event_button_callback(ev, &wibox->buttons, -1, 1, NULL); /* then try to match a widget binding */ widget_t *w = widget_getbycoords(wibox->orientation, &wibox->widgets, wibox->geometry.width, wibox->geometry.height, &ev->event_x, &ev->event_y); if(w) { /* Push widget (the wibox is already on stack) */ luaA_object_push_item(globalconf.L, -1, w); /* Move widget before wibox */ lua_insert(globalconf.L, -2); event_button_callback(ev, &w->buttons, -2, 2, NULL); } else /* Remove the wibox, we did not use it */ lua_pop(globalconf.L, 1); } else if((c = client_getbywin(ev->event))) { luaA_object_push(globalconf.L, c); event_button_callback(ev, &c->buttons, -1, 1, NULL); xcb_allow_events(globalconf.connection, XCB_ALLOW_REPLAY_POINTER, XCB_CURRENT_TIME); } else if(ev->child == XCB_NONE) for(screen = 0; screen < nb_screen; screen++) if(xutil_screen_get(connection, screen)->root == ev->event) { event_button_callback(ev, &globalconf.buttons, 0, 0, NULL); return 0; } return 0; }
xcb_window_t Select_Window(xcb_connection_t *dpy, const xcb_screen_t *screen, int descend) { xcb_cursor_t cursor; xcb_generic_event_t *event; xcb_window_t target_win = XCB_WINDOW_NONE; xcb_window_t root = screen->root; int buttons = 0; xcb_generic_error_t *err; xcb_grab_pointer_cookie_t grab_cookie; xcb_grab_pointer_reply_t *grab_reply; /* Make the target cursor */ cursor = Create_Font_Cursor (dpy, XC_crosshair); /* Grab the pointer using target cursor, letting it room all over */ grab_cookie = xcb_grab_pointer (dpy, False, root, XCB_EVENT_MASK_BUTTON_PRESS | XCB_EVENT_MASK_BUTTON_RELEASE, XCB_GRAB_MODE_SYNC, XCB_GRAB_MODE_ASYNC, root, cursor, XCB_TIME_CURRENT_TIME); grab_reply = xcb_grab_pointer_reply (dpy, grab_cookie, &err); if (grab_reply->status != XCB_GRAB_STATUS_SUCCESS) Fatal_Error ("Can't grab the mouse."); /* Let the user select a window... */ while ((target_win == XCB_WINDOW_NONE) || (buttons != 0)) { /* allow one more event */ xcb_allow_events (dpy, XCB_ALLOW_SYNC_POINTER, XCB_TIME_CURRENT_TIME); xcb_flush (dpy); event = xcb_wait_for_event (dpy); switch (event->response_type & 0x7f) { case XCB_BUTTON_PRESS: { xcb_button_press_event_t *bp = (xcb_button_press_event_t *)event; if (target_win == XCB_WINDOW_NONE) { target_win = bp->child; /* window selected */ if (target_win == XCB_WINDOW_NONE) target_win = root; } buttons++; break; } case XCB_BUTTON_RELEASE: if (buttons > 0) /* there may have been some down before we started */ buttons--; break; default: /* just discard all other events */ break; } free (event); } xcb_ungrab_pointer (dpy, XCB_TIME_CURRENT_TIME); /* Done with pointer */ if (!descend || (target_win == root)) return (target_win); target_win = Find_Client (dpy, root, target_win); return (target_win); }
/** The button press event handler. * \param ev The event. */ static void event_handle_button(xcb_button_press_event_t *ev) { lua_State *L = globalconf_get_lua_State(); client_t *c; drawin_t *drawin; globalconf.timestamp = ev->time; { /* ev->state contains the state before the event. Compute the state * after the event for the mousegrabber. */ uint16_t state = ev->state, change = 1 << (ev->detail - 1 + 8); if (XCB_EVENT_RESPONSE_TYPE(ev) == XCB_BUTTON_PRESS) state |= change; else state &= ~change; if(event_handle_mousegrabber(ev->root_x, ev->root_y, state)) return; } /* ev->state is * button status (8 bits) + modifiers status (8 bits) * we don't care for button status that we get, especially on release, so * drop them */ ev->state &= 0x00ff; if((drawin = drawin_getbywin(ev->event)) || (drawin = drawin_getbywin(ev->child))) { /* If the drawin is child, then x,y are * relative to root window */ if(drawin->window == ev->child) { ev->event_x -= drawin->geometry.x + drawin->border_width; ev->event_y -= drawin->geometry.y + drawin->border_width; } /* Push the drawable */ luaA_object_push(L, drawin); luaA_object_push_item(L, -1, drawin->drawable); /* and handle the button raw button event */ event_emit_button(L, ev); lua_pop(L, 1); /* check if any button object matches */ event_button_callback(ev, &drawin->buttons, L, -1, 1, NULL); /* Either we are receiving this due to ButtonPress/Release on the root * window or because we grabbed the button on the window. In the later * case we have to call AllowEvents. * Use AsyncPointer instead of ReplayPointer so that the event is * "eaten" instead of being handled again on the root window. */ if(ev->child == XCB_NONE) xcb_allow_events(globalconf.connection, XCB_ALLOW_ASYNC_POINTER, ev->time); } else if((c = client_getbyframewin(ev->event)) || (c = client_getbywin(ev->event))) { /* For clicks inside of c->window, we get two events. Once because of a * passive grab on c->window and then again for c->frame_window. * Ignore the second event (identifiable by ev->child != XCB_NONE). */ if (ev->event != c->frame_window || ev->child == XCB_NONE) { luaA_object_push(L, c); if (c->window == ev->event) { /* Button event into the client itself (not titlebar), translate * into the frame window. */ ev->event_x += c->titlebar[CLIENT_TITLEBAR_LEFT].size; ev->event_y += c->titlebar[CLIENT_TITLEBAR_TOP].size; } /* And handle the button raw button event */ event_emit_button(L, ev); /* then check if a titlebar was "hit" */ if (c->frame_window == ev->event) { int x = ev->event_x, y = ev->event_y; drawable_t *d = client_get_drawable_offset(c, &x, &y); if (d) { /* Copy the event so that we can fake x/y */ xcb_button_press_event_t event = *ev; event.event_x = x; event.event_y = y; luaA_object_push_item(L, -1, d); event_emit_button(L, &event); lua_pop(L, 1); } } /* then check if any button objects match */ event_button_callback(ev, &c->buttons, L, -1, 1, NULL); } xcb_allow_events(globalconf.connection, XCB_ALLOW_REPLAY_POINTER, ev->time); } else if(ev->child == XCB_NONE) if(globalconf.screen->root == ev->event) { event_button_callback(ev, &globalconf.buttons, L, 0, 0, NULL); return; } }
int main(void) { xcb_connection_t *c; xcb_screen_t *s; xcb_window_t w; xcb_gcontext_t g; xcb_generic_event_t *e; uint32_t mask; uint32_t values[2]; int done = 0; /* open connection with the server */ c = xcb_connect(NULL,NULL); if (xcb_connection_has_error(c)) { printf("Cannot open display\n"); exit(1); } /* get the first screen */ s = xcb_setup_roots_iterator( xcb_get_setup(c) ).data; G.conn = c; G.s= s; //enable mouse event xcb_cursor_t cursor; xcb_font_t cursor_font=0; short glyph = 0x34; //cross xcb_grab_pointer_cookie_t grab_cookie; xcb_grab_pointer_reply_t *grab_reply; xcb_generic_error_t *err; cursor = xcb_generate_id (c); if (!cursor_font) { cursor_font = xcb_generate_id (c); xcb_open_font (c, cursor_font, strlen ("cursor"), "cursor"); } xcb_create_glyph_cursor (c, cursor, cursor_font, cursor_font, glyph, glyph + 1, 0, 0, 0, 0xffff, 0xffff, 0xffff); /* rgb, rgb */ grab_cookie = xcb_grab_pointer(c, 0, s->root, XCB_EVENT_MASK_POINTER_MOTION | XCB_EVENT_MASK_BUTTON_PRESS | XCB_EVENT_MASK_BUTTON_RELEASE, XCB_GRAB_MODE_SYNC, XCB_GRAB_MODE_ASYNC, s->root, cursor, XCB_TIME_CURRENT_TIME); assert(grab_reply!=NULL); grab_reply = xcb_grab_pointer_reply (c, grab_cookie, &err); if (grab_reply->status != XCB_GRAB_STATUS_SUCCESS) printf("Can't grab the mouse."); printf("grab pointer cookie=0x%x\n", grab_cookie); xcb_allow_events (c, XCB_ALLOW_ASYNC_POINTER, XCB_TIME_CURRENT_TIME); xcb_flush (c); // xcb_allow_events (c, XCB_ALLOW_SYNC_POINTER, XCB_TIME_CURRENT_TIME); xcb_flush (c); while (!done ) { e = xcb_wait_for_event(c); if(e==NULL) printf("wait event error\n"); //printf("\revent=>%d", e->response_type); switch (e->response_type & ~0x80) { case XCB_EXPOSE: /* draw or redraw the window */ printf("XCB_EXPOSE\n"); draw_gc(w); break; case XCB_MOTION_NOTIFY: { static xcb_window_t oldw; xcb_button_press_event_t *bp = (xcb_button_press_event_t *)e; w = bp->child; /* window selected */ if(oldw!=w){ oldw = w; printf("windowid = %x\n", w); } //draw it draw_gc(w); } break; case XCB_BUTTON_PRESS: { xcb_button_press_event_t *bp = (xcb_button_press_event_t *)e; w = bp->child; /* window selected */ if (w== XCB_WINDOW_NONE){ printf("window select is root\n"); w=s->root; } else printf("window = %x\n", w); draw_gc(w); done=1; printf("grab a child\n"); break; } } free(e); } xcb_ungrab_pointer(c, XCB_TIME_CURRENT_TIME); draw_byxid(w); return 0; #if 0 /* create window */ w = xcb_generate_id(c); mask = XCB_CW_BACK_PIXEL | XCB_CW_EVENT_MASK; values[0] = s->white_pixel; values[1] = XCB_EVENT_MASK_EXPOSURE | XCB_EVENT_MASK_KEY_PRESS; xcb_create_window(c, s->root_depth, w, s->root, 10, 10, 100, 100, 1, XCB_WINDOW_CLASS_INPUT_OUTPUT, s->root_visual, mask, values); /* map (show) the window */ xcb_map_window(c, w); xcb_flush(c); /* event loop */ while (!done && (e = xcb_wait_for_event(c))) { switch (e->response_type & ~0x80) { case XCB_EXPOSE: /* draw or redraw the window */ xcb_poly_fill_rectangle(c, w, g, 1, &r); xcb_flush(c); break; case XCB_KEY_PRESS: /* exit on key press */ //gwj done = 1; break; } free(e); } /* close connection to server */ xcb_disconnect(c); return 0; if(0){ //draw image with xcb_put_image // creat gc and draw to parent window xcb_gcontext_t g; g = xcb_generate_id(c); xcb_create_gc(c, g, child, 0,NULL); //xcb_poly_fill_rectangle(c, w, g, 1, &r); xcb_flush(c); int psize=geo->width * geo->height* (geo->depth/8); uint8_t *pbuf = malloc(psize); xcb_void_cookie_t ck; printf("malloc pbuf=0x%x size=%d\n",pbuf, psize); memset(pbuf, 0x18, psize); ck = xcb_put_image_checked(c, XCB_IMAGE_FORMAT_Z_PIXMAP, child, g, geo->width, geo->height , 0, 0, 0, geo->depth, psize, pbuf); //BadMatch=8 BadLength=16 xcb_generic_error_t *err; err = xcb_request_check (c, ck); if (err) { int code = err->error_code; free (err); printf("put image error %d\n", code); assert (code != 0); } } printf("depth =%d\n", geo->depth); /* create black graphics context */ #endif }
bool ZealNativeEventFilter::nativeEventFilter(const QByteArray &eventType, void *message, long *result) { enabled = true; #ifdef WIN32 MSG* msg = static_cast<MSG*>(message); if(WM_HOTKEY == msg->message && msg->wParam == 10) { emit gotHotKey(); return true; } #elsif LINUX // WIN32 or LINUX xcb_generic_event_t* ev = static_cast<xcb_generic_event_t*>(message); if(((ev->response_type&127) == XCB_KEY_PRESS || (ev->response_type&127) == XCB_KEY_RELEASE) && !hotKey.isEmpty()) { // XCB_KEY_RELEASE must be ignored by Qt because otherwise it causes SIGSEGV in QXcbKeyboard::handleKeyReleaseEvent xcb_connection_t *c = static_cast<xcb_connection_t*>( ((QGuiApplication*)QGuiApplication::instance())-> platformNativeInterface()->nativeResourceForWindow("connection", 0)); xcb_key_press_event_t *event = (xcb_key_press_event_t *)ev; xcb_key_symbols_t *keysyms = xcb_key_symbols_alloc(c); xcb_keycode_t *keycodes = xcb_key_symbols_get_keycode(keysyms, GetX11Key(hotKey[0])); bool found = false; // found=true means either (a) complete hotkey was pressed, or (b) any of its separate // keys was released. We return true in both cases, because key releases while window // is not present cause SIGSEGV in QXcbKeyboard::handleKeyReleaseEvent if((ev->response_type&127) == XCB_KEY_RELEASE) { QList<QPair<int, Qt::Modifier> > modifiers; modifiers.append(qMakePair(XK_Alt_L, Qt::ALT)); modifiers.append(qMakePair(XK_Alt_R, Qt::ALT)); modifiers.append(qMakePair(XK_Control_L, Qt::CTRL)); modifiers.append(qMakePair(XK_Control_R, Qt::CTRL)); modifiers.append(qMakePair(XK_Meta_L, Qt::META)); modifiers.append(qMakePair(XK_Meta_R, Qt::META)); for(auto modifier : modifiers) { if(!(hotKey[0] & modifier.second)) { continue; } xcb_keycode_t *mod_keycodes = xcb_key_symbols_get_keycode(keysyms, modifier.first); if(mod_keycodes == nullptr) continue; int i = 0; while(mod_keycodes[i] != XCB_NO_SYMBOL) { if(event->detail == mod_keycodes[i]) { found = true; } i += 1; } free(mod_keycodes); } } int i = 0; while(keycodes[i] != XCB_NO_SYMBOL) { if(event->detail == keycodes[i]) { bool modifiers_present = true; if(hotKey[0] & Qt::ALT) { if(!(event->state & GetModifier(c, keysyms, XK_Alt_L) || event->state & GetModifier(c, keysyms, XK_Alt_R))) { modifiers_present = false; } } if(hotKey[0] & Qt::CTRL) { if(!(event->state & GetModifier(c, keysyms, XK_Control_L) || event->state & GetModifier(c, keysyms, XK_Control_R))) { modifiers_present = false; } } if(hotKey[0] & Qt::META) { if(!(event->state & GetModifier(c, keysyms, XK_Meta_L) || event->state & GetModifier(c, keysyms, XK_Meta_R))) { modifiers_present = false; } } if(hotKey[0] & Qt::SHIFT) { if(!(event->state & GetModifier(c, keysyms, XK_Shift_L) || event->state & GetModifier(c, keysyms, XK_Shift_R))) { modifiers_present = false; } } if(enabled && modifiers_present) { xcb_allow_events(c, XCB_ALLOW_ASYNC_KEYBOARD, event->time); if((ev->response_type&127) == XCB_KEY_PRESS) { emit gotHotKey(); } found = true; } else { if((ev->response_type&127) == XCB_KEY_RELEASE) { found = true; } xcb_allow_events(c, XCB_ALLOW_REPLAY_KEYBOARD, event->time); } break; } i += 1; } free(keysyms); free(keycodes); if(found) return true; } #endif // WIN32 or LINUX return false; }
/** The button press event handler. * \param data The type of mouse event. * \param connection The connection to the X server. * \param ev The event. */ static int event_handle_button(void *data, xcb_connection_t *connection, xcb_button_press_event_t *ev) { int screen; const int nb_screen = xcb_setup_roots_length(xcb_get_setup(connection)); client_t *c; wibox_t *wibox; /* ev->state is * button status (8 bits) + modifiers status (8 bits) * we don't care for button status that we get, especially on release, so * drop them */ ev->state &= 0x00ff; event_handle_mousegrabber(ev->root_x, ev->root_y, ev->state); if((wibox = wibox_getbywin(ev->event)) || (wibox = wibox_getbywin(ev->child))) { /* If the wibox is child, then x,y are * relative to root window */ if(wibox->sw.window == ev->child) { ev->event_x -= wibox->sw.geometry.x; ev->event_y -= wibox->sw.geometry.y; } /* check if we match a binding on the wibox */ button_array_t *b = &wibox->buttons; for(int i = 0; i < b->len; i++) if(ev->detail == b->tab[i]->button && ev->state == b->tab[i]->mod) switch(ev->response_type) { case XCB_BUTTON_PRESS: if(b->tab[i]->press != LUA_REFNIL) { wibox_push(globalconf.L, wibox); luaA_dofunction(globalconf.L, b->tab[i]->press, 1, 0); } break; case XCB_BUTTON_RELEASE: if(b->tab[i]->release != LUA_REFNIL) { wibox_push(globalconf.L, wibox); luaA_dofunction(globalconf.L, b->tab[i]->release, 1, 0); } break; } /* then try to match a widget binding */ widget_t *w = widget_getbycoords(wibox->position, &wibox->widgets, wibox->sw.geometry.width, wibox->sw.geometry.height, &ev->event_x, &ev->event_y); if(w) { b = &w->buttons; for(int i = 0; i < b->len; i++) if(ev->detail == b->tab[i]->button && ev->state == b->tab[i]->mod) switch(ev->response_type) { case XCB_BUTTON_PRESS: if(b->tab[i]->press != LUA_REFNIL) { wibox_push(globalconf.L, wibox); luaA_dofunction(globalconf.L, b->tab[i]->press, 1, 0); } break; case XCB_BUTTON_RELEASE: if(b->tab[i]->release != LUA_REFNIL) { wibox_push(globalconf.L, wibox); luaA_dofunction(globalconf.L, b->tab[i]->release, 1, 0); } break; } } /* return even if no widget match */ return 0; } else if((c = client_getbywin(ev->event))) { event_handle_mouse_button(c, ev->response_type, ev->detail, ev->state, &c->buttons); xcb_allow_events(globalconf.connection, XCB_ALLOW_REPLAY_POINTER, XCB_CURRENT_TIME); } else if(ev->child == XCB_NONE) { for(screen = 0; screen < nb_screen; screen++) if(xutil_screen_get(connection, screen)->root == ev->event) { event_handle_mouse_button(NULL, ev->response_type, ev->detail, ev->state, &globalconf.buttons); return 0; } } return 0; }