keypress_c.h 9.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355
  1. // Copyright 2016 The go-vgo Project Developers. See the COPYRIGHT
  2. // file at the top-level directory of this distribution and at
  3. // https://github.com/go-vgo/robotgo/blob/master/LICENSE
  4. //
  5. // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
  6. // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
  7. // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
  8. // option. This file may not be copied, modified, or distributed
  9. // except according to those terms.
  10. #include "../base/deadbeef_rand_c.h"
  11. #include "../base/microsleep.h"
  12. #include "keypress.h"
  13. #include "keycode_c.h"
  14. #include <ctype.h> /* For isupper() */
  15. #if defined(IS_MACOSX)
  16. #include <ApplicationServices/ApplicationServices.h>
  17. #import <IOKit/hidsystem/IOHIDLib.h>
  18. #import <IOKit/hidsystem/ev_keymap.h>
  19. #elif defined(USE_X11)
  20. #include <X11/extensions/XTest.h>
  21. // #include "../base/xdisplay_c.h"
  22. #endif
  23. /* Convenience wrappers around ugly APIs. */
  24. #if defined(IS_WINDOWS)
  25. HWND GetHwndByPid(DWORD dwProcessId);
  26. HWND getHwnd(uintptr pid, int8_t isPid) {
  27. HWND hwnd = (HWND) pid;
  28. if (isPid == 0) {
  29. hwnd = GetHwndByPid(pid);
  30. }
  31. return hwnd;
  32. }
  33. void WIN32_KEY_EVENT_WAIT(MMKeyCode key, DWORD flags, uintptr pid) {
  34. win32KeyEvent(key, flags, pid, 0);
  35. Sleep(DEADBEEF_RANDRANGE(0, 1));
  36. }
  37. #elif defined(USE_X11)
  38. Display *XGetMainDisplay(void);
  39. void X_KEY_EVENT(Display *display, MMKeyCode key, bool is_press) {
  40. XTestFakeKeyEvent(display, XKeysymToKeycode(display, key), is_press, CurrentTime);
  41. XSync(display, false);
  42. }
  43. void X_KEY_EVENT_WAIT(Display *display, MMKeyCode key, bool is_press) {
  44. X_KEY_EVENT(display, key, is_press);
  45. microsleep(DEADBEEF_UNIFORM(0.0, 0.5));
  46. }
  47. #endif
  48. #if defined(IS_MACOSX)
  49. int SendTo(uintptr pid, CGEventRef event) {
  50. if (pid != 0) {
  51. CGEventPostToPid(pid, event);
  52. } else {
  53. CGEventPost(kCGSessionEventTap, event);
  54. }
  55. CFRelease(event);
  56. return 0;
  57. }
  58. static io_connect_t _getAuxiliaryKeyDriver(void) {
  59. static mach_port_t sEventDrvrRef = 0;
  60. mach_port_t masterPort, service, iter;
  61. kern_return_t kr;
  62. if (!sEventDrvrRef) {
  63. kr = IOMasterPort(bootstrap_port, &masterPort);
  64. assert(KERN_SUCCESS == kr);
  65. kr = IOServiceGetMatchingServices(masterPort, IOServiceMatching(kIOHIDSystemClass), &iter);
  66. assert(KERN_SUCCESS == kr);
  67. service = IOIteratorNext(iter);
  68. assert(service);
  69. kr = IOServiceOpen(service, mach_task_self(), kIOHIDParamConnectType, &sEventDrvrRef);
  70. assert(KERN_SUCCESS == kr);
  71. IOObjectRelease(service);
  72. IOObjectRelease(iter);
  73. }
  74. return sEventDrvrRef;
  75. }
  76. #elif defined(IS_WINDOWS)
  77. void win32KeyEvent(int key, MMKeyFlags flags, uintptr pid, int8_t isPid) {
  78. int scan = MapVirtualKey(key & 0xff, MAPVK_VK_TO_VSC);
  79. /* Set the scan code for extended keys */
  80. switch (key){
  81. case VK_RCONTROL:
  82. case VK_SNAPSHOT: /* Print Screen */
  83. case VK_RMENU: /* Right Alt / Alt Gr */
  84. case VK_PAUSE: /* Pause / Break */
  85. case VK_HOME:
  86. case VK_UP:
  87. case VK_PRIOR: /* Page up */
  88. case VK_LEFT:
  89. case VK_RIGHT:
  90. case VK_END:
  91. case VK_DOWN:
  92. case VK_NEXT: /* 'Page Down' */
  93. case VK_INSERT:
  94. case VK_DELETE:
  95. case VK_LWIN:
  96. case VK_RWIN:
  97. case VK_APPS: /* Application */
  98. case VK_VOLUME_MUTE:
  99. case VK_VOLUME_DOWN:
  100. case VK_VOLUME_UP:
  101. case VK_MEDIA_NEXT_TRACK:
  102. case VK_MEDIA_PREV_TRACK:
  103. case VK_MEDIA_STOP:
  104. case VK_MEDIA_PLAY_PAUSE:
  105. case VK_BROWSER_BACK:
  106. case VK_BROWSER_FORWARD:
  107. case VK_BROWSER_REFRESH:
  108. case VK_BROWSER_STOP:
  109. case VK_BROWSER_SEARCH:
  110. case VK_BROWSER_FAVORITES:
  111. case VK_BROWSER_HOME:
  112. case VK_LAUNCH_MAIL:
  113. {
  114. flags |= KEYEVENTF_EXTENDEDKEY;
  115. break;
  116. }
  117. }
  118. // todo: test this
  119. if (pid != 0) {
  120. HWND hwnd = getHwnd(pid, isPid);
  121. int down = (flags == 0 ? WM_KEYDOWN : WM_KEYUP);
  122. // SendMessage(hwnd, down, key, 0);
  123. PostMessageW(hwnd, down, key, 0);
  124. return;
  125. }
  126. /* Set the scan code for keyup */
  127. // if ( flags & KEYEVENTF_KEYUP ) {
  128. // scan |= 0x80;
  129. // }
  130. // keybd_event(key, scan, flags, 0);
  131. INPUT keyInput;
  132. keyInput.type = INPUT_KEYBOARD;
  133. keyInput.ki.wVk = key;
  134. keyInput.ki.wScan = scan;
  135. keyInput.ki.dwFlags = flags;
  136. keyInput.ki.time = 0;
  137. keyInput.ki.dwExtraInfo = 0;
  138. SendInput(1, &keyInput, sizeof(keyInput));
  139. }
  140. #endif
  141. void toggleKeyCode(MMKeyCode code, const bool down, MMKeyFlags flags, uintptr pid) {
  142. #if defined(IS_MACOSX)
  143. /* The media keys all have 1000 added to them to help us detect them. */
  144. if (code >= 1000) {
  145. code = code - 1000; /* Get the real keycode. */
  146. NXEventData event;
  147. kern_return_t kr;
  148. IOGPoint loc = { 0, 0 };
  149. UInt32 evtInfo = code << 16 | (down?NX_KEYDOWN:NX_KEYUP) << 8;
  150. bzero(&event, sizeof(NXEventData));
  151. event.compound.subType = NX_SUBTYPE_AUX_CONTROL_BUTTONS;
  152. event.compound.misc.L[0] = evtInfo;
  153. kr = IOHIDPostEvent(_getAuxiliaryKeyDriver(),
  154. NX_SYSDEFINED, loc, &event, kNXEventDataVersion, 0, FALSE);
  155. assert(KERN_SUCCESS == kr);
  156. } else {
  157. CGEventRef keyEvent = CGEventCreateKeyboardEvent(NULL, (CGKeyCode)code, down);
  158. assert(keyEvent != NULL);
  159. CGEventSetType(keyEvent, down ? kCGEventKeyDown : kCGEventKeyUp);
  160. if (flags != 0) {
  161. CGEventSetFlags(keyEvent, (CGEventFlags) flags);
  162. }
  163. SendTo(pid, keyEvent);
  164. }
  165. #elif defined(IS_WINDOWS)
  166. const DWORD dwFlags = down ? 0 : KEYEVENTF_KEYUP;
  167. /* Parse modifier keys. */
  168. if (flags & MOD_META) { WIN32_KEY_EVENT_WAIT(K_META, dwFlags, pid); }
  169. if (flags & MOD_ALT) { WIN32_KEY_EVENT_WAIT(K_ALT, dwFlags, pid); }
  170. if (flags & MOD_CONTROL) { WIN32_KEY_EVENT_WAIT(K_CONTROL, dwFlags, pid); }
  171. if (flags & MOD_SHIFT) { WIN32_KEY_EVENT_WAIT(K_SHIFT, dwFlags, pid); }
  172. win32KeyEvent(code, dwFlags, pid, 0);
  173. #elif defined(USE_X11)
  174. Display *display = XGetMainDisplay();
  175. const Bool is_press = down ? True : False; /* Just to be safe. */
  176. /* Parse modifier keys. */
  177. if (flags & MOD_META) { X_KEY_EVENT_WAIT(display, K_META, is_press); }
  178. if (flags & MOD_ALT) { X_KEY_EVENT_WAIT(display, K_ALT, is_press); }
  179. if (flags & MOD_CONTROL) { X_KEY_EVENT_WAIT(display, K_CONTROL, is_press); }
  180. if (flags & MOD_SHIFT) { X_KEY_EVENT_WAIT(display, K_SHIFT, is_press); }
  181. X_KEY_EVENT(display, code, is_press);
  182. #endif
  183. }
  184. // void tapKeyCode(MMKeyCode code, MMKeyFlags flags){
  185. // toggleKeyCode(code, true, flags);
  186. // microsleep(5.0);
  187. // toggleKeyCode(code, false, flags);
  188. // }
  189. #if defined(USE_X11)
  190. bool toUpper(char c) {
  191. if (isupper(c)) {
  192. return true;
  193. }
  194. char *special = "~!@#$%^&*()_+{}|:\"<>?";
  195. while (*special) {
  196. if (*special == c) {
  197. return true;
  198. }
  199. special++;
  200. }
  201. return false;
  202. }
  203. #endif
  204. void toggleKey(char c, const bool down, MMKeyFlags flags, uintptr pid) {
  205. MMKeyCode keyCode = keyCodeForChar(c);
  206. #if defined(USE_X11)
  207. if (toUpper(c) && !(flags & MOD_SHIFT)) {
  208. flags |= MOD_SHIFT; /* Not sure if this is safe for all layouts. */
  209. }
  210. #else
  211. if (isupper(c) && !(flags & MOD_SHIFT)) {
  212. flags |= MOD_SHIFT; /* Not sure if this is safe for all layouts. */
  213. }
  214. #endif
  215. #if defined(IS_WINDOWS)
  216. int modifiers = keyCode >> 8; // Pull out modifers.
  217. if ((modifiers & 1) != 0) { flags |= MOD_SHIFT; } // Uptdate flags from keycode modifiers.
  218. if ((modifiers & 2) != 0) { flags |= MOD_CONTROL; }
  219. if ((modifiers & 4) != 0) { flags |= MOD_ALT; }
  220. keyCode = keyCode & 0xff; // Mask out modifiers.
  221. #endif
  222. toggleKeyCode(keyCode, down, flags, pid);
  223. }
  224. // void tapKey(char c, MMKeyFlags flags){
  225. // toggleKey(c, true, flags);
  226. // microsleep(5.0);
  227. // toggleKey(c, false, flags);
  228. // }
  229. #if defined(IS_MACOSX)
  230. void toggleUnicode(UniChar ch, const bool down, uintptr pid) {
  231. /* This function relies on the convenient CGEventKeyboardSetUnicodeString(),
  232. convert characters to a keycode, but does not support adding modifier flags.
  233. It is only used in typeString().
  234. -- if you need modifier keys, use the above functions instead. */
  235. CGEventRef keyEvent = CGEventCreateKeyboardEvent(NULL, 0, down);
  236. if (keyEvent == NULL) {
  237. fputs("Could not create keyboard event.\n", stderr);
  238. return;
  239. }
  240. CGEventKeyboardSetUnicodeString(keyEvent, 1, &ch);
  241. SendTo(pid, keyEvent);
  242. }
  243. #else
  244. #define toggleUniKey(c, down) toggleKey(c, down, MOD_NONE, 0)
  245. #endif
  246. // unicode type
  247. void unicodeType(const unsigned value, uintptr pid, int8_t isPid) {
  248. #if defined(IS_MACOSX)
  249. UniChar ch = (UniChar)value; // Convert to unsigned char
  250. toggleUnicode(ch, true, pid);
  251. microsleep(5.0);
  252. toggleUnicode(ch, false, pid);
  253. #elif defined(IS_WINDOWS)
  254. if (pid != 0) {
  255. HWND hwnd = getHwnd(pid, isPid);
  256. // SendMessage(hwnd, down, value, 0);
  257. PostMessageW(hwnd, WM_CHAR, value, 0);
  258. return;
  259. }
  260. INPUT input[2];
  261. memset(input, 0, sizeof(input));
  262. input[0].type = INPUT_KEYBOARD;
  263. input[0].ki.wVk = 0;
  264. input[0].ki.wScan = value;
  265. input[0].ki.dwFlags = 0x4; // KEYEVENTF_UNICODE;
  266. input[1].type = INPUT_KEYBOARD;
  267. input[1].ki.wVk = 0;
  268. input[1].ki.wScan = value;
  269. input[1].ki.dwFlags = KEYEVENTF_KEYUP | 0x4; // KEYEVENTF_UNICODE;
  270. SendInput(2, input, sizeof(INPUT));
  271. #elif defined(USE_X11)
  272. toggleUniKey(value, true);
  273. microsleep(5.0);
  274. toggleUniKey(value, false);
  275. #endif
  276. }
  277. #if defined(USE_X11)
  278. int input_utf(const char *utf) {
  279. Display *dpy = XOpenDisplay(NULL);
  280. KeySym sym = XStringToKeysym(utf);
  281. // KeySym sym = XKeycodeToKeysym(dpy, utf);
  282. int min, max, numcodes;
  283. XDisplayKeycodes(dpy, &min, &max);
  284. KeySym *keysym;
  285. keysym = XGetKeyboardMapping(dpy, min, max-min+1, &numcodes);
  286. keysym[(max-min-1)*numcodes] = sym;
  287. XChangeKeyboardMapping(dpy, min, numcodes, keysym, (max-min));
  288. XFree(keysym);
  289. XFlush(dpy);
  290. KeyCode code = XKeysymToKeycode(dpy, sym);
  291. XTestFakeKeyEvent(dpy, code, True, 1);
  292. XTestFakeKeyEvent(dpy, code, False, 1);
  293. XFlush(dpy);
  294. XCloseDisplay(dpy);
  295. return 0;
  296. }
  297. #else
  298. int input_utf(const char *utf){
  299. return 0;
  300. }
  301. #endif