main.cpp 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120
  1. #include <cstring>
  2. #include <cassert>
  3. #include <cstdio>
  4. #include <thread>
  5. #include <chrono>
  6. #include <X11/Xlib.h>
  7. #include <X11/keysymdef.h>
  8. extern "C" {
  9. #include <xdo.h>
  10. }
  11. // const auto KEY_INTERVAL = std::chrono::seconds(64);
  12. const useconds_t KEY_DELAY = 12000; // microseconds
  13. void search_windows_by_name(const xdo_t* xdo, const char* name_regex, Window** windowlist_ret, unsigned int* nwindows_ret) {
  14. xdo_search_t search;
  15. memset(&search, 0, sizeof(xdo_search_t));
  16. search.max_depth = -1;
  17. search.require = xdo_search::SEARCH_ALL;
  18. search.searchmask |= SEARCH_NAME;
  19. search.winname = name_regex;
  20. xdo_search_windows(xdo, &search, windowlist_ret, nwindows_ret);
  21. }
  22. class ToontownKeyboardManager {
  23. Display* display;
  24. int screen;
  25. Window main_window;
  26. xdo_t* xdo;
  27. void search_toontown_windows(Window** windowlist_ret, unsigned int* nwindows_ret) {
  28. search_windows_by_name(xdo, "Toontown.*", windowlist_ret, nwindows_ret);
  29. }
  30. void send_keys(const char* keysequence) {
  31. Window* windows;
  32. unsigned int nwindows;
  33. search_toontown_windows(&windows, &nwindows);
  34. for(unsigned int i=0; i<nwindows; i++) {
  35. // file:///usr/share/doc/libxdo-dev/html/xdo_8h.html
  36. // http://www.cl.cam.ac.uk/~mgk25/ucs/keysymdef.h
  37. xdo_send_keysequence_window(xdo, windows[i], keysequence, KEY_DELAY);
  38. }
  39. }
  40. bool key_event(XKeyEvent* key_event) {
  41. // https://tronche.com/gui/x/xlib/events/keyboard-pointer/keyboard-pointer.html#XKeyEvent
  42. // https://tronche.com/gui/x/xlib/utilities/keyboard/XLookupKeysym.html
  43. KeySym key_symbol = XLookupKeysym(key_event, 0);
  44. const char* key_str = XKeysymToString(key_symbol);
  45. printf(
  46. "%s %d %lu %s %d\n",
  47. (key_event->type == KeyPress) ? "p" : "r",
  48. key_event->keycode,
  49. key_symbol,
  50. key_str,
  51. key_event->state
  52. );
  53. if(key_event->state == ControlMask && key_symbol == XStringToKeysym("c")) {
  54. return false; // Ctrl-c
  55. } else {
  56. if(key_event->type == KeyPress) {
  57. send_keys(key_str);
  58. }
  59. return true;
  60. }
  61. }
  62. bool window_event(XEvent* event) {
  63. if(event->type == KeyPress || event->type == KeyRelease) {
  64. return key_event(&event->xkey);
  65. } else {
  66. printf("window event %d", event->type);
  67. return true;
  68. }
  69. }
  70. public:
  71. ToontownKeyboardManager() {
  72. display = XOpenDisplay(NULL);
  73. assert(display);
  74. screen = XDefaultScreen(display);
  75. xdo = xdo_new(NULL);
  76. assert(xdo);
  77. // https://tronche.com/gui/x/xlib/window/XCreateWindow.html
  78. main_window = XCreateSimpleWindow(
  79. display,
  80. RootWindow(display, screen), // parent
  81. 0, // x
  82. 0, // y
  83. 50, // width
  84. 50, // height
  85. 1, // border width
  86. 0, // border
  87. 0 // background
  88. );
  89. XSelectInput(display, main_window, KeyPressMask | KeyReleaseMask);
  90. XMapWindow(display, main_window);
  91. }
  92. void loop() {
  93. XEvent event;
  94. do {
  95. XNextEvent(display, &event);
  96. } while(window_event(&event));
  97. }
  98. ~ToontownKeyboardManager() {
  99. XCloseDisplay(display);
  100. }
  101. };
  102. int main() {
  103. // http://stackoverflow.com/questions/2100654/ignore-auto-repeat-in-x11-applications
  104. // XAutoRepeatOn(display);
  105. ToontownKeyboardManager app;
  106. app.loop();
  107. return 0;
  108. }