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.

1896 lines
60KB

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