main_windows.cpp 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883
  1. /*
  2. * Copyright (c) 2012-2022 Daniele Bartolini et al.
  3. * License: https://github.com/crownengine/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/mpsc_queue.inl"
  13. #include "core/thread/thread.h"
  14. #include "core/unit_tests.h"
  15. #include "device/device.h"
  16. #include "device/device_event_queue.inl"
  17. #include "resource/data_compiler.h"
  18. #include <bgfx/platform.h>
  19. #include <stdio.h> // FILE, freopen, stdio etc.
  20. #include <winsock2.h>
  21. #include <windowsx.h> // GET_X_LPARAM, GET_Y_LPARAM
  22. #include <xinput.h>
  23. #define STB_SPRINTF_IMPLEMENTATION
  24. #include <stb_sprintf.h>
  25. namespace crown
  26. {
  27. static KeyboardButton::Enum win_translate_key(s32 winkey)
  28. {
  29. switch (winkey) {
  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. XINPUT_STATE state;
  164. memset(&state, 0, sizeof(state));
  165. const DWORD result = XInputGetState(i, &state);
  166. const bool connected = result == ERROR_SUCCESS;
  167. if (connected != _connected[i])
  168. queue.push_status_event(InputDeviceType::JOYPAD, i, connected);
  169. _connected[i] = connected;
  170. if (!connected || state.dwPacketNumber == _state[i].dwPacketNumber)
  171. continue;
  172. XINPUT_GAMEPAD &gamepad = _state[i].Gamepad;
  173. const WORD diff = state.Gamepad.wButtons ^ gamepad.wButtons;
  174. const WORD curr = state.Gamepad.wButtons;
  175. if (diff != 0) {
  176. for (u8 bb = 0; bb < countof(s_xinput_to_joypad); ++bb) {
  177. WORD bit = s_xinput_to_joypad[bb].bit;
  178. if (bit & diff) {
  179. queue.push_button_event(InputDeviceType::JOYPAD
  180. , i
  181. , s_xinput_to_joypad[bb].button
  182. , (curr & bit) != 0
  183. );
  184. gamepad.wButtons = curr;
  185. }
  186. }
  187. }
  188. if (state.Gamepad.sThumbLX != gamepad.sThumbLX) {
  189. _axis[i].lx = state.Gamepad.sThumbLX;
  190. queue.push_axis_event(InputDeviceType::JOYPAD
  191. , i
  192. , JoypadAxis::LEFT
  193. , _axis[i].lx
  194. , _axis[i].ly
  195. , 0
  196. );
  197. gamepad.sThumbLX = state.Gamepad.sThumbLX;
  198. }
  199. if (state.Gamepad.sThumbLY != gamepad.sThumbLY) {
  200. _axis[i].ly = state.Gamepad.sThumbLY;
  201. queue.push_axis_event(InputDeviceType::JOYPAD
  202. , i
  203. , JoypadAxis::LEFT
  204. , _axis[i].lx
  205. , _axis[i].ly
  206. , 0
  207. );
  208. gamepad.sThumbLY = state.Gamepad.sThumbLY;
  209. }
  210. if (state.Gamepad.sThumbRX != gamepad.sThumbRX) {
  211. _axis[i].rx = state.Gamepad.sThumbRX;
  212. queue.push_axis_event(InputDeviceType::JOYPAD
  213. , i
  214. , JoypadAxis::RIGHT
  215. , _axis[i].rx
  216. , _axis[i].ry
  217. , 0
  218. );
  219. gamepad.sThumbRX = state.Gamepad.sThumbRX;
  220. }
  221. if (state.Gamepad.sThumbRY != gamepad.sThumbRY) {
  222. _axis[i].ry = state.Gamepad.sThumbRY;
  223. queue.push_axis_event(InputDeviceType::JOYPAD
  224. , i
  225. , JoypadAxis::RIGHT
  226. , _axis[i].rx
  227. , _axis[i].ry
  228. , 0
  229. );
  230. gamepad.sThumbRY = state.Gamepad.sThumbRY;
  231. }
  232. if (state.Gamepad.bLeftTrigger != gamepad.bLeftTrigger) {
  233. _axis[i].lz = state.Gamepad.bLeftTrigger;
  234. queue.push_axis_event(InputDeviceType::JOYPAD
  235. , i
  236. , JoypadAxis::TRIGGER_LEFT
  237. , 0
  238. , 0
  239. , _axis[i].lz
  240. );
  241. gamepad.bLeftTrigger = state.Gamepad.bLeftTrigger;
  242. }
  243. if (state.Gamepad.bRightTrigger != gamepad.bRightTrigger) {
  244. _axis[i].rz = state.Gamepad.bRightTrigger;
  245. queue.push_axis_event(InputDeviceType::JOYPAD
  246. , i
  247. , JoypadAxis::TRIGGER_RIGHT
  248. , 0
  249. , 0
  250. , _axis[i].rz
  251. );
  252. gamepad.bRightTrigger = state.Gamepad.bRightTrigger;
  253. }
  254. }
  255. }
  256. };
  257. static bool s_exit = false;
  258. static HCURSOR _win_cursors[MouseCursor::COUNT];
  259. static bool push_event(const OsEvent &ev);
  260. struct WindowsDevice
  261. {
  262. HWND _hwnd;
  263. HCURSOR _hcursor;
  264. MPSCQueue<OsEvent, CROWN_MAX_OS_EVENTS> _events;
  265. DeviceEventQueue _queue;
  266. Joypad _joypad;
  267. s16 _mouse_last_x;
  268. s16 _mouse_last_y;
  269. CursorMode::Enum _cursor_mode;
  270. DeviceOptions *_options;
  271. WindowsDevice(Allocator &a, DeviceOptions &opts)
  272. : _hwnd(NULL)
  273. , _hcursor(NULL)
  274. , _events(a)
  275. , _queue(push_event)
  276. , _mouse_last_x(INT16_MAX)
  277. , _mouse_last_y(INT16_MAX)
  278. , _cursor_mode(CursorMode::NORMAL)
  279. , _options(&opts)
  280. {
  281. }
  282. int run()
  283. {
  284. HINSTANCE instance = (HINSTANCE)GetModuleHandle(NULL);
  285. WNDCLASSEX wnd;
  286. memset(&wnd, 0, sizeof(wnd));
  287. wnd.cbSize = sizeof(wnd);
  288. wnd.style = CS_HREDRAW | CS_VREDRAW;
  289. wnd.lpfnWndProc = window_proc;
  290. wnd.hInstance = instance;
  291. wnd.hIcon = LoadIcon(NULL, IDI_APPLICATION);
  292. wnd.hCursor = LoadCursor(NULL, IDC_ARROW);
  293. wnd.lpszClassName = "crown";
  294. wnd.hIconSm = LoadIcon(NULL, IDI_APPLICATION);
  295. RegisterClassExA(&wnd);
  296. DWORD style = WS_VISIBLE;
  297. DWORD exstyle = 0;
  298. if (_options->_parent_window == 0) {
  299. style |= WS_OVERLAPPEDWINDOW;
  300. } else {
  301. style |= WS_POPUP;
  302. exstyle |= WS_EX_TRANSPARENT | WS_EX_LAYERED | WS_EX_NOACTIVATE;
  303. }
  304. RECT rect;
  305. rect.left = 0;
  306. rect.top = 0;
  307. rect.right = _options->_window_width;
  308. rect.bottom = _options->_window_height;
  309. AdjustWindowRect(&rect, style, FALSE);
  310. _hwnd = CreateWindowExA(exstyle
  311. , "crown"
  312. , "Crown"
  313. , style
  314. , _options->_window_x
  315. , _options->_window_y
  316. , rect.right - rect.left
  317. , rect.bottom - rect.top
  318. , 0
  319. , NULL
  320. , instance
  321. , NULL
  322. );
  323. CE_ASSERT(_hwnd != NULL, "CreateWindowA: GetLastError = %d", GetLastError());
  324. if (_options->_parent_window != 0)
  325. SetParent(_hwnd, (HWND)(UINT_PTR)_options->_parent_window);
  326. _hcursor = LoadCursorA(NULL, IDC_ARROW);
  327. // Create standard cursors
  328. _win_cursors[MouseCursor::ARROW] = LoadCursorA(NULL, IDC_ARROW);
  329. _win_cursors[MouseCursor::HAND] = LoadCursorA(NULL, IDC_HAND);
  330. _win_cursors[MouseCursor::TEXT_INPUT] = LoadCursorA(NULL, IDC_IBEAM);
  331. _win_cursors[MouseCursor::CORNER_TOP_LEFT] = LoadCursorA(NULL, IDC_SIZENESW);
  332. _win_cursors[MouseCursor::CORNER_TOP_RIGHT] = LoadCursorA(NULL, IDC_SIZENWSE);
  333. _win_cursors[MouseCursor::CORNER_BOTTOM_LEFT] = LoadCursorA(NULL, IDC_SIZENWSE);
  334. _win_cursors[MouseCursor::CORNER_BOTTOM_RIGHT] = LoadCursorA(NULL, IDC_SIZENESW);
  335. _win_cursors[MouseCursor::SIZE_HORIZONTAL] = LoadCursorA(NULL, IDC_SIZEWE);
  336. _win_cursors[MouseCursor::SIZE_VERTICAL] = LoadCursorA(NULL, IDC_SIZENS);
  337. _win_cursors[MouseCursor::WAIT] = LoadCursorA(NULL, IDC_WAIT);
  338. Thread main_thread;
  339. main_thread.start([](void *user_data) {
  340. WindowsDevice *win = (WindowsDevice *)user_data;
  341. crown::run(*win->_options);
  342. s_exit = true;
  343. PostMessageA(win->_hwnd, WM_USER + 1, 0, 0);
  344. return EXIT_SUCCESS;
  345. }
  346. , this
  347. );
  348. Thread joypad_thread;
  349. joypad_thread.start([](void *user_data) {
  350. WindowsDevice *win = (WindowsDevice *)user_data;
  351. while (!s_exit) {
  352. win->_joypad.update(win->_queue);
  353. os::sleep(4);
  354. }
  355. return EXIT_SUCCESS;
  356. }
  357. , this
  358. );
  359. // Windows event loop.
  360. MSG msg;
  361. msg.message = WM_NULL;
  362. while (GetMessage(&msg, NULL, 0U, 0U) != 0) {
  363. TranslateMessage(&msg);
  364. DispatchMessage(&msg);
  365. }
  366. joypad_thread.stop();
  367. main_thread.stop();
  368. // Destroy standard cursors
  369. DestroyIcon((HICON)_win_cursors[MouseCursor::WAIT]);
  370. DestroyIcon((HICON)_win_cursors[MouseCursor::SIZE_VERTICAL]);
  371. DestroyIcon((HICON)_win_cursors[MouseCursor::SIZE_HORIZONTAL]);
  372. DestroyIcon((HICON)_win_cursors[MouseCursor::CORNER_BOTTOM_RIGHT]);
  373. DestroyIcon((HICON)_win_cursors[MouseCursor::CORNER_BOTTOM_LEFT]);
  374. DestroyIcon((HICON)_win_cursors[MouseCursor::CORNER_TOP_RIGHT]);
  375. DestroyIcon((HICON)_win_cursors[MouseCursor::CORNER_TOP_LEFT]);
  376. DestroyIcon((HICON)_win_cursors[MouseCursor::TEXT_INPUT]);
  377. DestroyIcon((HICON)_win_cursors[MouseCursor::HAND]);
  378. DestroyIcon((HICON)_win_cursors[MouseCursor::ARROW]);
  379. DestroyWindow(_hwnd);
  380. return EXIT_SUCCESS;
  381. }
  382. LRESULT pump_events(HWND hwnd, UINT id, WPARAM wparam, LPARAM lparam)
  383. {
  384. switch (id) {
  385. case WM_DESTROY:
  386. case WM_USER + 1:
  387. PostQuitMessage(0);
  388. return 0;
  389. case WM_CLOSE:
  390. s_exit = true;
  391. _queue.push_exit_event();
  392. return 0;
  393. case WM_SIZE: {
  394. u32 width = GET_X_LPARAM(lparam);
  395. u32 height = GET_Y_LPARAM(lparam);
  396. if (_cursor_mode == CursorMode::DISABLED) {
  397. RECT clipRect;
  398. GetWindowRect(_hwnd, &clipRect);
  399. ClipCursor(&clipRect);
  400. }
  401. _queue.push_resolution_event(width, height);
  402. break;
  403. }
  404. case WM_SYSCOMMAND:
  405. switch (wparam) {
  406. case SC_MINIMIZE:
  407. case SC_RESTORE: {
  408. HWND parent = GetWindow(hwnd, GW_OWNER);
  409. if (parent != NULL) {
  410. PostMessage(parent, id, wparam, lparam);
  411. }
  412. break;
  413. }
  414. }
  415. break;
  416. case WM_MOUSEWHEEL: {
  417. short delta = GET_WHEEL_DELTA_WPARAM(wparam);
  418. _queue.push_axis_event(InputDeviceType::MOUSE
  419. , 0
  420. , MouseAxis::WHEEL
  421. , 0
  422. , delta / WHEEL_DELTA
  423. , 0
  424. );
  425. break;
  426. }
  427. case WM_MOUSEMOVE: {
  428. s32 mx = GET_X_LPARAM(lparam);
  429. s32 my = GET_Y_LPARAM(lparam);
  430. s16 deltax = mx - (_mouse_last_x == INT16_MAX ? mx : _mouse_last_x);
  431. s16 deltay = my - (_mouse_last_y == INT16_MAX ? my : _mouse_last_y);
  432. if (_cursor_mode == CursorMode::DISABLED) {
  433. RECT clipRect;
  434. GetWindowRect(_hwnd, &clipRect);
  435. unsigned width = clipRect.right - clipRect.left;
  436. unsigned height = clipRect.bottom - clipRect.top;
  437. if (mx != (s32)width/2 || my != (s32)height/2) {
  438. _queue.push_axis_event(InputDeviceType::MOUSE
  439. , 0
  440. , MouseAxis::CURSOR_DELTA
  441. , deltax
  442. , deltay
  443. , 0
  444. );
  445. POINT mouse_pos = { (long)width/2, (long)height/2 };
  446. ClientToScreen(_hwnd, &mouse_pos);
  447. SetCursorPos(mouse_pos.x, mouse_pos.y);
  448. _mouse_last_x = (s16)width/2;
  449. _mouse_last_y = (s16)height/2;
  450. } else if (_cursor_mode == CursorMode::NORMAL) {
  451. _queue.push_axis_event(InputDeviceType::MOUSE
  452. , 0
  453. , MouseAxis::CURSOR_DELTA
  454. , deltax
  455. , deltay
  456. , 0
  457. );
  458. POINT mouse_pos = {(long)width/2, (long)height/2};
  459. ClientToScreen(_hwnd, &mouse_pos);
  460. SetCursorPos(mouse_pos.x, mouse_pos.y);
  461. _mouse_last_x = (s16)width/2;
  462. _mouse_last_y = (s16)height/2;
  463. }
  464. } else if (_cursor_mode == CursorMode::NORMAL) {
  465. _queue.push_axis_event(InputDeviceType::MOUSE
  466. , 0
  467. , MouseAxis::CURSOR_DELTA
  468. , deltax
  469. , deltay
  470. , 0
  471. );
  472. _mouse_last_x = (s16)mx;
  473. _mouse_last_y = (s16)my;
  474. }
  475. _queue.push_axis_event(InputDeviceType::MOUSE
  476. , 0
  477. , MouseAxis::CURSOR
  478. , (s16)mx
  479. , (s16)my
  480. , 0
  481. );
  482. break;
  483. }
  484. case WM_LBUTTONDOWN:
  485. case WM_LBUTTONUP:
  486. case WM_RBUTTONDOWN:
  487. case WM_RBUTTONUP:
  488. case WM_MBUTTONDOWN:
  489. case WM_MBUTTONUP: {
  490. MouseButton::Enum mb;
  491. if (id == WM_LBUTTONDOWN || id == WM_LBUTTONUP)
  492. mb = MouseButton::LEFT;
  493. else if (id == WM_RBUTTONDOWN || id == WM_RBUTTONUP)
  494. mb = MouseButton::RIGHT;
  495. else /* if (id == WM_MBUTTONDOWN || id == WM_MBUTTONUP) */
  496. mb = MouseButton::MIDDLE;
  497. bool down = id == WM_LBUTTONDOWN
  498. || id == WM_RBUTTONDOWN
  499. || id == WM_MBUTTONDOWN
  500. ;
  501. _queue.push_button_event(InputDeviceType::MOUSE
  502. , 0
  503. , mb
  504. , down
  505. );
  506. break;
  507. }
  508. case WM_KEYDOWN:
  509. case WM_SYSKEYDOWN:
  510. case WM_KEYUP:
  511. case WM_SYSKEYUP: {
  512. KeyboardButton::Enum kb = win_translate_key(wparam & 0xff);
  513. if (kb != KeyboardButton::COUNT) {
  514. _queue.push_button_event(InputDeviceType::KEYBOARD
  515. , 0
  516. , kb
  517. , (id == WM_KEYDOWN || id == WM_SYSKEYDOWN)
  518. );
  519. }
  520. break;
  521. }
  522. case WM_CHAR: {
  523. uint8_t utf8[4] = { 0 };
  524. uint8_t len = (uint8_t)WideCharToMultiByte(CP_UTF8
  525. , 0
  526. , (LPCWSTR)&wparam
  527. , 1
  528. , (LPSTR)utf8
  529. , sizeof(utf8)
  530. , NULL
  531. , NULL
  532. );
  533. if (len)
  534. _queue.push_text_event(len, utf8);
  535. break;
  536. }
  537. case WM_SETCURSOR:
  538. if (LOWORD(lparam) == HTCLIENT) {
  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_windows_device;
  553. LRESULT CALLBACK WindowsDevice::window_proc(HWND hwnd, UINT id, WPARAM wparam, LPARAM lparam)
  554. {
  555. return s_windows_device->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*/) override
  571. {
  572. move(x, y);
  573. resize(width, height);
  574. }
  575. void close() override
  576. {
  577. }
  578. void bgfx_setup() override
  579. {
  580. bgfx::PlatformData pd;
  581. memset(&pd, 0, sizeof(pd));
  582. pd.nwh = s_windows_device->_hwnd;
  583. bgfx::setPlatformData(pd);
  584. }
  585. void show() override
  586. {
  587. ShowWindow(s_windows_device->_hwnd, SW_SHOW);
  588. }
  589. void hide() override
  590. {
  591. ShowWindow(s_windows_device->_hwnd, SW_HIDE);
  592. }
  593. void resize(u16 width, u16 height) override
  594. {
  595. _width = width;
  596. _height = height;
  597. DWORD style = GetWindowLongA(s_windows_device->_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_windows_device->_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) override
  613. {
  614. _x = x;
  615. _y = y;
  616. resize(_width, _height);
  617. }
  618. void minimize() override
  619. {
  620. ShowWindow(s_windows_device->_hwnd, SW_MINIMIZE);
  621. }
  622. void maximize() override
  623. {
  624. ShowWindow(s_windows_device->_hwnd, SW_MAXIMIZE);
  625. }
  626. void restore() override
  627. {
  628. ShowWindow(s_windows_device->_hwnd, SW_RESTORE);
  629. }
  630. const char *title() override
  631. {
  632. static char buf[512];
  633. memset(buf, 0, sizeof(buf));
  634. GetWindowText(s_windows_device->_hwnd, buf, sizeof(buf));
  635. return buf;
  636. }
  637. void set_title(const char *title) override
  638. {
  639. SetWindowText(s_windows_device->_hwnd, title);
  640. }
  641. void show_cursor(bool show) override
  642. {
  643. s_windows_device->_hcursor = show ? LoadCursorA(NULL, IDC_ARROW) : NULL;
  644. SetCursor(s_windows_device->_hcursor);
  645. }
  646. void set_fullscreen(bool /*fullscreen*/) override
  647. {
  648. }
  649. void set_cursor(MouseCursor::Enum cursor) override
  650. {
  651. s_windows_device->_hcursor = _win_cursors[cursor];
  652. SetCursor(s_windows_device->_hcursor);
  653. }
  654. void set_cursor_mode(CursorMode::Enum mode) override
  655. {
  656. if (mode == s_windows_device->_cursor_mode)
  657. return;
  658. s_windows_device->_cursor_mode = mode;
  659. if (mode == CursorMode::DISABLED) {
  660. RECT clipRect;
  661. GetWindowRect(s_windows_device->_hwnd, &clipRect);
  662. unsigned width = clipRect.right - clipRect.left;
  663. unsigned height = clipRect.bottom - clipRect.top;
  664. s_windows_device->_mouse_last_x = width/2;
  665. s_windows_device->_mouse_last_y = height/2;
  666. POINT mouse_pos = { (long)width/2, (long)height/2 };
  667. ClientToScreen(s_windows_device->_hwnd, &mouse_pos);
  668. SetCursorPos(mouse_pos.x, mouse_pos.y);
  669. show_cursor(false);
  670. ClipCursor(&clipRect);
  671. } else if (mode == CursorMode::NORMAL) {
  672. show_cursor(true);
  673. ClipCursor(NULL);
  674. }
  675. }
  676. void *handle() override
  677. {
  678. return (void *)(uintptr_t)s_windows_device->_hwnd;
  679. }
  680. };
  681. namespace window
  682. {
  683. Window *create(Allocator &a)
  684. {
  685. return CE_NEW(a, WindowWin)();
  686. }
  687. void destroy(Allocator &a, Window &w)
  688. {
  689. CE_DELETE(a, &w);
  690. }
  691. } // namespace window
  692. struct DisplayWin : public Display
  693. {
  694. void modes(Array<DisplayMode> & /*modes*/) override
  695. {
  696. }
  697. void set_mode(u32 /*id*/) override
  698. {
  699. }
  700. };
  701. namespace display
  702. {
  703. Display *create(Allocator &a)
  704. {
  705. return CE_NEW(a, DisplayWin)();
  706. }
  707. void destroy(Allocator &a, Display &d)
  708. {
  709. CE_DELETE(a, &d);
  710. }
  711. } // namespace display
  712. static bool push_event(const OsEvent &ev)
  713. {
  714. return s_windows_device->_events.push(ev);
  715. }
  716. bool next_event(OsEvent &ev)
  717. {
  718. return s_windows_device->_events.pop(ev);
  719. }
  720. } // namespace crown
  721. struct InitGlobals
  722. {
  723. InitGlobals()
  724. {
  725. crown::memory_globals::init();
  726. crown::guid_globals::init();
  727. }
  728. ~InitGlobals()
  729. {
  730. crown::guid_globals::shutdown();
  731. crown::memory_globals::shutdown();
  732. }
  733. };
  734. int main(int argc, char **argv)
  735. {
  736. using namespace crown;
  737. if (AttachConsole(ATTACH_PARENT_PROCESS) != 0) {
  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. return main_unit_tests();
  751. }
  752. #endif
  753. InitGlobals m;
  754. CE_UNUSED(m);
  755. DeviceOptions opts(default_allocator(), argc, (const char **)argv);
  756. bool quit = false;
  757. int ec = opts.parse(&quit);
  758. if (quit)
  759. return ec;
  760. #if CROWN_CAN_COMPILE
  761. if (ec == EXIT_SUCCESS && (opts._do_compile || opts._server)) {
  762. ec = main_data_compiler(opts);
  763. if (!opts._do_continue)
  764. return ec;
  765. }
  766. #endif
  767. if (ec == EXIT_SUCCESS) {
  768. s_windows_device = CE_NEW(default_allocator(), WindowsDevice)(default_allocator(), opts);
  769. ec = s_windows_device->run();
  770. CE_DELETE(default_allocator(), s_windows_device);
  771. }
  772. FreeConsole();
  773. WSACleanup();
  774. return ec;
  775. }
  776. #endif // if CROWN_PLATFORM_WINDOWS