#include #include #include #include #include #include #include #include #include #include #include #include /* for this struct, refer to libxnee */ typedef union { unsigned char type ; xEvent event ; xResourceReq req ; xGenericReply reply ; xError error ; xConnSetupPrefix setup; } XRecordDatum; /* * FIXME: We need define a private struct for callback function, * to store cur_x, cur_y, data_disp, ctrl_disp etc. */ static xcb_connection_t *data_disp = NULL; static xcb_connection_t *ctrl_disp = NULL; /* stop flag */ int stop = 0; size_t event_callback(xcb_record_enable_context_reply_t *reply, uint8_t *data_); int main () { ctrl_disp = xcb_connect (NULL, NULL); data_disp = xcb_connect (NULL, NULL); if (xcb_connection_has_error(ctrl_disp) || xcb_connection_has_error(data_disp)) { fprintf (stderr, "Error to open local display!\n"); exit (1); } const xcb_query_extension_reply_t *query_ext = xcb_get_extension_data(ctrl_disp, &xcb_record_id); if (!query_ext) { fprintf (stderr, "RECORD extension not supported on this X server!\n"); exit (2); } xcb_record_query_version_reply_t *version_reply = xcb_record_query_version_reply(ctrl_disp, xcb_record_query_version(ctrl_disp, XCB_RECORD_MAJOR_VERSION, XCB_RECORD_MINOR_VERSION), NULL); if (!version_reply) { fprintf (stderr, "This should not happen: Can't get RECORD version\n"); exit (2); } printf ("RECORD extension for local server is version is %d.%d\n", version_reply->major_version, version_reply->minor_version); free(version_reply); xcb_record_range_t rr; xcb_record_client_spec_t rcs; xcb_record_context_t rc = xcb_generate_id(ctrl_disp); memset(&rr, 0, sizeof(rr)); rr.device_events.first = XCB_KEY_PRESS; rr.device_events.last = XCB_MOTION_NOTIFY; rcs = XCB_RECORD_CS_ALL_CLIENTS; xcb_void_cookie_t create_cookie = xcb_record_create_context_checked (ctrl_disp, rc, 0, 1, 1, &rcs, &rr); xcb_generic_error_t *error = xcb_request_check(ctrl_disp, create_cookie); if (error) { fprintf (stderr, "Could not create a record context!\n"); free(error); exit (4); } /* The above xcb_request_check() makes sure the server already handled the * CreateContext request, thus this isn't needed anymore: * XSync(ctrl_disp, 0); */ xcb_record_enable_context_cookie_t cookie = xcb_record_enable_context(data_disp, rc); while (!stop) { xcb_record_enable_context_reply_t *reply = xcb_record_enable_context_reply(data_disp, cookie, NULL); if (!reply) break; if (reply->client_swapped) { fprintf (stderr, "I am too lazy to implement byteswapping\n"); exit(42); } if (reply->category == 0 /* XRecordFromServer */) { size_t offset = 0; uint8_t *data = xcb_record_enable_context_data(reply); while (offset < reply->length<<2) { offset += event_callback(reply, &data[offset]); } } free(reply); } xcb_record_disable_context (ctrl_disp, rc); xcb_record_free_context (ctrl_disp, rc); xcb_flush (ctrl_disp); xcb_disconnect (data_disp); xcb_disconnect (ctrl_disp); return 0; } size_t event_callback(xcb_record_enable_context_reply_t *reply, uint8_t *data_) { /* FIXME: we need use XQueryPointer to get the first location */ static int cur_x = 0; static int cur_y = 0; XRecordDatum *data = (XRecordDatum*) data_; int event_type = data->type; BYTE btncode, keycode; btncode = keycode = data->event.u.u.detail; int rootx = data->event.u.keyButtonPointer.rootX; int rooty = data->event.u.keyButtonPointer.rootY; int time = reply->server_time; switch (event_type) { case KeyPress: /* if escape is pressed, stop the loop and clean up, then exit */ if (keycode == 9) stop = 1; /* Note: you should not use data_disp to do normal X operations !!!*/ /*printf ("KeyPress: \t%s\n", XKeysymToString(XKeycodeToKeysym(ctrl_disp, keycode, 0)));*/ printf ("KeyPress: \t%d\n", keycode); break; case KeyRelease: /*printf ("KeyRelease: \t%s\n", XKeysymToString(XKeycodeToKeysym(ctrl_disp, keycode, 0)));*/ printf ("KeyRelease: \t%d\n", keycode); break; case ButtonPress: /* printf ("ButtonPress: /t%d, rootX=%d, rootY=%d", btncode, cur_x, cur_y); */ break; case ButtonRelease: /* printf ("ButtonRelease: /t%d, rootX=%d, rootY=%d", btncode, cur_x, cur_y); */ break; case MotionNotify: /* printf ("MouseMove: /trootX=%d, rootY=%d",rootx, rooty); */ cur_x = rootx; cur_y = rooty; break; case CreateNotify: break; case DestroyNotify: break; case NoExpose: break; case Expose: break; default: break; } printf (", time=%d\n", time); if (data_[0] == 0) /* reply */ return ((*(uint32_t*) &data_[4]) + 8) << 2; /* Error or event TODO: What about XGE events? */ return 32; }