main_windows.cpp 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882
  1. /*
  2. * Copyright (c) 2012-2022 Daniele Bartolini et al.
  3. * License: https://github.com/dbartolini/crown/blob/master/LICENSE
  4. */
  5. #include "config.h"
  6. #if CROWN_PLATFORM_WINDOWS
  7. #include "core/command_line.h"
  8. #include "core/containers/array.inl"
  9. #include "core/guid.h"
  10. #include "core/memory/globals.h"
  11. #include "core/memory/memory.inl"
  12. #include "core/thread/thread.h"
  13. #include "core/unit_tests.h"
  14. #include "device/device.h"
  15. #include "device/device_event_queue.inl"
  16. #include "resource/data_compiler.h"
  17. #include <bgfx/platform.h>
  18. #include <stdio.h> // FILE, freopen, stdio etc.
  19. #include <winsock2.h>
  20. #include <windowsx.h> // GET_X_LPARAM, GET_Y_LPARAM
  21. #include <xinput.h>
  22. #define STB_SPRINTF_IMPLEMENTATION
  23. #include <stb_sprintf.h>
  24. namespace crown
  25. {
  26. static KeyboardButton::Enum win_translate_key(s32 winkey)
  27. {
  28. switch (winkey)
  29. {
  30. case VK_BACK: return KeyboardButton::BACKSPACE;
  31. case VK_TAB: return KeyboardButton::TAB;
  32. case VK_SPACE: return KeyboardButton::SPACE;
  33. case VK_ESCAPE: return KeyboardButton::ESCAPE;
  34. case VK_RETURN: return KeyboardButton::ENTER;
  35. case VK_F1: return KeyboardButton::F1;
  36. case VK_F2: return KeyboardButton::F2;
  37. case VK_F3: return KeyboardButton::F3;
  38. case VK_F4: return KeyboardButton::F4;
  39. case VK_F5: return KeyboardButton::F5;
  40. case VK_F6: return KeyboardButton::F6;
  41. case VK_F7: return KeyboardButton::F7;
  42. case VK_F8: return KeyboardButton::F8;
  43. case VK_F9: return KeyboardButton::F9;
  44. case VK_F10: return KeyboardButton::F10;
  45. case VK_F11: return KeyboardButton::F11;
  46. case VK_F12: return KeyboardButton::F12;
  47. case VK_HOME: return KeyboardButton::HOME;
  48. case VK_LEFT: return KeyboardButton::LEFT;
  49. case VK_UP: return KeyboardButton::UP;
  50. case VK_RIGHT: return KeyboardButton::RIGHT;
  51. case VK_DOWN: return KeyboardButton::DOWN;
  52. case VK_PRIOR: return KeyboardButton::PAGE_UP;
  53. case VK_NEXT: return KeyboardButton::PAGE_DOWN;
  54. case VK_INSERT: return KeyboardButton::INS;
  55. case VK_DELETE: return KeyboardButton::DEL;
  56. case VK_END: return KeyboardButton::END;
  57. case VK_LSHIFT: return KeyboardButton::SHIFT_LEFT;
  58. case VK_RSHIFT: return KeyboardButton::SHIFT_RIGHT;
  59. case VK_LCONTROL: return KeyboardButton::CTRL_LEFT;
  60. case VK_RCONTROL: return KeyboardButton::CTRL_RIGHT;
  61. case VK_CAPITAL: return KeyboardButton::CAPS_LOCK;
  62. case VK_LMENU: return KeyboardButton::ALT_LEFT;
  63. case VK_RMENU: return KeyboardButton::ALT_RIGHT;
  64. case VK_LWIN: return KeyboardButton::SUPER_LEFT;
  65. case VK_RWIN: return KeyboardButton::SUPER_RIGHT;
  66. case VK_NUMLOCK: return KeyboardButton::NUM_LOCK;
  67. // case VK_RETURN: return KeyboardButton::NUMPAD_ENTER;
  68. case VK_DECIMAL: return KeyboardButton::NUMPAD_DELETE;
  69. case VK_MULTIPLY: return KeyboardButton::NUMPAD_MULTIPLY;
  70. case VK_ADD: return KeyboardButton::NUMPAD_ADD;
  71. case VK_SUBTRACT: return KeyboardButton::NUMPAD_SUBTRACT;
  72. case VK_DIVIDE: return KeyboardButton::NUMPAD_DIVIDE;
  73. case VK_NUMPAD0: return KeyboardButton::NUMPAD_0;
  74. case VK_NUMPAD1: return KeyboardButton::NUMPAD_1;
  75. case VK_NUMPAD2: return KeyboardButton::NUMPAD_2;
  76. case VK_NUMPAD3: return KeyboardButton::NUMPAD_3;
  77. case VK_NUMPAD4: return KeyboardButton::NUMPAD_4;
  78. case VK_NUMPAD5: return KeyboardButton::NUMPAD_5;
  79. case VK_NUMPAD6: return KeyboardButton::NUMPAD_6;
  80. case VK_NUMPAD7: return KeyboardButton::NUMPAD_7;
  81. case VK_NUMPAD8: return KeyboardButton::NUMPAD_8;
  82. case VK_NUMPAD9: return KeyboardButton::NUMPAD_9;
  83. case '0': return KeyboardButton::NUMBER_0;
  84. case '1': return KeyboardButton::NUMBER_1;
  85. case '2': return KeyboardButton::NUMBER_2;
  86. case '3': return KeyboardButton::NUMBER_3;
  87. case '4': return KeyboardButton::NUMBER_4;
  88. case '5': return KeyboardButton::NUMBER_5;
  89. case '6': return KeyboardButton::NUMBER_6;
  90. case '7': return KeyboardButton::NUMBER_7;
  91. case '8': return KeyboardButton::NUMBER_8;
  92. case '9': return KeyboardButton::NUMBER_9;
  93. case 'A': return KeyboardButton::A;
  94. case 'B': return KeyboardButton::B;
  95. case 'C': return KeyboardButton::C;
  96. case 'D': return KeyboardButton::D;
  97. case 'E': return KeyboardButton::E;
  98. case 'F': return KeyboardButton::F;
  99. case 'G': return KeyboardButton::G;
  100. case 'H': return KeyboardButton::H;
  101. case 'I': return KeyboardButton::I;
  102. case 'J': return KeyboardButton::J;
  103. case 'K': return KeyboardButton::K;
  104. case 'L': return KeyboardButton::L;
  105. case 'M': return KeyboardButton::M;
  106. case 'N': return KeyboardButton::N;
  107. case 'O': return KeyboardButton::O;
  108. case 'P': return KeyboardButton::P;
  109. case 'Q': return KeyboardButton::Q;
  110. case 'R': return KeyboardButton::R;
  111. case 'S': return KeyboardButton::S;
  112. case 'T': return KeyboardButton::T;
  113. case 'U': return KeyboardButton::U;
  114. case 'V': return KeyboardButton::V;
  115. case 'W': return KeyboardButton::W;
  116. case 'X': return KeyboardButton::X;
  117. case 'Y': return KeyboardButton::Y;
  118. case 'Z': return KeyboardButton::Z;
  119. default: return KeyboardButton::COUNT;
  120. }
  121. }
  122. struct XinputToJoypad
  123. {
  124. WORD bit;
  125. JoypadButton::Enum button;
  126. };
  127. static XinputToJoypad s_xinput_to_joypad[] =
  128. {
  129. { XINPUT_GAMEPAD_DPAD_UP, JoypadButton::UP },
  130. { XINPUT_GAMEPAD_DPAD_DOWN, JoypadButton::DOWN },
  131. { XINPUT_GAMEPAD_DPAD_LEFT, JoypadButton::LEFT },
  132. { XINPUT_GAMEPAD_DPAD_RIGHT, JoypadButton::RIGHT },
  133. { XINPUT_GAMEPAD_START, JoypadButton::START },
  134. { XINPUT_GAMEPAD_BACK, JoypadButton::BACK },
  135. { XINPUT_GAMEPAD_LEFT_THUMB, JoypadButton::THUMB_LEFT },
  136. { XINPUT_GAMEPAD_RIGHT_THUMB, JoypadButton::THUMB_RIGHT },
  137. { XINPUT_GAMEPAD_LEFT_SHOULDER, JoypadButton::SHOULDER_LEFT },
  138. { XINPUT_GAMEPAD_RIGHT_SHOULDER, JoypadButton::SHOULDER_RIGHT },
  139. { XINPUT_GAMEPAD_A, JoypadButton::A },
  140. { XINPUT_GAMEPAD_B, JoypadButton::B },
  141. { XINPUT_GAMEPAD_X, JoypadButton::X },
  142. { XINPUT_GAMEPAD_Y, JoypadButton::Y }
  143. };
  144. struct Joypad
  145. {
  146. struct Axis
  147. {
  148. s16 lx, ly, lz;
  149. s16 rx, ry, rz;
  150. };
  151. XINPUT_STATE _state[CROWN_MAX_JOYPADS];
  152. Axis _axis[CROWN_MAX_JOYPADS];
  153. bool _connected[CROWN_MAX_JOYPADS];
  154. Joypad()
  155. {
  156. memset(&_state, 0, sizeof(_state));
  157. memset(&_axis, 0, sizeof(_axis));
  158. memset(&_connected, 0, sizeof(_connected));
  159. }
  160. void update(DeviceEventQueue& queue)
  161. {
  162. for (u8 i = 0; i < CROWN_MAX_JOYPADS; ++i)
  163. {
  164. XINPUT_STATE state;
  165. memset(&state, 0, sizeof(state));
  166. const DWORD result = XInputGetState(i, &state);
  167. const bool connected = result == ERROR_SUCCESS;
  168. if (connected != _connected[i])
  169. queue.push_status_event(InputDeviceType::JOYPAD, i, connected);
  170. _connected[i] = connected;
  171. if (!connected || state.dwPacketNumber == _state[i].dwPacketNumber)
  172. continue;
  173. XINPUT_GAMEPAD& gamepad = _state[i].Gamepad;
  174. const WORD diff = state.Gamepad.wButtons ^ gamepad.wButtons;
  175. const WORD curr = state.Gamepad.wButtons;
  176. if (diff != 0)
  177. {
  178. for (u8 bb = 0; bb < countof(s_xinput_to_joypad); ++bb)
  179. {
  180. WORD bit = s_xinput_to_joypad[bb].bit;
  181. if (bit & diff)
  182. {
  183. queue.push_button_event(InputDeviceType::JOYPAD
  184. , i
  185. , s_xinput_to_joypad[bb].button
  186. , (curr & bit) != 0
  187. );
  188. gamepad.wButtons = curr;
  189. }
  190. }
  191. }
  192. if (state.Gamepad.sThumbLX != gamepad.sThumbLX)
  193. {
  194. _axis[i].lx = state.Gamepad.sThumbLX;
  195. queue.push_axis_event(InputDeviceType::JOYPAD
  196. , i
  197. , JoypadAxis::LEFT
  198. , _axis[i].lx
  199. , _axis[i].ly
  200. , 0
  201. );
  202. gamepad.sThumbLX = state.Gamepad.sThumbLX;
  203. }
  204. if (state.Gamepad.sThumbLY != gamepad.sThumbLY)
  205. {
  206. _axis[i].ly = state.Gamepad.sThumbLY;
  207. queue.push_axis_event(InputDeviceType::JOYPAD
  208. , i
  209. , JoypadAxis::LEFT
  210. , _axis[i].lx
  211. , _axis[i].ly
  212. , 0
  213. );
  214. gamepad.sThumbLY = state.Gamepad.sThumbLY;
  215. }
  216. if (state.Gamepad.sThumbRX != gamepad.sThumbRX)
  217. {
  218. _axis[i].rx = state.Gamepad.sThumbRX;
  219. queue.push_axis_event(InputDeviceType::JOYPAD
  220. , i
  221. , JoypadAxis::RIGHT
  222. , _axis[i].rx
  223. , _axis[i].ry
  224. , 0
  225. );
  226. gamepad.sThumbRX = state.Gamepad.sThumbRX;
  227. }
  228. if (state.Gamepad.sThumbRY != gamepad.sThumbRY)
  229. {
  230. _axis[i].ry = state.Gamepad.sThumbRY;
  231. queue.push_axis_event(InputDeviceType::JOYPAD
  232. , i
  233. , JoypadAxis::RIGHT
  234. , _axis[i].rx
  235. , _axis[i].ry
  236. , 0
  237. );
  238. gamepad.sThumbRY = state.Gamepad.sThumbRY;
  239. }
  240. if (state.Gamepad.bLeftTrigger != gamepad.bLeftTrigger)
  241. {
  242. _axis[i].lz = state.Gamepad.bLeftTrigger;
  243. queue.push_axis_event(InputDeviceType::JOYPAD
  244. , i
  245. , JoypadAxis::TRIGGER_LEFT
  246. , 0
  247. , 0
  248. , _axis[i].lz
  249. );
  250. gamepad.bLeftTrigger = state.Gamepad.bLeftTrigger;
  251. }
  252. if (state.Gamepad.bRightTrigger != gamepad.bRightTrigger)
  253. {
  254. _axis[i].rz = state.Gamepad.bRightTrigger;
  255. queue.push_axis_event(InputDeviceType::JOYPAD
  256. , i
  257. , JoypadAxis::TRIGGER_RIGHT
  258. , 0
  259. , 0
  260. , _axis[i].rz
  261. );
  262. gamepad.bRightTrigger = state.Gamepad.bRightTrigger;
  263. }
  264. }
  265. }
  266. };
  267. static bool s_exit = false;
  268. static HCURSOR _win_cursors[MouseCursor::COUNT];
  269. struct WindowsDevice
  270. {
  271. HWND _hwnd;
  272. HCURSOR _hcursor;
  273. DeviceEventQueue _queue;
  274. Joypad _joypad;
  275. s16 _mouse_last_x;
  276. s16 _mouse_last_y;
  277. CursorMode::Enum _cursor_mode;
  278. WindowsDevice()
  279. : _hwnd(NULL)
  280. , _hcursor(NULL)
  281. , _mouse_last_x(INT16_MAX)
  282. , _mouse_last_y(INT16_MAX)
  283. , _cursor_mode(CursorMode::NORMAL)
  284. {
  285. }
  286. int run(DeviceOptions* opts)
  287. {
  288. HINSTANCE instance = (HINSTANCE)GetModuleHandle(NULL);
  289. WNDCLASSEX wnd;
  290. memset(&wnd, 0, sizeof(wnd));
  291. wnd.cbSize = sizeof(wnd);
  292. wnd.style = CS_HREDRAW | CS_VREDRAW;
  293. wnd.lpfnWndProc = window_proc;
  294. wnd.hInstance = instance;
  295. wnd.hIcon = LoadIcon(NULL, IDI_APPLICATION);
  296. wnd.hCursor = LoadCursor(NULL, IDC_ARROW);
  297. wnd.lpszClassName = "crown";
  298. wnd.hIconSm = LoadIcon(NULL, IDI_APPLICATION);
  299. RegisterClassExA(&wnd);
  300. DWORD style = WS_VISIBLE;
  301. DWORD exstyle = 0;
  302. if (opts->_parent_window == 0)
  303. {
  304. style |= WS_OVERLAPPEDWINDOW;
  305. }
  306. else
  307. {
  308. style |= WS_POPUP;
  309. exstyle |= WS_EX_TRANSPARENT | WS_EX_LAYERED | WS_EX_NOACTIVATE;
  310. }
  311. RECT rect;
  312. rect.left = 0;
  313. rect.top = 0;
  314. rect.right = opts->_window_width;
  315. rect.bottom = opts->_window_height;
  316. AdjustWindowRect(&rect, style, FALSE);
  317. _hwnd = CreateWindowExA(exstyle
  318. , "crown"
  319. , "Crown"
  320. , style
  321. , opts->_window_x
  322. , opts->_window_y
  323. , rect.right - rect.left
  324. , rect.bottom - rect.top
  325. , 0
  326. , NULL
  327. , instance
  328. , NULL
  329. );
  330. CE_ASSERT(_hwnd != NULL, "CreateWindowA: GetLastError = %d", GetLastError());
  331. if (opts->_parent_window != 0)
  332. SetParent(_hwnd, (HWND)(UINT_PTR)opts->_parent_window);
  333. _hcursor = LoadCursorA(NULL, IDC_ARROW);
  334. // Create standard cursors
  335. _win_cursors[MouseCursor::ARROW] = LoadCursorA(NULL, IDC_ARROW);
  336. _win_cursors[MouseCursor::HAND] = LoadCursorA(NULL, IDC_HAND);
  337. _win_cursors[MouseCursor::TEXT_INPUT] = LoadCursorA(NULL, IDC_IBEAM);
  338. _win_cursors[MouseCursor::CORNER_TOP_LEFT] = LoadCursorA(NULL, IDC_SIZENESW);
  339. _win_cursors[MouseCursor::CORNER_TOP_RIGHT] = LoadCursorA(NULL, IDC_SIZENWSE);
  340. _win_cursors[MouseCursor::CORNER_BOTTOM_LEFT] = LoadCursorA(NULL, IDC_SIZENWSE);
  341. _win_cursors[MouseCursor::CORNER_BOTTOM_RIGHT] = LoadCursorA(NULL, IDC_SIZENESW);
  342. _win_cursors[MouseCursor::SIZE_HORIZONTAL] = LoadCursorA(NULL, IDC_SIZEWE);
  343. _win_cursors[MouseCursor::SIZE_VERTICAL] = LoadCursorA(NULL, IDC_SIZENS);
  344. _win_cursors[MouseCursor::WAIT] = LoadCursorA(NULL, IDC_WAIT);
  345. Thread main_thread;
  346. main_thread.start([](void* user_data) {
  347. crown::run(*((DeviceOptions*)user_data));
  348. s_exit = true;
  349. return EXIT_SUCCESS;
  350. }
  351. , opts
  352. );
  353. MSG msg;
  354. msg.message = WM_NULL;
  355. while (!s_exit)
  356. {
  357. _joypad.update(_queue);
  358. while (PeekMessage(&msg, NULL, 0U, 0U, PM_REMOVE) != 0)
  359. {
  360. TranslateMessage(&msg);
  361. DispatchMessage(&msg);
  362. }
  363. }
  364. main_thread.stop();
  365. // Destroy standard cursors
  366. DestroyIcon((HICON)_win_cursors[MouseCursor::WAIT]);
  367. DestroyIcon((HICON)_win_cursors[MouseCursor::SIZE_VERTICAL]);
  368. DestroyIcon((HICON)_win_cursors[MouseCursor::SIZE_HORIZONTAL]);
  369. DestroyIcon((HICON)_win_cursors[MouseCursor::CORNER_BOTTOM_RIGHT]);
  370. DestroyIcon((HICON)_win_cursors[MouseCursor::CORNER_BOTTOM_LEFT]);
  371. DestroyIcon((HICON)_win_cursors[MouseCursor::CORNER_TOP_RIGHT]);
  372. DestroyIcon((HICON)_win_cursors[MouseCursor::CORNER_TOP_LEFT]);
  373. DestroyIcon((HICON)_win_cursors[MouseCursor::TEXT_INPUT]);
  374. DestroyIcon((HICON)_win_cursors[MouseCursor::HAND]);
  375. DestroyIcon((HICON)_win_cursors[MouseCursor::ARROW]);
  376. DestroyWindow(_hwnd);
  377. return EXIT_SUCCESS;
  378. }
  379. LRESULT pump_events(HWND hwnd, UINT id, WPARAM wparam, LPARAM lparam)
  380. {
  381. switch (id)
  382. {
  383. case WM_DESTROY:
  384. break;
  385. case WM_QUIT:
  386. case WM_CLOSE:
  387. s_exit = true;
  388. _queue.push_exit_event();
  389. return 0;
  390. case WM_SIZE:
  391. {
  392. u32 width = GET_X_LPARAM(lparam);
  393. u32 height = GET_Y_LPARAM(lparam);
  394. if (_cursor_mode == CursorMode::DISABLED)
  395. {
  396. RECT clipRect;
  397. GetWindowRect(_hwnd, &clipRect);
  398. ClipCursor(&clipRect);
  399. }
  400. _queue.push_resolution_event(width, height);
  401. break;
  402. }
  403. case WM_SYSCOMMAND:
  404. switch (wparam)
  405. {
  406. case SC_MINIMIZE:
  407. case SC_RESTORE:
  408. {
  409. HWND parent = GetWindow(hwnd, GW_OWNER);
  410. if (parent != NULL)
  411. {
  412. PostMessage(parent, id, wparam, lparam);
  413. }
  414. break;
  415. }
  416. }
  417. break;
  418. case WM_MOUSEWHEEL:
  419. {
  420. short delta = GET_WHEEL_DELTA_WPARAM(wparam);
  421. _queue.push_axis_event(InputDeviceType::MOUSE
  422. , 0
  423. , MouseAxis::WHEEL
  424. , 0
  425. , delta / WHEEL_DELTA
  426. , 0
  427. );
  428. break;
  429. }
  430. case WM_MOUSEMOVE:
  431. {
  432. s32 mx = GET_X_LPARAM(lparam);
  433. s32 my = GET_Y_LPARAM(lparam);
  434. s16 deltax = mx - (_mouse_last_x == INT16_MAX ? mx : _mouse_last_x);
  435. s16 deltay = my - (_mouse_last_y == INT16_MAX ? my : _mouse_last_y);
  436. if (_cursor_mode == CursorMode::DISABLED)
  437. {
  438. RECT clipRect;
  439. GetWindowRect(_hwnd, &clipRect);
  440. unsigned width = clipRect.right - clipRect.left;
  441. unsigned height = clipRect.bottom - clipRect.top;
  442. if (mx != (s32)width/2 || my != (s32)height/2)
  443. {
  444. _queue.push_axis_event(InputDeviceType::MOUSE
  445. , 0
  446. , MouseAxis::CURSOR_DELTA
  447. , deltax
  448. , deltay
  449. , 0
  450. );
  451. POINT mouse_pos = {(long)width/2, (long)height/2};
  452. ClientToScreen(_hwnd, &mouse_pos);
  453. SetCursorPos(mouse_pos.x, mouse_pos.y);
  454. _mouse_last_x = (s16)width/2;
  455. _mouse_last_y = (s16)height/2;
  456. }
  457. }
  458. else if (_cursor_mode == CursorMode::NORMAL)
  459. {
  460. _queue.push_axis_event(InputDeviceType::MOUSE
  461. , 0
  462. , MouseAxis::CURSOR_DELTA
  463. , deltax
  464. , deltay
  465. , 0
  466. );
  467. _mouse_last_x = (s16)mx;
  468. _mouse_last_y = (s16)my;
  469. }
  470. _queue.push_axis_event(InputDeviceType::MOUSE
  471. , 0
  472. , MouseAxis::CURSOR
  473. , (s16)mx
  474. , (s16)my
  475. , 0
  476. );
  477. break;
  478. }
  479. case WM_LBUTTONDOWN:
  480. case WM_LBUTTONUP:
  481. case WM_RBUTTONDOWN:
  482. case WM_RBUTTONUP:
  483. case WM_MBUTTONDOWN:
  484. case WM_MBUTTONUP:
  485. {
  486. MouseButton::Enum mb;
  487. if (id == WM_LBUTTONDOWN || id == WM_LBUTTONUP)
  488. mb = MouseButton::LEFT;
  489. else if (id == WM_RBUTTONDOWN || id == WM_RBUTTONUP)
  490. mb = MouseButton::RIGHT;
  491. else /* if (id == WM_MBUTTONDOWN || id == WM_MBUTTONUP) */
  492. mb = MouseButton::MIDDLE;
  493. bool down = id == WM_LBUTTONDOWN
  494. || id == WM_RBUTTONDOWN
  495. || id == WM_MBUTTONDOWN
  496. ;
  497. _queue.push_button_event(InputDeviceType::MOUSE
  498. , 0
  499. , mb
  500. , down
  501. );
  502. break;
  503. }
  504. case WM_KEYDOWN:
  505. case WM_SYSKEYDOWN:
  506. case WM_KEYUP:
  507. case WM_SYSKEYUP:
  508. {
  509. KeyboardButton::Enum kb = win_translate_key(wparam & 0xff);
  510. if (kb != KeyboardButton::COUNT)
  511. {
  512. _queue.push_button_event(InputDeviceType::KEYBOARD
  513. , 0
  514. , kb
  515. , (id == WM_KEYDOWN || id == WM_SYSKEYDOWN)
  516. );
  517. }
  518. break;
  519. }
  520. case WM_CHAR:
  521. {
  522. uint8_t utf8[4] = { 0 };
  523. uint8_t len = (uint8_t)WideCharToMultiByte(CP_UTF8
  524. , 0
  525. , (LPCWSTR)&wparam
  526. , 1
  527. , (LPSTR)utf8
  528. , sizeof(utf8)
  529. , NULL
  530. , NULL
  531. );
  532. if (len)
  533. _queue.push_text_event(len, utf8);
  534. break;
  535. }
  536. case WM_SETCURSOR:
  537. if (LOWORD(lparam) == HTCLIENT)
  538. {
  539. if (_hcursor != NULL)
  540. SetCursor(_hcursor);
  541. else
  542. SetCursor(NULL);
  543. return TRUE;
  544. }
  545. default:
  546. break;
  547. }
  548. return DefWindowProc(hwnd, id, wparam, lparam);
  549. }
  550. static LRESULT CALLBACK window_proc(HWND hwnd, UINT id, WPARAM wparam, LPARAM lparam);
  551. };
  552. static WindowsDevice s_wdvc;
  553. LRESULT CALLBACK WindowsDevice::window_proc(HWND hwnd, UINT id, WPARAM wparam, LPARAM lparam)
  554. {
  555. return s_wdvc.pump_events(hwnd, id, wparam, lparam);
  556. }
  557. struct WindowWin : public Window
  558. {
  559. u16 _x;
  560. u16 _y;
  561. u16 _width;
  562. u16 _height;
  563. WindowWin()
  564. : _x(0)
  565. , _y(0)
  566. , _width(CROWN_DEFAULT_WINDOW_WIDTH)
  567. , _height(CROWN_DEFAULT_WINDOW_HEIGHT)
  568. {
  569. }
  570. void open(u16 x, u16 y, u16 width, u16 height, u32 /*parent*/)
  571. {
  572. move(x, y);
  573. resize(width, height);
  574. }
  575. void close()
  576. {
  577. }
  578. void bgfx_setup()
  579. {
  580. bgfx::PlatformData pd;
  581. memset(&pd, 0, sizeof(pd));
  582. pd.nwh = s_wdvc._hwnd;
  583. bgfx::setPlatformData(pd);
  584. }
  585. void show()
  586. {
  587. ShowWindow(s_wdvc._hwnd, SW_SHOW);
  588. }
  589. void hide()
  590. {
  591. ShowWindow(s_wdvc._hwnd, SW_HIDE);
  592. }
  593. void resize(u16 width, u16 height)
  594. {
  595. _width = width;
  596. _height = height;
  597. DWORD style = GetWindowLongA(s_wdvc._hwnd, GWL_STYLE);
  598. RECT rect;
  599. rect.left = 0;
  600. rect.top = 0;
  601. rect.right = _width;
  602. rect.bottom = _height;
  603. AdjustWindowRect(&rect, style, FALSE);
  604. MoveWindow(s_wdvc._hwnd
  605. , _x
  606. , _y
  607. , rect.right - rect.left
  608. , rect.bottom - rect.top
  609. , FALSE
  610. );
  611. }
  612. void move(u16 x, u16 y)
  613. {
  614. _x = x;
  615. _y = y;
  616. resize(_width, _height);
  617. }
  618. void minimize()
  619. {
  620. ShowWindow(s_wdvc._hwnd, SW_MINIMIZE);
  621. }
  622. void maximize()
  623. {
  624. ShowWindow(s_wdvc._hwnd, SW_MAXIMIZE);
  625. }
  626. void restore()
  627. {
  628. ShowWindow(s_wdvc._hwnd, SW_RESTORE);
  629. }
  630. const char* title()
  631. {
  632. static char buf[512];
  633. memset(buf, 0, sizeof(buf));
  634. GetWindowText(s_wdvc._hwnd, buf, sizeof(buf));
  635. return buf;
  636. }
  637. void set_title (const char* title)
  638. {
  639. SetWindowText(s_wdvc._hwnd, title);
  640. }
  641. void show_cursor(bool show)
  642. {
  643. s_wdvc._hcursor = show ? LoadCursorA(NULL, IDC_ARROW) : NULL;
  644. SetCursor(s_wdvc._hcursor);
  645. }
  646. void set_fullscreen(bool /*fullscreen*/)
  647. {
  648. }
  649. void set_cursor(MouseCursor::Enum cursor)
  650. {
  651. s_wdvc._hcursor = _win_cursors[cursor];
  652. SetCursor(s_wdvc._hcursor);
  653. }
  654. void set_cursor_mode(CursorMode::Enum mode)
  655. {
  656. if (mode == s_wdvc._cursor_mode)
  657. return;
  658. s_wdvc._cursor_mode = mode;
  659. if (mode == CursorMode::DISABLED)
  660. {
  661. RECT clipRect;
  662. GetWindowRect(s_wdvc._hwnd, &clipRect);
  663. unsigned width = clipRect.right - clipRect.left;
  664. unsigned height = clipRect.bottom - clipRect.top;
  665. s_wdvc._mouse_last_x = width/2;
  666. s_wdvc._mouse_last_y = height/2;
  667. POINT mouse_pos = {(long)width/2, (long)height/2};
  668. ClientToScreen(s_wdvc._hwnd, &mouse_pos);
  669. SetCursorPos(mouse_pos.x, mouse_pos.y);
  670. show_cursor(false);
  671. ClipCursor(&clipRect);
  672. }
  673. else if (mode == CursorMode::NORMAL)
  674. {
  675. show_cursor(true);
  676. ClipCursor(NULL);
  677. }
  678. }
  679. void* handle()
  680. {
  681. return (void*)(uintptr_t)s_wdvc._hwnd;
  682. }
  683. };
  684. namespace window
  685. {
  686. Window* create(Allocator& a)
  687. {
  688. return CE_NEW(a, WindowWin)();
  689. }
  690. void destroy(Allocator& a, Window& w)
  691. {
  692. CE_DELETE(a, &w);
  693. }
  694. } // namespace window
  695. struct DisplayWin : public Display
  696. {
  697. void modes(Array<DisplayMode>& /*modes*/)
  698. {
  699. }
  700. void set_mode(u32 /*id*/)
  701. {
  702. }
  703. };
  704. namespace display
  705. {
  706. Display* create(Allocator& a)
  707. {
  708. return CE_NEW(a, DisplayWin)();
  709. }
  710. void destroy(Allocator& a, Display& d)
  711. {
  712. CE_DELETE(a, &d);
  713. }
  714. } // namespace display
  715. bool next_event(OsEvent& ev)
  716. {
  717. return s_wdvc._queue.pop_event(ev);
  718. }
  719. } // namespace crown
  720. struct InitGlobals
  721. {
  722. InitGlobals()
  723. {
  724. crown::memory_globals::init();
  725. crown::guid_globals::init();
  726. }
  727. ~InitGlobals()
  728. {
  729. crown::guid_globals::shutdown();
  730. crown::memory_globals::shutdown();
  731. }
  732. };
  733. int main(int argc, char** argv)
  734. {
  735. using namespace crown;
  736. if (AttachConsole(ATTACH_PARENT_PROCESS) != 0)
  737. {
  738. freopen("CONIN$", "r", stdin);
  739. freopen("CONOUT$", "w", stdout);
  740. freopen("CONOUT$", "w", stderr);
  741. }
  742. WSADATA wsdata;
  743. int err = WSAStartup(MAKEWORD(2, 2), &wsdata);
  744. CE_ASSERT(err == 0, "WSAStartup: error = %d", err);
  745. CE_UNUSED(wsdata);
  746. CE_UNUSED(err);
  747. #if CROWN_BUILD_UNIT_TESTS
  748. CommandLine cl(argc, (const char**)argv);
  749. if (cl.has_option("run-unit-tests"))
  750. {
  751. return main_unit_tests();
  752. }
  753. #endif // CROWN_BUILD_UNIT_TESTS
  754. InitGlobals m;
  755. CE_UNUSED(m);
  756. DeviceOptions opts(default_allocator(), argc, (const char**)argv);
  757. bool quit = false;
  758. int ec = opts.parse(&quit);
  759. if (quit)
  760. return ec;
  761. #if CROWN_CAN_COMPILE
  762. if (ec == EXIT_SUCCESS && (opts._do_compile || opts._server))
  763. {
  764. ec = main_data_compiler(opts);
  765. if (!opts._do_continue)
  766. return ec;
  767. }
  768. #endif
  769. if (ec == EXIT_SUCCESS)
  770. ec = s_wdvc.run(&opts);
  771. FreeConsole();
  772. WSACleanup();
  773. return ec;
  774. }
  775. #endif // CROWN_PLATFORM_WINDOWS