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.

1941 lines
62KB

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