You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1968 lines
63KB

  1. /* ----
  2. * ---- file : lglw_windows.c
  3. * ---- author : bsp
  4. * ---- legal : Distributed under terms of the MIT LICENSE (MIT).
  5. * ----
  6. * ---- Permission is hereby granted, free of charge, to any person obtaining a copy
  7. * ---- of this software and associated documentation files (the "Software"), to deal
  8. * ---- in the Software without restriction, including without limitation the rights
  9. * ---- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  10. * ---- copies of the Software, and to permit persons to whom the Software is
  11. * ---- furnished to do so, subject to the following conditions:
  12. * ----
  13. * ---- The above copyright notice and this permission notice shall be included in
  14. * ---- all copies or substantial portions of the Software.
  15. * ----
  16. * ---- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  17. * ---- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  18. * ---- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  19. * ---- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  20. * ---- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  21. * ---- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  22. * ---- THE SOFTWARE.
  23. * ----
  24. * ---- info : This is part of the "lglw" package.
  25. * ----
  26. * ---- created: 04Aug2018
  27. * ---- changed: 05Aug2018, 06Aug2018, 07Aug2018, 08Aug2018, 09Aug2018, 18Aug2018, 07Mar2019
  28. * ---- 10Mar2019, 19May2019
  29. * ----
  30. * ----
  31. * ----
  32. */
  33. #include "lglw.h"
  34. #include <stdlib.h>
  35. #include <stdio.h>
  36. #include <string.h>
  37. #include <windows.h>
  38. #include <windowsx.h>
  39. // #define Dprintf if(0);else printf
  40. #define Dprintf if(1);else printf
  41. // ---------------------------------------------------------------------------- macros and defines
  42. #define LGLW(a) lglw_int_t *lglw = ((lglw_int_t*)(a))
  43. #define LGLW_HIDDEN_BASE_CLASS_NAME "hidden_LGLW"
  44. #define LGLW_WIN_BASE_CLASS_NAME "LGLW_"
  45. #define LGLW_DEFAULT_HIDDEN_W (800)
  46. #define LGLW_DEFAULT_HIDDEN_H (600)
  47. #define LGLW_MOUSE_TOUCH_LMB_TIMEOUT (250u)
  48. #define LGLW_MOUSE_TOUCH_RMB_TIMEOUT (500u)
  49. #define LGLW_MOUSE_TOUCH_RMB_STATE_IDLE (0u)
  50. #define LGLW_MOUSE_TOUCH_RMB_STATE_LMB (1u)
  51. #define LGLW_MOUSE_TOUCH_RMB_STATE_WAIT (2u)
  52. #define LGLW_MOUSE_TOUCH_RMB_STATE_RMB (3u)
  53. #define LGLW_MOUSE_TOUCH_RMB_MOVE_THRESHOLD (7u)
  54. #define sABS(x) (((x)>0)?(x):-(x))
  55. // ---------------------------------------------------------------------------- structs and typedefs
  56. typedef struct lglw_int_s {
  57. void *user_data; // arbitrary user data
  58. HWND parent_hwnd; // created by host
  59. struct {
  60. char class_name[128];
  61. HWND hwnd;
  62. HDC hdc;
  63. lglw_vec2i_t size;
  64. } hidden;
  65. struct {
  66. char class_name[128];
  67. HWND hwnd;
  68. HDC hdc;
  69. HHOOK keyboard_ll_hhook;
  70. lglw_vec2i_t size;
  71. int32_t swap_interval;
  72. } win;
  73. struct {
  74. HDC hdc;
  75. HGLRC hglrc;
  76. } prev;
  77. HGLRC hglrc;
  78. struct {
  79. uint32_t kmod_state; // See LGLW_KMOD_xxx
  80. lglw_keyboard_fxn_t cbk;
  81. } keyboard;
  82. struct {
  83. lglw_vec2i_t p; // last seen mouse position
  84. uint32_t button_state;
  85. lglw_mouse_fxn_t cbk;
  86. struct {
  87. uint32_t mode;
  88. lglw_vec2i_t p; // grab-start mouse position
  89. lglw_bool_t b_queue_warp;
  90. lglw_vec2i_t last_p;
  91. } grab;
  92. struct {
  93. lglw_bool_t b_enable;
  94. lglw_bool_t b_update_queued;
  95. lglw_bool_t b_syn_rmb;
  96. uint32_t syn_rmb_hold_state; // see LGLW_MOUSE_TOUCH_RMB_STATE_xxx
  97. uint32_t hold_start_ms;
  98. lglw_vec2i_t hold_start_p;
  99. } touch;
  100. } mouse;
  101. struct {
  102. uint32_t state;
  103. lglw_focus_fxn_t cbk;
  104. } focus;
  105. struct {
  106. lglw_bool_t b_running;
  107. lglw_timer_fxn_t cbk;
  108. } timer;
  109. struct {
  110. lglw_dropfiles_fxn_t cbk;
  111. } dropfiles;
  112. struct {
  113. lglw_redraw_fxn_t cbk;
  114. } redraw;
  115. } lglw_int_t;
  116. // ---------------------------------------------------------------------------- module fxn fwd decls
  117. static lglw_bool_t loc_create_hidden_window (lglw_int_t *lglw, int32_t _w, int32_t _h);
  118. static void loc_destroy_hidden_window(lglw_int_t *lglw);
  119. static LRESULT CALLBACK loc_WndProc (HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
  120. static void loc_key_hook(lglw_int_t *lglw);
  121. static void loc_key_unhook(lglw_int_t *lglw);
  122. static LRESULT CALLBACK loc_LowLevelKeyboardProc(int nCode, WPARAM wParam, LPARAM lParam);
  123. static lglw_bool_t loc_handle_key (lglw_int_t *lglw, lglw_bool_t _bPressed, uint32_t _vkey);
  124. // static lglw_bool_t loc_touchkeyboard_get_rect (RECT *rect);
  125. // static lglw_bool_t loc_touchkeyboard_is_visible (void);
  126. extern lglw_bool_t lglw_int_touchkeyboard_toggle (void);
  127. static void loc_handle_mouseleave (lglw_int_t *lglw);
  128. static void loc_handle_mouseenter (lglw_int_t *lglw);
  129. static void loc_handle_mousebutton (lglw_int_t *lglw, lglw_bool_t _bPressed, uint32_t _button);
  130. static void loc_handle_mousemotion (lglw_int_t *lglw);
  131. static void loc_handle_queued_mouse_warp (lglw_int_t *lglw);
  132. static void loc_touchinput_update (lglw_int_t *lglw);
  133. static void loc_enable_dropfiles (lglw_int_t *lglw, lglw_bool_t _bEnable);
  134. // ---------------------------------------------------------------------------- module vars
  135. static lglw_int_t *khook_lglw = NULL; // currently key-hooked lglw instance (one at a time)
  136. // ---------------------------------------------------------------------------- lglw_init
  137. lglw_t lglw_init(int32_t _w, int32_t _h) {
  138. lglw_int_t *lglw = malloc(sizeof(lglw_int_t));
  139. if(NULL != lglw)
  140. {
  141. memset(lglw, 0, sizeof(lglw_int_t));
  142. if(_w <= 16)
  143. _w = LGLW_DEFAULT_HIDDEN_W;
  144. if(_h <= 16)
  145. _h = LGLW_DEFAULT_HIDDEN_H;
  146. if(!loc_create_hidden_window(lglw, _w, _h))
  147. {
  148. free(lglw);
  149. lglw = NULL;
  150. }
  151. }
  152. return lglw;
  153. }
  154. // ---------------------------------------------------------------------------- lglw_exit
  155. void lglw_exit(lglw_t _lglw) {
  156. LGLW(_lglw);
  157. if(NULL != lglw)
  158. {
  159. loc_destroy_hidden_window(lglw);
  160. free(lglw);
  161. }
  162. }
  163. // ---------------------------------------------------------------------------- lglw_userdata_set
  164. void lglw_userdata_set(lglw_t _lglw, void *_userData) {
  165. LGLW(_lglw);
  166. if(NULL != lglw)
  167. {
  168. lglw->user_data = _userData;
  169. }
  170. }
  171. // ---------------------------------------------------------------------------- lglw_userdata_get
  172. void *lglw_userdata_get(lglw_t _lglw) {
  173. LGLW(_lglw);
  174. if(NULL != lglw)
  175. {
  176. return lglw->user_data;
  177. }
  178. return NULL;
  179. }
  180. // ---------------------------------------------------------------------------- loc_create_hidden_window
  181. static lglw_bool_t loc_create_hidden_window(lglw_int_t *lglw, int32_t _w, int32_t _h) {
  182. sprintf(lglw->hidden.class_name, LGLW_HIDDEN_BASE_CLASS_NAME "%p", lglw);
  183. WNDCLASS wc;
  184. ZeroMemory(&wc, sizeof(wc));
  185. wc.style = CS_OWNDC;
  186. wc.lpfnWndProc = (WNDPROC) &loc_WndProc;
  187. wc.hInstance = GetModuleHandle(NULL);
  188. wc.hCursor = LoadCursor(NULL, IDC_ARROW);
  189. wc.lpszClassName = lglw->hidden.class_name;
  190. if(!RegisterClass(&wc))
  191. {
  192. // something went terribly wrong
  193. printf("[---] lglw: failed to register hidden window class\n");
  194. return LGLW_FALSE;
  195. }
  196. DWORD dwExStyle = 0;
  197. DWORD dwStyle = 0;
  198. lglw->hidden.hwnd = CreateWindowEx(dwExStyle,
  199. lglw->hidden.class_name,
  200. "LGLW_hidden",
  201. dwStyle,
  202. 0/*xpos*/, 0/*ypos*/,
  203. _w, _h,
  204. NULL/*parentHWND*/,
  205. NULL/*window menu*/,
  206. GetModuleHandle(NULL),
  207. NULL
  208. );
  209. lglw->hidden.size.x = _w;
  210. lglw->hidden.size.y = _h;
  211. PIXELFORMATDESCRIPTOR pfd = {
  212. sizeof(PIXELFORMATDESCRIPTOR),
  213. 1,
  214. PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER, //Flags
  215. PFD_TYPE_RGBA, // The kind of framebuffer. RGBA or palette.
  216. 32, // Colordepth of the framebuffer.
  217. 0, 0, 0, 0, 0, 0,
  218. 0,
  219. 0,
  220. 0,
  221. 0, 0, 0, 0,
  222. 24, // Number of bits for the depthbuffer
  223. 8, // Number of bits for the stencilbuffer
  224. 0, // Number of Aux buffers in the framebuffer.
  225. PFD_MAIN_PLANE,
  226. 0,
  227. 0, 0, 0
  228. };
  229. lglw->hidden.hdc = GetDC(lglw->hidden.hwnd);
  230. Dprintf("xxx lglw: hidden hdc=%p\n", lglw->hidden.hdc);
  231. int pfmt = ChoosePixelFormat(lglw->hidden.hdc, &pfd);
  232. Dprintf("xxx lglw: hidden pfmt=%d\n", pfmt);
  233. SetPixelFormat(lglw->hidden.hdc, pfmt, &pfd);
  234. lglw->hglrc = wglCreateContext(lglw->hidden.hdc);
  235. Dprintf("xxx lglw: hidden hglrc=%p\n", lglw->hglrc);
  236. return LGLW_TRUE;
  237. }
  238. // ---------------------------------------------------------------------------- loc_destroy_hidden_window
  239. static void loc_destroy_hidden_window(lglw_int_t *lglw) {
  240. if(NULL != lglw->hidden.hwnd)
  241. {
  242. wglDeleteContext(lglw->hglrc);
  243. lglw->hglrc = NULL;
  244. DestroyWindow(lglw->hidden.hwnd);
  245. lglw->hidden.hwnd = NULL;
  246. UnregisterClass(lglw->hidden.class_name, GetModuleHandle(NULL));
  247. }
  248. }
  249. // ---------------------------------------------------------------------------- lglw_window_open
  250. lglw_bool_t lglw_window_open (lglw_t _lglw, void *_parentHWNDOrNull, int32_t _x, int32_t _y, int32_t _w, int32_t _h) {
  251. lglw_bool_t r = LGLW_FALSE;
  252. LGLW(_lglw);
  253. if(NULL != lglw)
  254. {
  255. lglw->parent_hwnd = (HWND)_parentHWNDOrNull;
  256. sprintf(lglw->win.class_name, LGLW_WIN_BASE_CLASS_NAME "%p", lglw);
  257. WNDCLASS wc;
  258. ZeroMemory(&wc, sizeof(wc));
  259. wc.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
  260. wc.lpfnWndProc = (WNDPROC) &loc_WndProc;
  261. wc.hInstance = GetModuleHandle(NULL);
  262. wc.hCursor = LoadCursor(NULL, IDC_ARROW);
  263. wc.lpszClassName = lglw->win.class_name;
  264. if(!RegisterClass(&wc))
  265. {
  266. // something went terribly wrong
  267. printf("[---] lglw: failed to register window class\n");
  268. return LGLW_FALSE;
  269. }
  270. if(_w <= 16)
  271. _w = lglw->hidden.size.x;
  272. if(_h <= 16)
  273. _h = lglw->hidden.size.y;
  274. DWORD dwExStyle = 0;
  275. DWORD dwStyle = ((NULL != _parentHWNDOrNull) ? WS_CHILD : 0) | WS_VISIBLE;
  276. lglw->win.hwnd = CreateWindowEx(dwExStyle,
  277. lglw->win.class_name,
  278. "LGLW",
  279. dwStyle,
  280. (NULL == _parentHWNDOrNull) ? _x : 0,
  281. (NULL == _parentHWNDOrNull) ? _y : 0,
  282. _w, _h,
  283. _parentHWNDOrNull,
  284. NULL/*window menu*/,
  285. GetModuleHandle(NULL),
  286. NULL
  287. );
  288. lglw->win.size.x = _w;
  289. lglw->win.size.y = _h;
  290. // window_to_wrapper = this;
  291. PIXELFORMATDESCRIPTOR pfd = {
  292. sizeof(PIXELFORMATDESCRIPTOR),
  293. 1,
  294. PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER, //Flags
  295. PFD_TYPE_RGBA, // The kind of framebuffer. RGBA or palette.
  296. 32, // Colordepth of the framebuffer.
  297. 0, 0, 0, 0, 0, 0,
  298. 0,
  299. 0,
  300. 0,
  301. 0, 0, 0, 0,
  302. 24, // Number of bits for the depthbuffer
  303. 8, // Number of bits for the stencilbuffer
  304. 0, // Number of Aux buffers in the framebuffer.
  305. PFD_MAIN_PLANE,
  306. 0,
  307. 0, 0, 0
  308. };
  309. lglw->win.hdc = GetDC(lglw->win.hwnd);
  310. int pfmt = ChoosePixelFormat(lglw->win.hdc, &pfd);
  311. Dprintf("xxx lglw: win pfmt=%d\n", pfmt);
  312. SetPixelFormat(lglw->win.hdc, pfmt, &pfd);
  313. (void)SetWindowLongPtr(lglw->win.hwnd, GWLP_USERDATA, (LONG_PTR)lglw);
  314. loc_enable_dropfiles(lglw, (NULL != lglw->dropfiles.cbk));
  315. }
  316. return r;
  317. }
  318. // ---------------------------------------------------------------------------- lglw_window_resize
  319. lglw_bool_t lglw_window_resize (lglw_t _lglw, int32_t _w, int32_t _h) {
  320. lglw_bool_t r = LGLW_FALSE;
  321. LGLW(_lglw);
  322. if(NULL != lglw)
  323. {
  324. if(NULL != lglw->win.hwnd)
  325. {
  326. r = LGLW_TRUE;
  327. SetWindowPos(lglw->win.hwnd,
  328. HWND_TOP,
  329. 0, 0, // x/y
  330. _w, _h,
  331. SWP_NOMOVE | SWP_SHOWWINDOW
  332. );
  333. int deltaW = _w - lglw->win.size.x;
  334. int deltaH = _h - lglw->win.size.y;
  335. lglw->win.size.x = _w;
  336. lglw->win.size.y = _h;
  337. // Resize parent window (if any)
  338. {
  339. HWND hwnd;
  340. hwnd = GetAncestor(lglw->win.hwnd, GA_ROOT);
  341. Dprintf("xxx lglw_window_resize: ancestor=%p\n", hwnd);
  342. if(NULL != hwnd)
  343. {
  344. RECT rect;
  345. if(GetWindowRect(hwnd, &rect))
  346. {
  347. rect.right += deltaW;
  348. rect.bottom += deltaH;
  349. SetWindowPos(hwnd,
  350. HWND_TOP,
  351. 0, 0, // x/y
  352. rect.right - rect.left, rect.bottom - rect.top,
  353. SWP_NOMOVE | SWP_FRAMECHANGED | SWP_SHOWWINDOW
  354. );
  355. }
  356. }
  357. }
  358. }
  359. }
  360. return r;
  361. }
  362. // ---------------------------------------------------------------------------- lglw_window_close
  363. void lglw_window_close (lglw_t _lglw) {
  364. LGLW(_lglw);
  365. if(NULL != lglw)
  366. {
  367. if(NULL != lglw->win.hwnd)
  368. {
  369. lglw_timer_stop(_lglw);
  370. loc_key_unhook(lglw);
  371. DestroyWindow(lglw->win.hwnd);
  372. lglw->win.hwnd = NULL;
  373. lglw->win.hdc = NULL;
  374. UnregisterClass(lglw->win.class_name, GetModuleHandle(NULL));
  375. // window_to_wrapper = NULL;
  376. }
  377. }
  378. }
  379. // ---------------------------------------------------------------------------- lglw_window_show
  380. void lglw_window_show(lglw_t _lglw) {
  381. LGLW(_lglw);
  382. if(NULL != lglw)
  383. {
  384. if(NULL != lglw->win.hwnd)
  385. {
  386. ShowWindow(lglw->win.hwnd, SW_SHOWNORMAL);
  387. }
  388. }
  389. }
  390. // ---------------------------------------------------------------------------- lglw_window_hide
  391. void lglw_window_hide(lglw_t _lglw) {
  392. LGLW(_lglw);
  393. if(NULL != lglw)
  394. {
  395. if(NULL != lglw->win.hwnd)
  396. {
  397. ShowWindow(lglw->win.hwnd, SW_HIDE);
  398. }
  399. }
  400. }
  401. // ---------------------------------------------------------------------------- lglw_window_is_visible
  402. lglw_bool_t lglw_window_is_visible(lglw_t _lglw) {
  403. lglw_bool_t r = LGLW_FALSE;
  404. LGLW(_lglw);
  405. if(NULL != lglw)
  406. {
  407. r = (lglw_bool_t)IsWindowVisible(lglw->win.hwnd);
  408. }
  409. return r;
  410. }
  411. // ---------------------------------------------------------------------------- lglw_window_size_get
  412. void lglw_window_size_get(lglw_t _lglw, int32_t *_retX, int32_t *_retY) {
  413. LGLW(_lglw);
  414. if(NULL != lglw)
  415. {
  416. if(NULL != lglw->win.hwnd)
  417. {
  418. if(NULL != _retX)
  419. *_retX = lglw->win.size.x;
  420. if(NULL != _retY)
  421. *_retY = lglw->win.size.y;
  422. }
  423. }
  424. }
  425. // ---------------------------------------------------------------------------- lglw_redraw
  426. void lglw_redraw(lglw_t _lglw) {
  427. LGLW(_lglw);
  428. if(NULL != lglw)
  429. {
  430. if(NULL != lglw->win.hwnd)
  431. {
  432. RedrawWindow(lglw->win.hwnd, NULL/*lprcUpdate*/, NULL/*hrgnUpdate*/, RDW_INTERNALPAINT | RDW_UPDATENOW);
  433. }
  434. }
  435. }
  436. // ---------------------------------------------------------------------------- lglw_redraw_callback_set
  437. void lglw_redraw_callback_set(lglw_t _lglw, lglw_redraw_fxn_t _cbk) {
  438. LGLW(_lglw);
  439. if(NULL != lglw)
  440. {
  441. lglw->redraw.cbk = _cbk;
  442. }
  443. }
  444. // ---------------------------------------------------------------------------- lglw_glcontext_push
  445. void lglw_glcontext_push(lglw_t _lglw) {
  446. LGLW(_lglw);
  447. if(NULL != lglw)
  448. {
  449. lglw->prev.hdc = wglGetCurrentDC();
  450. lglw->prev.hglrc = wglGetCurrentContext();
  451. // Dprintf("xxx lglw_glcontext_push: prev.hdc=%p prev.hglrc=%p\n", lglw->prev.hdc, lglw->prev.hglrc);
  452. // Dprintf("xxx lglw_glcontext_push: win.hdc=%p lglw->hglrc=%p\n", lglw->win.hdc, lglw->hglrc);
  453. if(!wglMakeCurrent((NULL == lglw->win.hdc) ? lglw->hidden.hdc : lglw->win.hdc, lglw->hglrc))
  454. {
  455. printf("[---] lglw_glcontext_push: wglMakeCurrent() failed. win.hdc=%p hidden.hdc=%p hglrc=%p GetLastError()=%d\n", lglw->win.hdc, lglw->hidden.hdc, lglw->hglrc, GetLastError());
  456. }
  457. }
  458. }
  459. // ---------------------------------------------------------------------------- lglw_glcontext_pop
  460. void lglw_glcontext_pop(lglw_t _lglw) {
  461. LGLW(_lglw);
  462. if(NULL != lglw)
  463. {
  464. // Dprintf("xxx lglw_glcontext_pop: prev.hdc=%p prev.hglrc=%p\n", lglw->prev.hdc, lglw->prev.hglrc);
  465. if(!wglMakeCurrent(lglw->prev.hdc, lglw->prev.hglrc))
  466. {
  467. printf("[---] lglw_glcontext_pop: wglMakeCurrent() failed. prev.hdc=%p hglrc=%p GetLastError()=%d\n", lglw->prev.hdc, lglw->prev.hglrc, GetLastError());
  468. }
  469. }
  470. }
  471. // ---------------------------------------------------------------------------- lglw_swap_buffers
  472. void lglw_swap_buffers(lglw_t _lglw) {
  473. LGLW(_lglw);
  474. if(NULL != lglw)
  475. {
  476. wglSwapLayerBuffers(lglw->win.hdc, WGL_SWAP_MAIN_PLANE);
  477. }
  478. }
  479. // ---------------------------------------------------------------------------- lglw_swap_interval_set
  480. typedef void (APIENTRY *PFNWGLEXTSWAPINTERVALPROC) (int);
  481. void lglw_swap_interval_set(lglw_t _lglw, int32_t _ival) {
  482. LGLW(_lglw);
  483. if(NULL != lglw)
  484. {
  485. PFNWGLEXTSWAPINTERVALPROC wglSwapIntervalEXT;
  486. wglSwapIntervalEXT = (PFNWGLEXTSWAPINTERVALPROC) wglGetProcAddress("wglSwapIntervalEXT");
  487. if(NULL != wglSwapIntervalEXT)
  488. {
  489. wglSwapIntervalEXT(_ival);
  490. lglw->win.swap_interval = _ival;
  491. }
  492. }
  493. }
  494. // ---------------------------------------------------------------------------- lglw_swap_interval_get
  495. int32_t lglw_swap_interval_get(lglw_t _lglw) {
  496. LGLW(_lglw);
  497. int32_t r = 0;
  498. if(NULL != lglw)
  499. {
  500. r = lglw->win.swap_interval;
  501. }
  502. return r;
  503. }
  504. // ---------------------------------------------------------------------------- loc_key_hook
  505. static void loc_key_hook(lglw_int_t *lglw) {
  506. loc_key_unhook(lglw);
  507. // https://msdn.microsoft.com/en-us/library/windows/desktop/ms644990(v=vs.85).aspx
  508. lglw->win.keyboard_ll_hhook = SetWindowsHookEx(WH_KEYBOARD_LL, &loc_LowLevelKeyboardProc, GetModuleHandle(NULL), 0/*dwThreadId*/);
  509. khook_lglw = lglw;
  510. }
  511. // ---------------------------------------------------------------------------- loc_key_unhook
  512. static void loc_key_unhook(lglw_int_t *lglw) {
  513. if(NULL != lglw->win.keyboard_ll_hhook)
  514. {
  515. UnhookWindowsHookEx(lglw->win.keyboard_ll_hhook);
  516. lglw->win.keyboard_ll_hhook = NULL;
  517. if(khook_lglw == lglw)
  518. khook_lglw = NULL;
  519. }
  520. }
  521. // ---------------------------------------------------------------------------- loc_handle_mouseleave
  522. static void loc_handle_mouseleave(lglw_int_t *lglw) {
  523. loc_key_unhook(lglw);
  524. lglw->focus.state &= ~LGLW_FOCUS_MOUSE;
  525. if(NULL != lglw->focus.cbk)
  526. {
  527. lglw->focus.cbk(lglw, lglw->focus.state, LGLW_FOCUS_MOUSE);
  528. }
  529. Dprintf("xxx lglw:loc_handle_mouseleave: LEAVE\n");
  530. }
  531. // ---------------------------------------------------------------------------- loc_handle_mouseenter
  532. static void loc_handle_mouseenter(lglw_int_t *lglw) {
  533. TRACKMOUSEEVENT tme;
  534. ZeroMemory(&tme, sizeof(tme));
  535. tme.cbSize = sizeof(TRACKMOUSEEVENT);
  536. tme.dwFlags = TME_LEAVE;
  537. tme.hwndTrack = lglw->win.hwnd;
  538. tme.dwHoverTime = HOVER_DEFAULT;
  539. (void)TrackMouseEvent(&tme);
  540. loc_key_hook(lglw);
  541. lglw->focus.state |= LGLW_FOCUS_MOUSE;
  542. if(NULL != lglw->focus.cbk)
  543. {
  544. lglw->focus.cbk(lglw, lglw->focus.state, LGLW_FOCUS_MOUSE);
  545. }
  546. Dprintf("xxx lglw:loc_handle_mouseenter: LEAVE\n");
  547. }
  548. // ---------------------------------------------------------------------------- loc_handle_mousebutton
  549. static void loc_handle_mousebutton(lglw_int_t *lglw, lglw_bool_t _bPressed, uint32_t _button) {
  550. if(_bPressed)
  551. lglw->mouse.button_state |= _button;
  552. else
  553. lglw->mouse.button_state &= ~_button;
  554. if(NULL != lglw->mouse.cbk)
  555. {
  556. lglw->mouse.cbk(lglw, lglw->mouse.p.x, lglw->mouse.p.y, lglw->mouse.button_state, _button);
  557. }
  558. }
  559. // ---------------------------------------------------------------------------- loc_handle_mousemotion
  560. static void loc_handle_mousemotion(lglw_int_t *lglw) {
  561. if(NULL != lglw->mouse.cbk)
  562. {
  563. lglw->mouse.cbk(lglw, lglw->mouse.p.x, lglw->mouse.p.y, lglw->mouse.button_state, 0u/*changedbuttonstate*/);
  564. }
  565. }
  566. // ---------------------------------------------------------------------------- lglw_mouse_callback_set
  567. void lglw_mouse_callback_set(lglw_t _lglw, lglw_mouse_fxn_t _cbk) {
  568. LGLW(_lglw);
  569. if(NULL != lglw)
  570. {
  571. lglw->mouse.cbk = _cbk;
  572. }
  573. }
  574. // ---------------------------------------------------------------------------- lglw_mouse_callback_set
  575. void lglw_focus_callback_set(lglw_t _lglw, lglw_focus_fxn_t _cbk) {
  576. LGLW(_lglw);
  577. if(NULL != lglw)
  578. {
  579. lglw->focus.cbk = _cbk;
  580. }
  581. }
  582. // ---------------------------------------------------------------------------- loc_handle_key
  583. static lglw_bool_t loc_handle_key(lglw_int_t *lglw, lglw_bool_t _bPressed, uint32_t _vkey) {
  584. lglw_bool_t r = LGLW_FALSE;
  585. if(NULL != lglw->keyboard.cbk)
  586. {
  587. r = lglw->keyboard.cbk(lglw, _vkey, lglw->keyboard.kmod_state, _bPressed);
  588. }
  589. return r;
  590. }
  591. // ---------------------------------------------------------------------------- lglw_keyboard_callback_set
  592. void lglw_keyboard_callback_set(lglw_t _lglw, lglw_keyboard_fxn_t _cbk) {
  593. LGLW(_lglw);
  594. if(NULL != lglw)
  595. {
  596. lglw->keyboard.cbk = _cbk;
  597. }
  598. }
  599. // ---------------------------------------------------------------------------- lglw_keyboard_get_modifiers
  600. uint32_t lglw_keyboard_get_modifiers(lglw_t _lglw) {
  601. uint32_t r = 0u;
  602. LGLW(_lglw);
  603. if(NULL != lglw)
  604. {
  605. r = lglw->keyboard.kmod_state;
  606. }
  607. return r;
  608. }
  609. // ---------------------------------------------------------------------------- lglw_keyboard_clear_modifiers
  610. void lglw_keyboard_clear_modifiers(lglw_t _lglw) {
  611. LGLW(_lglw);
  612. if(NULL != lglw)
  613. {
  614. lglw->keyboard.kmod_state = 0;
  615. }
  616. }
  617. // ---------------------------------------------------------------------------- loc_touchkeyboard_get_rect
  618. #if 0
  619. static lglw_bool_t loc_touchkeyboard_get_rect(RECT *rect) {
  620. lglw_bool_t r = LGLW_FALSE;
  621. //*******************************************************************
  622. //
  623. // RETURNS KEYBOARD RECTANGLE OR EMPTY ONE IF KEYBOARD IS NOT VISIBLE
  624. //
  625. //*******************************************************************
  626. // by "Sevast", <https://stackoverflow.com/questions/38774139/show-touch-keyboard-tabtip-exe-in-windows-10-anniversary-edition>
  627. IFrameworkInputPane *inputPane = NULL;
  628. HRESULT hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
  629. rect->left = rect->right = rect->top = rect->bottom = 0; // screen location
  630. if (SUCCEEDED(hr))
  631. {
  632. hr = CoCreateInstance(CLSID_FrameworkInputPane, NULL, CLSCTX_INPROC_SERVER, IID_IFrameworkInputPane, (LPVOID*)&inputPane);
  633. if (SUCCEEDED(hr))
  634. {
  635. hr=inputPane->Location(rect);
  636. if(SUCCEEDED(hr))
  637. {
  638. r = LGLW_TRUE;
  639. }
  640. inputPane->Release();
  641. }
  642. }
  643. CoUninitialize();
  644. return r;
  645. }
  646. #endif
  647. // ---------------------------------------------------------------------------- loc_touchkeyboard_is_visible
  648. #if 0
  649. static lglw_bool_t loc_touchkeyboard_is_visible(void) {
  650. lglw_bool_t r = LGLW_FALSE;
  651. HWND hwnd = FindWindow("IPTIP_Main_Window", NULL);
  652. printf("xxx lglw: IPTIP hwnd=%p\n", hwnd);
  653. if(NULL != hwnd)
  654. {
  655. #if 0
  656. // (note) does not work, style flags are always the same and rect is always (0; 0; 0; 0)
  657. LONG style = GetWindowLong(hwnd, GWL_STYLE);
  658. RECT rect;
  659. r = (0u != (style & WS_VISIBLE)) && (0u == (style & WS_DISABLED));
  660. GetWindowRect(hwnd, &rect);
  661. printf("xxx lglw: touchkeyboard_is_visible: style=0x%08x rect=(%d; %d; %d; %d) r=%d\n", style, rect.top, rect.left, rect.bottom, rect.right, r);
  662. #endif
  663. // (note) does not work, either
  664. static const char *WindowClass1709 = "Windows.UI.Core.CoreWindow";
  665. static const char *WindowCaption1709 = "Microsoft Text Input Application";
  666. static const char *WindowParentClass1709 = "ApplicationFrameWindow";
  667. HWND hwnd1709 = FindWindowEx(NULL, NULL, WindowClass1709, WindowCaption1709);
  668. printf("xxx lglw: touchkeyboard_is_visible: hwnd1709=%p\n", hwnd1709);
  669. // if there is a top-level window - the keyboard is closed
  670. if(NULL != hwnd1709)
  671. {
  672. r = LGLW_FALSE;
  673. }
  674. else
  675. {
  676. HWND parent = NULL;
  677. for(;;)
  678. {
  679. HWND childHWND;
  680. parent = FindWindowEx(NULL, parent, WindowParentClass1709, NULL);
  681. if(NULL == parent)
  682. break; // no more windows, keyboard state is unknown
  683. // if it's a child of a WindowParentClass1709 window - the keyboard is open
  684. childHWND = FindWindowEx(parent, NULL, WindowClass1709, WindowCaption1709);
  685. if (NULL != childHWND)
  686. {
  687. r = LGLW_TRUE;
  688. break;
  689. }
  690. }
  691. }
  692. }
  693. return r;
  694. }
  695. #endif
  696. // ---------------------------------------------------------------------------- lglw_touchkeyboard_show
  697. void lglw_touchkeyboard_show(lglw_t _lglw, lglw_bool_t _bEnable) {
  698. LGLW(_lglw);
  699. if(NULL != lglw)
  700. {
  701. #if 0
  702. RECT keyRect;
  703. if(loc_touchkeyboard_get_rect(&keyRect))
  704. {
  705. lglw_bool_t bToggle = _bEnable ^ ((keyRect.right - keyRect.left) > 0);
  706. if(bToggle)
  707. {
  708. loc_touchkeyboard_toggle();
  709. }
  710. }
  711. #endif
  712. #if 0
  713. lglw_bool_t bToggle = _bEnable ^ loc_touchkeyboard_is_visible();
  714. if(bToggle)
  715. {
  716. lglw_int_touchkeyboard_toggle();
  717. }
  718. #endif
  719. // (note) there seems to be no (sane) way to determine whether the virtual keyboard is visible.
  720. // the solutions suggested on stack overflow don't work (anymore).
  721. // => just toggle the kbd
  722. lglw_int_touchkeyboard_toggle();
  723. }
  724. }
  725. // ---------------------------------------------------------------------------- lglw_mouse_get_buttons
  726. uint32_t lglw_mouse_get_buttons(lglw_t _lglw) {
  727. uint32_t r = 0u;
  728. LGLW(_lglw);
  729. if(NULL != lglw)
  730. {
  731. r = lglw->mouse.button_state;
  732. }
  733. return r;
  734. }
  735. // ---------------------------------------------------------------------------- lglw_mouse_grab
  736. void lglw_mouse_grab(lglw_t _lglw, uint32_t _grabMode) {
  737. LGLW(_lglw);
  738. if(NULL != lglw)
  739. {
  740. if(NULL != lglw->win.hwnd)
  741. {
  742. if(!lglw->mouse.touch.b_enable)
  743. {
  744. if(lglw->mouse.grab.mode != _grabMode)
  745. {
  746. lglw_mouse_ungrab(_lglw);
  747. }
  748. switch(_grabMode)
  749. {
  750. default:
  751. case LGLW_MOUSE_GRAB_NONE:
  752. break;
  753. case LGLW_MOUSE_GRAB_CAPTURE:
  754. (void)SetCapture(lglw->win.hwnd);
  755. lglw->mouse.grab.mode = _grabMode;
  756. break;
  757. case LGLW_MOUSE_GRAB_WARP:
  758. (void)SetCapture(lglw->win.hwnd);
  759. lglw_mouse_cursor_show(_lglw, LGLW_FALSE);
  760. lglw->mouse.grab.p = lglw->mouse.p;
  761. lglw->mouse.grab.last_p = lglw->mouse.p;
  762. lglw->mouse.grab.mode = _grabMode;
  763. break;
  764. }
  765. }
  766. }
  767. }
  768. }
  769. // ---------------------------------------------------------------------------- lglw_mouse_ungrab
  770. void lglw_mouse_ungrab(lglw_t _lglw) {
  771. LGLW(_lglw);
  772. if(NULL != lglw)
  773. {
  774. if(NULL != lglw->win.hwnd)
  775. {
  776. if(!lglw->mouse.touch.b_enable)
  777. {
  778. switch(lglw->mouse.grab.mode)
  779. {
  780. default:
  781. case LGLW_MOUSE_GRAB_NONE:
  782. break;
  783. case LGLW_MOUSE_GRAB_CAPTURE:
  784. (void)ReleaseCapture();
  785. lglw->mouse.grab.mode = LGLW_MOUSE_GRAB_NONE;
  786. break;
  787. case LGLW_MOUSE_GRAB_WARP:
  788. (void)ReleaseCapture();
  789. lglw->mouse.grab.mode = LGLW_MOUSE_GRAB_NONE;
  790. lglw->mouse.grab.b_queue_warp = LGLW_TRUE;
  791. lglw_mouse_cursor_show(_lglw, LGLW_TRUE);
  792. break;
  793. }
  794. }
  795. }
  796. }
  797. }
  798. // ---------------------------------------------------------------------------- lglw_mouse_warp
  799. void lglw_mouse_warp(lglw_t _lglw, int32_t _x, int32_t _y) {
  800. LGLW(_lglw);
  801. if(NULL != lglw)
  802. {
  803. if(NULL != lglw->win.hwnd)
  804. {
  805. POINT p;
  806. p.x = _x;
  807. p.y = _y;
  808. if(ClientToScreen(lglw->win.hwnd, &p))
  809. {
  810. SetCursorPos(p.x, p.y);
  811. if(LGLW_MOUSE_GRAB_WARP != lglw->mouse.grab.mode)
  812. {
  813. lglw->mouse.p.x = p.x;
  814. lglw->mouse.p.y = p.y;
  815. }
  816. }
  817. }
  818. }
  819. }
  820. // ---------------------------------------------------------------------------- loc_handle_queued_mouse_warp
  821. static void loc_handle_queued_mouse_warp(lglw_int_t *lglw) {
  822. if(lglw->mouse.grab.b_queue_warp)
  823. {
  824. lglw->mouse.grab.b_queue_warp = LGLW_FALSE;
  825. lglw_mouse_warp(lglw, lglw->mouse.grab.p.x, lglw->mouse.grab.p.y);
  826. lglw->mouse.grab.last_p = lglw->mouse.grab.p;
  827. }
  828. }
  829. // ---------------------------------------------------------------------------- lglw_mouse_cursor_show
  830. void lglw_mouse_cursor_show (lglw_t _lglw, lglw_bool_t _bShow) {
  831. LGLW(_lglw);
  832. if(NULL != lglw)
  833. {
  834. if(NULL != lglw->win.hwnd)
  835. {
  836. (void)ShowCursor(_bShow);
  837. }
  838. }
  839. }
  840. // ---------------------------------------------------------------------------- lglw_timer_start
  841. void lglw_timer_start(lglw_t _lglw, uint32_t _millisec) {
  842. LGLW(_lglw);
  843. if(NULL != lglw)
  844. {
  845. if(NULL != lglw->win.hwnd)
  846. {
  847. (void)SetTimer(lglw->win.hwnd, 1/*nIDEvent*/, _millisec, NULL/*lpTimerFunc*/);
  848. lglw->timer.b_running = LGLW_TRUE;
  849. }
  850. }
  851. }
  852. // ---------------------------------------------------------------------------- lglw_timer_stop
  853. void lglw_timer_stop(lglw_t _lglw) {
  854. LGLW(_lglw);
  855. if(NULL != lglw)
  856. {
  857. if(NULL != lglw->win.hwnd)
  858. {
  859. if(lglw->timer.b_running)
  860. {
  861. (void)KillTimer(lglw->win.hwnd, 1/*nIDEvent*/);
  862. lglw->timer.b_running = LGLW_FALSE;
  863. }
  864. }
  865. }
  866. }
  867. // ---------------------------------------------------------------------------- lglw_timer_callback_set
  868. void lglw_timer_callback_set(lglw_t _lglw, lglw_timer_fxn_t _cbk) {
  869. LGLW(_lglw);
  870. if(NULL != lglw)
  871. {
  872. lglw->timer.cbk = _cbk;
  873. }
  874. }
  875. // ---------------------------------------------------------------------------- lglw_time_get_millisec
  876. uint32_t lglw_time_get_millisec(lglw_t _lglw) {
  877. uint32_t r = 0u;
  878. LGLW(_lglw);
  879. if(NULL != lglw)
  880. {
  881. r = GetTickCount();
  882. }
  883. return r;
  884. }
  885. // ---------------------------------------------------------------------------- loc_enable_dropfiles
  886. static void loc_enable_dropfiles(lglw_int_t *lglw, lglw_bool_t _bEnable) {
  887. if(NULL != lglw->win.hwnd)
  888. {
  889. DragAcceptFiles(lglw->win.hwnd, _bEnable ? TRUE : FALSE);
  890. }
  891. }
  892. // ---------------------------------------------------------------------------- lglw_dropfiles_callback_set
  893. void lglw_dropfiles_callback_set(lglw_t _lglw, lglw_dropfiles_fxn_t _cbk) {
  894. LGLW(_lglw);
  895. if(NULL != _lglw)
  896. {
  897. lglw->dropfiles.cbk = _cbk;
  898. loc_enable_dropfiles(lglw, (NULL != _cbk));
  899. }
  900. }
  901. // ---------------------------------------------------------------------------- loc_touchinput_update
  902. typedef void (*EnableMouseInPointer_fxn_t)(BOOL fEnable);
  903. static void loc_touchinput_update(lglw_int_t *lglw) {
  904. HMODULE hDLL = LoadLibrary("User32.dll");
  905. if(NULL != hDLL)
  906. {
  907. EnableMouseInPointer_fxn_t enableMouseInPointer = (EnableMouseInPointer_fxn_t)
  908. GetProcAddress(hDLL, "EnableMouseInPointer");
  909. if(NULL != enableMouseInPointer)
  910. {
  911. Dprintf("[dbg] lglw: EnableMouseInPointer() detected (win8+)\n");
  912. (void)enableMouseInPointer(lglw->mouse.touch.b_enable);
  913. }
  914. FreeLibrary(hDLL);
  915. }
  916. }
  917. // ---------------------------------------------------------------------------- lglw_touchinput_set
  918. void lglw_touchinput_set(lglw_t _lglw, lglw_bool_t _bEnable) {
  919. LGLW(_lglw);
  920. if(NULL != _lglw)
  921. {
  922. lglw->mouse.touch.b_enable = _bEnable;
  923. lglw->mouse.touch.b_update_queued = LGLW_TRUE;
  924. }
  925. }
  926. // ---------------------------------------------------------------------------- lglw_touchinput_get
  927. lglw_bool_t lglw_touchinput_get(lglw_t _lglw) {
  928. lglw_bool_t r = LGLW_FALSE;
  929. LGLW(_lglw);
  930. if(NULL != _lglw)
  931. {
  932. r = lglw->mouse.touch.b_enable;
  933. }
  934. return r;
  935. }
  936. // ---------------------------------------------------------------------------- lglw_clipboard_text_set
  937. void lglw_clipboard_text_set(lglw_t _lglw, const uint32_t _numChars, const char *_text) {
  938. LGLW(_lglw);
  939. (void)_numChars;
  940. if(NULL != _text)
  941. {
  942. if(NULL != _lglw)
  943. {
  944. if(NULL != lglw->win.hwnd)
  945. {
  946. uint32_t numChars = (0u == _numChars) ? ((uint32_t)strlen(_text)+1u) : _numChars;
  947. if(numChars > 0u)
  948. {
  949. if(OpenClipboard(lglw->win.hwnd))
  950. {
  951. HANDLE hGlobal = GlobalAlloc(GMEM_MOVEABLE, numChars * sizeof(TCHAR));
  952. if(NULL != hGlobal)
  953. {
  954. char *d = (char*) GlobalLock(hGlobal);
  955. if(NULL != d)
  956. {
  957. uint32_t i;
  958. for(i = 0u; i < numChars; i++)
  959. {
  960. d[i] = _text[i];
  961. }
  962. d[numChars - 1] = 0;
  963. Dprintf("xxx lglw_clipboard_text_set: SetClipboardData(\"%s\")\n", d);
  964. GlobalUnlock(hGlobal);
  965. (void)SetClipboardData(CF_TEXT, hGlobal);
  966. }
  967. }
  968. CloseClipboard();
  969. }
  970. }
  971. }
  972. }
  973. }
  974. }
  975. // ---------------------------------------------------------------------------- lglw_clipboard_text_get
  976. void lglw_clipboard_text_get(lglw_t _lglw, uint32_t _maxChars, uint32_t *_retNumChars, char *_retText) {
  977. LGLW(_lglw);
  978. if(NULL != _retNumChars)
  979. *_retNumChars = 0u;
  980. if(NULL != _retText)
  981. *_retText = 0;
  982. if(_maxChars > 0u)
  983. {
  984. if(NULL != _lglw)
  985. {
  986. if(NULL != lglw->win.hwnd)
  987. {
  988. if(OpenClipboard(lglw->win.hwnd))
  989. {
  990. const char *data = (const char*)GetClipboardData(CF_TEXT);
  991. Dprintf("xxx lglw_clipboard_text_get: data=\"%s\"\n", data);
  992. if(NULL != data)
  993. {
  994. uint32_t i = 0u;
  995. for(; i < _maxChars; i++)
  996. {
  997. _retText[i] = data[i];
  998. if(0 == _retText[i])
  999. break;
  1000. }
  1001. _retText[_maxChars - 1u] = 0; // ASCIIZ
  1002. if(NULL != _retNumChars)
  1003. {
  1004. *_retNumChars = i;
  1005. }
  1006. }
  1007. CloseClipboard();
  1008. }
  1009. }
  1010. }
  1011. }
  1012. }
  1013. // ---------------------------------------------------------------------------- loc_LowLevelKeyboardProc
  1014. static LRESULT CALLBACK loc_LowLevelKeyboardProc(int nCode, WPARAM wParam, LPARAM lParam) {
  1015. Dprintf("xxx lglw:loc_LowLevelKeyboardProc: wParam=0x%08x lParam=0x%08x\n", (uint32_t)wParam, (uint32_t)lParam);
  1016. if(HC_ACTION == nCode)
  1017. {
  1018. if(NULL != khook_lglw)
  1019. {
  1020. KBDLLHOOKSTRUCT *hs = (KBDLLHOOKSTRUCT*)lParam;
  1021. lglw_bool_t bHandled = LGLW_FALSE;
  1022. switch(wParam)
  1023. {
  1024. default:
  1025. break;
  1026. case WM_KEYDOWN:
  1027. // Dprintf("xxx lglw:loc_LowLevelKeyboardProc: WM_KEYDOWN vkCode=0x%08x scanCode=0x%08x bExt=%d\n", hs->vkCode, hs->scanCode, (0 != (hs->flags & LLKHF_EXTENDED)));
  1028. switch(hs->vkCode)
  1029. {
  1030. default:
  1031. if(0u == (hs->flags & LLKHF_EXTENDED))
  1032. {
  1033. uint16_t ucBuf[16];
  1034. BYTE keyState[256];
  1035. // Dprintf("xxx lglw call toUnicode\n");
  1036. GetKeyboardState(keyState);
  1037. // don't let e.g. ctrl-<a..z> produce symbol chars
  1038. keyState[VK_CONTROL] = 0;
  1039. keyState[VK_LCONTROL] = 0;
  1040. keyState[VK_RCONTROL] = 0;
  1041. if(ToUnicode(hs->vkCode, hs->scanCode, keyState, (LPWSTR)ucBuf, 8/*cchBuff*/, 0/*wFlags*/) >= 1)
  1042. {
  1043. // Dprintf("xxx lglw toUnicode: ucBuf[0]=0x%04x\n", ucBuf[0]);
  1044. bHandled = loc_handle_key(khook_lglw, LGLW_TRUE/*bPressed*/, ucBuf[0]);
  1045. }
  1046. else
  1047. {
  1048. Dprintf("xxx lglw:loc_LowLevelKeyboardProc<down>: ToUnicode failed\n");
  1049. }
  1050. }
  1051. else
  1052. {
  1053. bHandled = loc_handle_key(khook_lglw, LGLW_TRUE/*bPressed*/, hs->vkCode | LGLW_VKEY_EXT);
  1054. bHandled = LGLW_FALSE;
  1055. }
  1056. break;
  1057. case VK_F1:
  1058. case VK_F2:
  1059. case VK_F3:
  1060. case VK_F4:
  1061. case VK_F5:
  1062. case VK_F6:
  1063. case VK_F7:
  1064. case VK_F8:
  1065. case VK_F9:
  1066. case VK_F10:
  1067. case VK_F11:
  1068. case VK_F12:
  1069. case VK_BACK:
  1070. case VK_TAB:
  1071. case VK_RETURN:
  1072. case VK_ESCAPE:
  1073. bHandled = loc_handle_key(khook_lglw, LGLW_TRUE/*bPressed*/, hs->vkCode | LGLW_VKEY_EXT);
  1074. break;
  1075. case VK_LSHIFT:
  1076. // Dprintf("xxx lglw:loc_LowLevelKeyboardProc<down>: VK_LSHIFT\n");
  1077. khook_lglw->keyboard.kmod_state |= LGLW_KMOD_LSHIFT;
  1078. bHandled = loc_handle_key(khook_lglw, LGLW_TRUE/*bPressed*/, LGLW_VKEY_LSHIFT);
  1079. bHandled = LGLW_FALSE;
  1080. break;
  1081. case VK_RSHIFT:
  1082. // Dprintf("xxx lglw:loc_LowLevelKeyboardProc<down>: VK_RSHIFT\n");
  1083. khook_lglw->keyboard.kmod_state |= LGLW_KMOD_RSHIFT;
  1084. bHandled = loc_handle_key(khook_lglw, LGLW_TRUE/*bPressed*/, LGLW_VKEY_RSHIFT);
  1085. bHandled = LGLW_FALSE;
  1086. break;
  1087. case VK_LCONTROL:
  1088. // Dprintf("xxx lglw:loc_LowLevelKeyboardProc<down>: VK_LCONTROL\n");
  1089. khook_lglw->keyboard.kmod_state |= LGLW_KMOD_LCTRL;
  1090. bHandled = loc_handle_key(khook_lglw, LGLW_TRUE/*bPressed*/, LGLW_VKEY_LCTRL);
  1091. bHandled = LGLW_FALSE;
  1092. break;
  1093. case VK_RCONTROL:
  1094. // Dprintf("xxx lglw:loc_LowLevelKeyboardProc<down>: VK_RCONTROL\n");
  1095. khook_lglw->keyboard.kmod_state |= LGLW_KMOD_RCTRL;
  1096. bHandled = loc_handle_key(khook_lglw, LGLW_TRUE/*bPressed*/, LGLW_VKEY_RCTRL);
  1097. bHandled = LGLW_FALSE;
  1098. break;
  1099. case VK_LMENU:
  1100. // Dprintf("xxx lglw:loc_LowLevelKeyboardProc<down>: VK_LALT\n");
  1101. khook_lglw->keyboard.kmod_state |= LGLW_KMOD_LALT;
  1102. bHandled = loc_handle_key(khook_lglw, LGLW_TRUE/*bPressed*/, LGLW_VKEY_LALT);
  1103. bHandled = LGLW_FALSE;
  1104. break;
  1105. case VK_RMENU:
  1106. // Dprintf("xxx lglw:loc_LowLevelKeyboardProc<down>: VK_RALT\n");
  1107. khook_lglw->keyboard.kmod_state |= LGLW_KMOD_RALT;
  1108. bHandled = loc_handle_key(khook_lglw, LGLW_TRUE/*bPressed*/, LGLW_VKEY_RALT);
  1109. bHandled = LGLW_FALSE;
  1110. break;
  1111. // //case VK_RWIN:
  1112. // //case VK_F1:
  1113. // case VK_LMENU:
  1114. // // not received
  1115. // // Dprintf("xxx lglw:loc_LowLevelKeyboardProc<down>: VK_LMENU\n");
  1116. // khook_lglw->keyboard.kmod_state |= LGLW_KMOD_LSUPER;
  1117. // bHandled = loc_handle_key(khook_lglw, LGLW_TRUE/*bPressed*/, LGLW_VKEY_LSUPER);
  1118. // bHandled = LGLW_FALSE;
  1119. // break;
  1120. case 0x5D/*VK_CONTEXTKEY*/:
  1121. // Dprintf("xxx lglw:loc_LowLevelKeyboardProc<down>: VK_RMENU\n");
  1122. khook_lglw->keyboard.kmod_state |= LGLW_KMOD_RSUPER;
  1123. bHandled = loc_handle_key(khook_lglw, LGLW_TRUE/*bPressed*/, LGLW_VKEY_RSUPER);
  1124. bHandled = LGLW_FALSE;
  1125. break;
  1126. }
  1127. break;
  1128. case WM_KEYUP:
  1129. // Dprintf("xxx lglw:loc_LowLevelKeyboardProc: WM_KEYUP vkCode=0x%08x scanCode=0x%08x bExt=%d\n", hs->vkCode, hs->scanCode, (0 != (hs->flags & LLKHF_EXTENDED)));
  1130. switch(hs->vkCode)
  1131. {
  1132. default:
  1133. if(0u == (hs->flags & LLKHF_EXTENDED))
  1134. {
  1135. uint16_t ucBuf[16];
  1136. BYTE keyState[256];
  1137. GetKeyboardState(keyState);
  1138. if(ToUnicode(hs->vkCode, hs->scanCode, keyState, (LPWSTR)ucBuf, 8/*cchBuff*/, 0/*wFlags*/) >= 1)
  1139. {
  1140. bHandled = loc_handle_key(khook_lglw, LGLW_FALSE/*bPressed*/, ucBuf[0]);
  1141. }
  1142. }
  1143. else
  1144. {
  1145. bHandled = loc_handle_key(khook_lglw, LGLW_FALSE/*bPressed*/, hs->vkCode | LGLW_VKEY_EXT);
  1146. bHandled = LGLW_FALSE;
  1147. }
  1148. break;
  1149. case VK_F1:
  1150. case VK_F2:
  1151. case VK_F3:
  1152. case VK_F4:
  1153. case VK_F5:
  1154. case VK_F6:
  1155. case VK_F7:
  1156. case VK_F8:
  1157. case VK_F9:
  1158. case VK_F10:
  1159. case VK_F11:
  1160. case VK_F12:
  1161. case VK_BACK:
  1162. case VK_TAB:
  1163. case VK_RETURN:
  1164. case VK_ESCAPE:
  1165. bHandled = loc_handle_key(khook_lglw, LGLW_FALSE/*bPressed*/, hs->vkCode | LGLW_VKEY_EXT);
  1166. break;
  1167. case VK_LSHIFT:
  1168. khook_lglw->keyboard.kmod_state &= ~LGLW_KMOD_LSHIFT;
  1169. bHandled = loc_handle_key(khook_lglw, LGLW_FALSE/*bPressed*/, LGLW_VKEY_LSHIFT);
  1170. bHandled = LGLW_FALSE;
  1171. break;
  1172. case VK_RSHIFT:
  1173. khook_lglw->keyboard.kmod_state &= ~LGLW_KMOD_RSHIFT;
  1174. bHandled = loc_handle_key(khook_lglw, LGLW_FALSE/*bPressed*/, LGLW_VKEY_RSHIFT);
  1175. bHandled = LGLW_FALSE;
  1176. break;
  1177. case VK_LCONTROL:
  1178. khook_lglw->keyboard.kmod_state &= ~LGLW_KMOD_LCTRL;
  1179. bHandled = loc_handle_key(khook_lglw, LGLW_FALSE/*bPressed*/, LGLW_VKEY_LCTRL);
  1180. bHandled = LGLW_FALSE;
  1181. break;
  1182. case VK_RCONTROL:
  1183. khook_lglw->keyboard.kmod_state &= ~LGLW_KMOD_RCTRL;
  1184. bHandled = loc_handle_key(khook_lglw, LGLW_FALSE/*bPressed*/, LGLW_VKEY_RCTRL);
  1185. bHandled = LGLW_FALSE;
  1186. break;
  1187. case VK_LMENU:
  1188. khook_lglw->keyboard.kmod_state &= ~LGLW_KMOD_LALT;
  1189. bHandled = loc_handle_key(khook_lglw, LGLW_FALSE/*bPressed*/, LGLW_VKEY_LALT);
  1190. bHandled = LGLW_FALSE;
  1191. break;
  1192. case VK_RMENU:
  1193. khook_lglw->keyboard.kmod_state &= ~LGLW_KMOD_RALT;
  1194. bHandled = loc_handle_key(khook_lglw, LGLW_FALSE/*bPressed*/, LGLW_VKEY_RALT);
  1195. bHandled = LGLW_FALSE;
  1196. break;
  1197. // case VK_LMENU: // not revc'd
  1198. // khook_lglw->keyboard.kmod_state &= ~LGLW_KMOD_LSUPER;
  1199. // bHandled = loc_handle_key(khook_lglw, LGLW_FALSE/*bPressed*/, LGLW_VKEY_LSUPER);
  1200. // bHandled = LGLW_FALSE;
  1201. // break;
  1202. case 0x5D/*VK_CONTEXTKEY*/:
  1203. khook_lglw->keyboard.kmod_state &= ~LGLW_KMOD_RSUPER;
  1204. bHandled = loc_handle_key(khook_lglw, LGLW_FALSE/*bPressed*/, LGLW_VKEY_RSUPER);
  1205. bHandled = LGLW_FALSE;
  1206. break;
  1207. }
  1208. break;
  1209. }
  1210. if(!bHandled)
  1211. {
  1212. Dprintf("xxx lglw: CallNextHookEx<kbd>\n");
  1213. return CallNextHookEx(NULL, nCode, wParam, lParam);
  1214. }
  1215. else
  1216. {
  1217. Dprintf("xxx lglw: CallNextHookEx<kbd>: was handled\n");
  1218. return 1;
  1219. }
  1220. } // if khook_lglw
  1221. }
  1222. return CallNextHookEx(NULL, nCode, wParam, lParam);
  1223. }
  1224. // ---------------------------------------------------------------------------- loc_WndProc
  1225. LRESULT CALLBACK loc_WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) {
  1226. LGLW(GetWindowLongPtr(hWnd, GWLP_USERDATA));
  1227. if(NULL != lglw)
  1228. {
  1229. // Dprintf("xxx lglw:loc_WndProc: message=%08x wParam=0x%08x lParam=0x%08x\n", message, (uint32_t)wParam, (uint32_t)lParam);
  1230. switch(message)
  1231. {
  1232. case WM_CREATE:
  1233. Dprintf("xxx lglw: WM_CREATE\n");
  1234. break;
  1235. case WM_DESTROY:
  1236. Dprintf("xxx lglw: WM_DESTROY\n");
  1237. break;
  1238. case WM_ACTIVATEAPP: // 0x1c wParam=0/1
  1239. Dprintf("xxx lglw: WM_ACTIVATEAPP wParam=%d\n", (int32_t)wParam);
  1240. break;
  1241. case WM_MOUSELEAVE:
  1242. // (note) only received after TrackMouseEvent() has been called
  1243. Dprintf("xxx lglw: WM_MOUSELEAVE\n");
  1244. loc_handle_mouseleave(lglw);
  1245. break;
  1246. case WM_MOUSEMOVE:
  1247. // Dprintf("xxx lglw: WM_MOUSEMOVE:\n");
  1248. if(lglw->mouse.touch.b_update_queued)
  1249. {
  1250. loc_touchinput_update(lglw);
  1251. lglw->mouse.touch.b_update_queued = LGLW_FALSE;
  1252. }
  1253. if(!lglw->mouse.touch.b_enable)
  1254. {
  1255. int32_t x = GET_X_LPARAM(lParam); // lo
  1256. int32_t y = GET_Y_LPARAM(lParam); // hi
  1257. if(LGLW_MOUSE_GRAB_WARP == lglw->mouse.grab.mode)
  1258. {
  1259. lglw->mouse.grab.b_queue_warp = LGLW_TRUE;
  1260. lglw->mouse.p.x += (x - lglw->mouse.grab.last_p.x);
  1261. lglw->mouse.p.y += (y - lglw->mouse.grab.last_p.y);
  1262. lglw->mouse.grab.last_p.x = x;
  1263. lglw->mouse.grab.last_p.y = y;
  1264. }
  1265. else
  1266. {
  1267. lglw->mouse.p.x = x;
  1268. lglw->mouse.p.y = y;
  1269. }
  1270. if(0u == (lglw->focus.state & LGLW_FOCUS_MOUSE))
  1271. {
  1272. loc_handle_mouseenter(lglw);
  1273. }
  1274. loc_handle_mousemotion(lglw);
  1275. }
  1276. break;
  1277. case WM_LBUTTONDOWN:
  1278. if(!lglw->mouse.touch.b_enable)
  1279. {
  1280. // Dprintf("xxx lglw: WM_LBUTTONDOWN\n");
  1281. loc_handle_mousebutton(lglw, LGLW_TRUE/*bPressed*/, LGLW_MOUSE_LBUTTON);
  1282. }
  1283. break;
  1284. case WM_LBUTTONUP:
  1285. if(!lglw->mouse.touch.b_enable)
  1286. {
  1287. // Dprintf("xxx lglw: WM_LBUTTONUP\n");
  1288. loc_handle_mousebutton(lglw, LGLW_FALSE/*bPressed*/, LGLW_MOUSE_LBUTTON);
  1289. }
  1290. break;
  1291. case WM_RBUTTONDOWN:
  1292. if(!lglw->mouse.touch.b_enable)
  1293. {
  1294. // Dprintf("xxx lglw: WM_RBUTTONDOWN\n");
  1295. loc_handle_mousebutton(lglw, LGLW_TRUE/*bPressed*/, LGLW_MOUSE_RBUTTON);
  1296. }
  1297. break;
  1298. case WM_RBUTTONUP:
  1299. if(!lglw->mouse.touch.b_enable)
  1300. {
  1301. // Dprintf("xxx lglw: WM_RBUTTONUP\n");
  1302. loc_handle_mousebutton(lglw, LGLW_FALSE/*bPressed*/, LGLW_MOUSE_RBUTTON);
  1303. }
  1304. break;
  1305. case WM_MBUTTONDOWN:
  1306. if(!lglw->mouse.touch.b_enable)
  1307. {
  1308. // Dprintf("xxx lglw: WM_MBUTTONDOWN\n");
  1309. loc_handle_mousebutton(lglw, LGLW_TRUE/*bPressed*/, LGLW_MOUSE_MBUTTON);
  1310. }
  1311. break;
  1312. case WM_MBUTTONUP:
  1313. if(!lglw->mouse.touch.b_enable)
  1314. {
  1315. // Dprintf("xxx lglw: WM_MBUTTONUP\n");
  1316. loc_handle_mousebutton(lglw, LGLW_FALSE/*bPressed*/, LGLW_MOUSE_MBUTTON);
  1317. }
  1318. break;
  1319. case WM_MOUSEWHEEL:
  1320. // Dprintf("xxx lglw: WM_MOUSEWHEEL\n");
  1321. {
  1322. uint32_t bt = (((int16_t)(((uint32_t)wParam)>>16)) > 0) ? LGLW_MOUSE_WHEELUP : LGLW_MOUSE_WHEELDOWN;
  1323. loc_handle_mousebutton(lglw, LGLW_TRUE/*bPressed*/, bt);
  1324. loc_handle_mousebutton(lglw, LGLW_FALSE/*bPressed*/, bt);
  1325. }
  1326. break;
  1327. case WM_CAPTURECHANGED:
  1328. // e.g. after alt-tab
  1329. Dprintf("xxx lglw: WM_CAPTURECHANGED\n");
  1330. lglw->mouse.grab.mode = LGLW_MOUSE_GRAB_NONE;
  1331. break;
  1332. #if 1
  1333. // (note) VST windows usually don't receive key/char messages (they are consumed by the DAW)
  1334. case WM_GETDLGCODE:
  1335. // never received
  1336. Dprintf("xxx lglw: WM_GETDLGCODE\n");
  1337. return DLGC_WANTALLKEYS;
  1338. case WM_KEYDOWN:
  1339. // never received
  1340. Dprintf("xxx lglw: WM_KEYDOWN nVirtKey=0x%08x lKeydata=0x%08x\n", (uint32_t)wParam, (uint32_t)lParam);
  1341. break;
  1342. case WM_KEYUP:
  1343. // never received
  1344. Dprintf("xxx lglw: WM_KEYUP nVirtKey=0x%08x lKeydata=0x%08x\n", (uint32_t)wParam, (uint32_t)lParam);
  1345. break;
  1346. case WM_CHAR:
  1347. // never received
  1348. Dprintf("xxx lglw: WM_CHAR charCode=0x%08x bPressed=%u\n", (uint32_t)wParam, (((uint32_t)lParam)>>31)&1u);
  1349. break;
  1350. #endif
  1351. case WM_PAINT:
  1352. // https://docs.microsoft.com/en-us/windows/desktop/api/Winuser/nf-winuser-redrawwindow
  1353. // Dprintf("xxx lglw: WM_PAINT\n");
  1354. loc_handle_queued_mouse_warp(lglw);
  1355. if(NULL != lglw->redraw.cbk)
  1356. {
  1357. lglw->redraw.cbk(lglw);
  1358. }
  1359. break;
  1360. case WM_TIMER:
  1361. // Dprintf("xxx lglw: WM_TIMER cbk=%p\n", lglw->timer.cbk);
  1362. if(lglw->mouse.touch.b_enable)
  1363. {
  1364. // Dprintf("xxx lglw: WM_TIMER hold_state=%u\n", lglw->mouse.touch.syn_rmb_hold_state);
  1365. if(LGLW_MOUSE_TOUCH_RMB_STATE_IDLE != lglw->mouse.touch.syn_rmb_hold_state)
  1366. {
  1367. uint32_t ms = (uint32_t)GetTickCount();
  1368. uint32_t delta;
  1369. if(ms < lglw->mouse.touch.hold_start_ms)
  1370. {
  1371. // Overflow after 49.7 days
  1372. delta = ~lglw->mouse.touch.hold_start_ms + 1u + ms;
  1373. }
  1374. else
  1375. {
  1376. delta = (ms - lglw->mouse.touch.hold_start_ms);
  1377. }
  1378. if(LGLW_MOUSE_TOUCH_RMB_STATE_LMB == lglw->mouse.touch.syn_rmb_hold_state)
  1379. {
  1380. if(delta >= LGLW_MOUSE_TOUCH_LMB_TIMEOUT)
  1381. {
  1382. loc_handle_mousebutton(lglw, LGLW_FALSE/*bPressed*/, LGLW_MOUSE_LBUTTON);
  1383. lglw->mouse.touch.syn_rmb_hold_state = LGLW_MOUSE_TOUCH_RMB_STATE_WAIT;
  1384. }
  1385. }
  1386. if(LGLW_MOUSE_TOUCH_RMB_STATE_WAIT == lglw->mouse.touch.syn_rmb_hold_state)
  1387. {
  1388. if(delta >= LGLW_MOUSE_TOUCH_RMB_TIMEOUT)
  1389. {
  1390. lglw->mouse.touch.syn_rmb_hold_state = LGLW_MOUSE_TOUCH_RMB_STATE_RMB;
  1391. loc_handle_mousebutton(lglw, LGLW_TRUE/*bPressed*/, LGLW_MOUSE_RBUTTON);
  1392. }
  1393. }
  1394. }
  1395. }
  1396. else
  1397. {
  1398. loc_handle_queued_mouse_warp(lglw);
  1399. }
  1400. if(NULL != lglw->timer.cbk)
  1401. {
  1402. lglw->timer.cbk(lglw);
  1403. }
  1404. break;
  1405. case WM_DROPFILES:
  1406. if(NULL != lglw->dropfiles.cbk)
  1407. {
  1408. HDROP hDrop = (HDROP) wParam;
  1409. POINT p;
  1410. if(TRUE == DragQueryPoint(hDrop, &p))
  1411. {
  1412. Dprintf("xxx lglw: WM_DROPFILES: p=(%d; %d)\n", p.x, p.y);
  1413. UINT numFiles = DragQueryFile(hDrop, 0xffffffff, NULL, 0);
  1414. Dprintf("xxx lglw: WM_DROPFILES: dropped %u file(s)\n", numFiles);
  1415. if(numFiles > 0u)
  1416. {
  1417. UINT i;
  1418. char **pathnames = malloc((sizeof(char*) * numFiles) + (MAX_PATH * sizeof(char) * numFiles));
  1419. char *pathname = (char*)&pathnames[numFiles];
  1420. for(i=0; i<numFiles; i++)
  1421. {
  1422. DragQueryFile(hDrop, i, pathname, MAX_PATH);
  1423. Dprintf("xxx lglw: WM_DROPFILES: file[%d] = \"%s\"\n", i, pathname);
  1424. pathnames[i] = pathname;
  1425. pathname += MAX_PATH;
  1426. }
  1427. lglw->dropfiles.cbk(lglw, p.x, p.y, numFiles, pathnames);
  1428. free(pathnames);
  1429. }
  1430. }
  1431. }
  1432. break;
  1433. #ifdef BUILD_64
  1434. // Touch messages:
  1435. #ifndef GET_X_LPARAM
  1436. #define GET_X_LPARAM(lp) ((int)(short)LOWORD(lp))
  1437. #define GET_Y_LPARAM(lp) ((int)(short)HIWORD(lp))
  1438. #define GET_POINTERID_WPARAM(wParam) (LOWORD(wParam))
  1439. #define IS_POINTER_FLAG_SET_WPARAM(wParam, flag) (((DWORD)HIWORD(wParam) & (flag)) == (flag))
  1440. #define IS_POINTER_NEW_WPARAM(wParam) IS_POINTER_FLAG_SET_WPARAM(wParam, POINTER_MESSAGE_FLAG_NEW)
  1441. #define IS_POINTER_INRANGE_WPARAM(wParam) IS_POINTER_FLAG_SET_WPARAM(wParam, POINTER_MESSAGE_FLAG_INRANGE)
  1442. #define IS_POINTER_INCONTACT_WPARAM(wParam) IS_POINTER_FLAG_SET_WPARAM(wParam, POINTER_MESSAGE_FLAG_INCONTACT)
  1443. #define IS_POINTER_FIRSTBUTTON_WPARAM(wParam) IS_POINTER_FLAG_SET_WPARAM(wParam, POINTER_MESSAGE_FLAG_FIRSTBUTTON)
  1444. #define IS_POINTER_SECONDBUTTON_WPARAM(wParam) IS_POINTER_FLAG_SET_WPARAM(wParam, POINTER_MESSAGE_FLAG_SECONDBUTTON)
  1445. #define IS_POINTER_THIRDBUTTON_WPARAM(wParam) IS_POINTER_FLAG_SET_WPARAM(wParam, POINTER_MESSAGE_FLAG_THIRDBUTTON)
  1446. #define IS_POINTER_FOURTHBUTTON_WPARAM(wParam) IS_POINTER_FLAG_SET_WPARAM(wParam, POINTER_MESSAGE_FLAG_FOURTHBUTTON)
  1447. #define IS_POINTER_FIFTHBUTTON_WPARAM(wParam) IS_POINTER_FLAG_SET_WPARAM(wParam, POINTER_MESSAGE_FLAG_FIFTHBUTTON)
  1448. #define IS_POINTER_PRIMARY_WPARAM(wParam) IS_POINTER_FLAG_SET_WPARAM(wParam, POINTER_MESSAGE_FLAG_PRIMARY)
  1449. #define HAS_POINTER_CONFIDENCE_WPARAM(wParam) IS_POINTER_FLAG_SET_WPARAM(wParam, POINTER_MESSAGE_FLAG_CONFIDENCE)
  1450. #define IS_POINTER_CANCELED_WPARAM(wParam) IS_POINTER_FLAG_SET_WPARAM(wParam, POINTER_MESSAGE_FLAG_CANCELED)
  1451. #endif
  1452. case WM_POINTERDOWN:
  1453. {
  1454. POINT p;
  1455. lglw->mouse.touch.b_enable = LGLW_TRUE;
  1456. lglw->mouse.touch.b_update_queued = LGLW_FALSE;
  1457. if(0u == (lglw->focus.state & LGLW_FOCUS_MOUSE))
  1458. {
  1459. loc_handle_mouseenter(lglw);
  1460. }
  1461. // Dprintf("xxx lglw: WM_POINTERDOWN\n");
  1462. // Dprintf("xxx lglw: WM_POINTERDOWN: IS_POINTER_FIRSTBUTTON_WPARAM(wParam)=%d\n", IS_POINTER_FIRSTBUTTON_WPARAM(wParam));
  1463. // Dprintf("xxx lglw: WM_POINTERDOWN: IS_POINTER_SECONDBUTTON_WPARAM(wParam)=%d\n", IS_POINTER_SECONDBUTTON_WPARAM(wParam));
  1464. // Dprintf("xxx lglw: WM_POINTERDOWN: IS_POINTER_THIRDBUTTON_WPARAM(wParam)=%d\n", IS_POINTER_THIRDBUTTON_WPARAM(wParam));
  1465. p.x = GET_X_LPARAM(lParam);
  1466. p.y = GET_Y_LPARAM(lParam);
  1467. (void)ScreenToClient(lglw->win.hwnd, &p);
  1468. lglw->mouse.p.x = p.x;
  1469. lglw->mouse.p.y = p.y;
  1470. loc_handle_mousemotion(lglw);
  1471. if(IS_POINTER_FIRSTBUTTON_WPARAM(wParam))
  1472. {
  1473. lglw->mouse.touch.b_syn_rmb = (0u != (lglw->keyboard.kmod_state & LGLW_KMOD_CTRL));
  1474. loc_handle_mousebutton(lglw, LGLW_TRUE/*bPressed*/,
  1475. lglw->mouse.touch.b_syn_rmb ? LGLW_MOUSE_RBUTTON : LGLW_MOUSE_LBUTTON
  1476. );
  1477. if(lglw->mouse.touch.b_syn_rmb)
  1478. {
  1479. lglw->mouse.touch.syn_rmb_hold_state = LGLW_MOUSE_TOUCH_RMB_STATE_IDLE;
  1480. }
  1481. else
  1482. {
  1483. lglw->mouse.touch.syn_rmb_hold_state = LGLW_MOUSE_TOUCH_RMB_STATE_LMB;
  1484. lglw->mouse.touch.hold_start_ms = GetTickCount();
  1485. lglw->mouse.touch.hold_start_p = lglw->mouse.p;
  1486. }
  1487. }
  1488. else if(IS_POINTER_SECONDBUTTON_WPARAM(wParam))
  1489. {
  1490. loc_handle_mousebutton(lglw, LGLW_TRUE/*bPressed*/, LGLW_MOUSE_RBUTTON);
  1491. }
  1492. else if(IS_POINTER_THIRDBUTTON_WPARAM(wParam))
  1493. {
  1494. loc_handle_mousebutton(lglw, LGLW_TRUE/*bPressed*/, LGLW_MOUSE_MBUTTON);
  1495. }
  1496. }
  1497. break;
  1498. case WM_POINTERUP:
  1499. {
  1500. POINT p;
  1501. // Dprintf("xxx lglw: WM_POINTERUP\n");
  1502. lglw->mouse.touch.b_enable = LGLW_TRUE;
  1503. lglw->mouse.touch.b_update_queued = LGLW_FALSE;
  1504. p.x = GET_X_LPARAM(lParam);
  1505. p.y = GET_Y_LPARAM(lParam);
  1506. (void)ScreenToClient(lglw->win.hwnd, &p);
  1507. lglw->mouse.p.x = p.x;
  1508. lglw->mouse.p.y = p.y;
  1509. loc_handle_mousemotion(lglw);
  1510. // Dprintf("xxx lglw: WM_POINTERUP: IS_POINTER_FIRSTBUTTON_WPARAM(wParam)=%d\n", IS_POINTER_FIRSTBUTTON_WPARAM(wParam));
  1511. // Dprintf("xxx lglw: WM_POINTERUP: IS_POINTER_SECONDBUTTON_WPARAM(wParam)=%d\n", IS_POINTER_SECONDBUTTON_WPARAM(wParam));
  1512. // Dprintf("xxx lglw: WM_POINTERUP: IS_POINTER_THIRDBUTTON_WPARAM(wParam)=%d\n", IS_POINTER_THIRDBUTTON_WPARAM(wParam));
  1513. if( (0u != (lglw->mouse.button_state & LGLW_MOUSE_LBUTTON)) && !IS_POINTER_FIRSTBUTTON_WPARAM(wParam) )
  1514. {
  1515. if(LGLW_MOUSE_TOUCH_RMB_STATE_RMB == lglw->mouse.touch.syn_rmb_hold_state)
  1516. {
  1517. loc_handle_mousebutton(lglw, LGLW_FALSE/*bPressed*/, LGLW_MOUSE_RBUTTON);
  1518. }
  1519. else
  1520. {
  1521. loc_handle_mousebutton(lglw, LGLW_FALSE/*bPressed*/,
  1522. lglw->mouse.touch.b_syn_rmb ? LGLW_MOUSE_RBUTTON : LGLW_MOUSE_LBUTTON
  1523. );
  1524. }
  1525. lglw->mouse.touch.b_syn_rmb = LGLW_FALSE;
  1526. lglw->mouse.touch.syn_rmb_hold_state = LGLW_MOUSE_TOUCH_RMB_STATE_IDLE;
  1527. }
  1528. else if( (0u != (lglw->mouse.button_state & LGLW_MOUSE_RBUTTON)) && !IS_POINTER_SECONDBUTTON_WPARAM(wParam))
  1529. {
  1530. loc_handle_mousebutton(lglw, LGLW_FALSE/*bPressed*/, LGLW_MOUSE_RBUTTON);
  1531. }
  1532. else if( (0u != (lglw->mouse.button_state & LGLW_MOUSE_MBUTTON)) && !IS_POINTER_THIRDBUTTON_WPARAM(wParam))
  1533. {
  1534. loc_handle_mousebutton(lglw, LGLW_FALSE/*bPressed*/, LGLW_MOUSE_MBUTTON);
  1535. }
  1536. }
  1537. break;
  1538. case WM_POINTERENTER:
  1539. {
  1540. POINT p;
  1541. Dprintf("xxx lglw: WM_POINTERENTER\n");
  1542. lglw->mouse.touch.b_enable = LGLW_TRUE;
  1543. lglw->mouse.touch.b_update_queued = LGLW_FALSE;
  1544. if(0u == (lglw->focus.state & LGLW_FOCUS_MOUSE))
  1545. {
  1546. loc_handle_mouseenter(lglw);
  1547. }
  1548. p.x = GET_X_LPARAM(lParam);
  1549. p.y = GET_Y_LPARAM(lParam);
  1550. (void)ScreenToClient(lglw->win.hwnd, &p);
  1551. lglw->mouse.p.x = p.x;
  1552. lglw->mouse.p.y = p.y;
  1553. loc_handle_mousemotion(lglw);
  1554. loc_handle_mouseenter(lglw);
  1555. }
  1556. break;
  1557. case WM_POINTERLEAVE:
  1558. {
  1559. POINT p;
  1560. Dprintf("xxx lglw: WM_POINTERLEAVE\n");
  1561. lglw->mouse.touch.b_enable = LGLW_TRUE;
  1562. lglw->mouse.touch.b_update_queued = LGLW_FALSE;
  1563. p.x = GET_X_LPARAM(lParam);
  1564. p.y = GET_Y_LPARAM(lParam);
  1565. (void)ScreenToClient(lglw->win.hwnd, &p);
  1566. loc_handle_mouseleave(lglw);
  1567. }
  1568. break;
  1569. case WM_POINTERUPDATE:
  1570. {
  1571. POINT p;
  1572. lglw->mouse.touch.b_enable = LGLW_TRUE;
  1573. lglw->mouse.touch.b_update_queued = LGLW_FALSE;
  1574. p.x = GET_X_LPARAM(lParam);
  1575. p.y = GET_Y_LPARAM(lParam);
  1576. (void)ScreenToClient(lglw->win.hwnd, &p);
  1577. lglw->mouse.p.x = p.x;
  1578. lglw->mouse.p.y = p.y;
  1579. loc_handle_mousemotion(lglw);
  1580. if(LGLW_MOUSE_TOUCH_RMB_STATE_LMB == lglw->mouse.touch.syn_rmb_hold_state)
  1581. {
  1582. if( (sABS(p.x - lglw->mouse.touch.hold_start_p.x) >= LGLW_MOUSE_TOUCH_RMB_MOVE_THRESHOLD) ||
  1583. (sABS(p.y - lglw->mouse.touch.hold_start_p.y) >= LGLW_MOUSE_TOUCH_RMB_MOVE_THRESHOLD)
  1584. )
  1585. {
  1586. lglw->mouse.touch.syn_rmb_hold_state = LGLW_MOUSE_TOUCH_RMB_STATE_IDLE;
  1587. }
  1588. }
  1589. }
  1590. break;
  1591. #endif // BUILD_64
  1592. } // switch message
  1593. } // if lglw
  1594. return DefWindowProc(hWnd, message, wParam, lParam);
  1595. }