| 
					
				 | 
			
			
				@@ -1,15 +1,12 @@ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 #include <cstring> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 #include <cassert> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 #include <cstdio> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-#include <thread> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-#include <chrono> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+#include <set> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 #include <X11/Xlib.h> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-#include <X11/keysymdef.h> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 extern "C" { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     #include <xdo.h> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-// const auto KEY_INTERVAL = std::chrono::seconds(64); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 const useconds_t KEY_DELAY = 12000; // microseconds 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 void search_windows_by_name(const xdo_t* xdo, const char* name_regex, Window** windowlist_ret, unsigned int* nwindows_ret) { 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -32,35 +29,53 @@ class ToontownKeyboardManager { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         search_windows_by_name(xdo, "Toontown.*", windowlist_ret, nwindows_ret); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    void send_keys(const char* keysequence) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    void send_keyseq(const char* keysequence, int type) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         Window* windows; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         unsigned int nwindows; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         search_toontown_windows(&windows, &nwindows); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         for(unsigned int i=0; i<nwindows; i++) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             // file:///usr/share/doc/libxdo-dev/html/xdo_8h.html 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             // http://www.cl.cam.ac.uk/~mgk25/ucs/keysymdef.h 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            xdo_send_keysequence_window(xdo, windows[i], keysequence, KEY_DELAY); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            if(type == KeyPress) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                xdo_send_keysequence_window_down(xdo, windows[i], keysequence, KEY_DELAY); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            } else if(type == KeyRelease) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                xdo_send_keysequence_window_up(xdo, windows[i], keysequence, KEY_DELAY); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        if(type == KeyPress) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            printf("> '%s' down\n", keysequence); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } else if(type == KeyRelease) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            printf("> '%s' up\n", keysequence); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    static Bool key_autorepeat_predicate(Display* display, XEvent* event, XPointer arg) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        XKeyEvent* release_event = (XKeyEvent*)arg; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        return event->type == KeyPress 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            && event->xkey.keycode == release_event->keycode 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            && event->xkey.time == release_event->time; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     bool key_event(XKeyEvent* key_event) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         // https://tronche.com/gui/x/xlib/events/keyboard-pointer/keyboard-pointer.html#XKeyEvent 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         // https://tronche.com/gui/x/xlib/utilities/keyboard/XLookupKeysym.html 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         KeySym key_symbol = XLookupKeysym(key_event, 0); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         const char* key_str = XKeysymToString(key_symbol); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        printf( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            "%s %d %lu %s %d\n", 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            (key_event->type == KeyPress) ? "p" : "r", 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            key_event->keycode, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            key_symbol, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            key_str, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            key_event->state 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            ); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        // printf( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        //     "%s %d %lu %s %d %lu\n", 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        //     (key_event->type == KeyPress) ? "p" : "r", 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        //     key_event->keycode, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        //     key_symbol, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        //     key_str, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        //     key_event->state 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        //     , key_event->time 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        //     ); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         if(key_event->state == ControlMask && key_symbol == XStringToKeysym("c")) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             return false; // Ctrl-c 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         } else { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            if(key_event->type == KeyPress) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                send_keys(key_str); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            XEvent repeat_event;  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            if(!XCheckIfEvent(display, &repeat_event, key_autorepeat_predicate, (XPointer)key_event)) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                send_keyseq(key_str, key_event->type); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             return true; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         } 
			 |