window_win32.odin 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337
  1. #+build windows
  2. #+private file
  3. package karl2d
  4. @(private="package")
  5. WINDOW_INTERFACE_WIN32 :: Window_Interface {
  6. state_size = win32_state_size,
  7. init = win32_init,
  8. window_handle = win32_window_handle,
  9. process_events = win32_process_events,
  10. get_events = win32_get_events,
  11. clear_events = win32_clear_events,
  12. set_position = win32_set_position,
  13. set_size = win32_set_size,
  14. set_flags = win32_set_flags,
  15. set_internal_state = win32_set_internal_state,
  16. }
  17. import win32 "core:sys/windows"
  18. import "base:runtime"
  19. win32_state_size :: proc() -> int {
  20. return size_of(Win32_State)
  21. }
  22. win32_init :: proc(window_state: rawptr, window_width: int, window_height: int, window_title: string,
  23. flags: Window_Flags, allocator: runtime.Allocator) {
  24. assert(window_state != nil)
  25. s = (^Win32_State)(window_state)
  26. s.allocator = allocator
  27. s.events = make([dynamic]Window_Event, allocator)
  28. s.custom_context = context
  29. win32.SetProcessDPIAware()
  30. CLASS_NAME :: "karl2d"
  31. instance := win32.HINSTANCE(win32.GetModuleHandleW(nil))
  32. cls := win32.WNDCLASSW {
  33. lpfnWndProc = window_proc,
  34. lpszClassName = CLASS_NAME,
  35. hInstance = instance,
  36. hCursor = win32.LoadCursorA(nil, win32.IDC_ARROW),
  37. }
  38. win32.RegisterClassW(&cls)
  39. r: win32.RECT
  40. r.right = i32(window_width)
  41. r.bottom = i32(window_height)
  42. s.flags = flags
  43. style := style_from_flags(flags)
  44. win32.AdjustWindowRect(&r, style, false)
  45. hwnd := win32.CreateWindowW(CLASS_NAME,
  46. win32.utf8_to_wstring(window_title),
  47. style,
  48. 100, 10, r.right - r.left, r.bottom - r.top,
  49. nil, nil, instance, nil,
  50. )
  51. win32.XInputEnable(true)
  52. assert(hwnd != nil, "Failed creating window")
  53. s.hwnd = hwnd
  54. }
  55. win32_shutdown :: proc() {
  56. delete(s.events)
  57. win32.DestroyWindow(s.hwnd)
  58. }
  59. win32_window_handle :: proc() -> Window_Handle {
  60. return Window_Handle(s.hwnd)
  61. }
  62. win32_process_events :: proc() {
  63. msg: win32.MSG
  64. for win32.PeekMessageW(&msg, nil, 0, 0, win32.PM_REMOVE) {
  65. win32.TranslateMessage(&msg)
  66. win32.DispatchMessageW(&msg)
  67. }
  68. for gamepad in 0..<4 {
  69. gp_event: win32.XINPUT_KEYSTROKE
  70. for win32.XInputGetKeystroke(win32.XUSER(gamepad), 0, &gp_event) == .SUCCESS {
  71. button: Maybe(Gamepad_Button)
  72. #partial switch gp_event.VirtualKey {
  73. case .DPAD_UP: button = .Left_Face_Up
  74. case .DPAD_DOWN: button = .Left_Face_Down
  75. case .DPAD_LEFT: button = .Left_Face_Left
  76. case .DPAD_RIGHT: button = .Left_Face_Right
  77. case .Y: button = .Right_Face_Up
  78. case .A: button = .Right_Face_Down
  79. case .X: button = .Right_Face_Left
  80. case .B: button = .Right_Face_Right
  81. case .LSHOULDER: button = .Left_Shoulder
  82. case .LTRIGGER: button = .Left_Trigger
  83. case .RSHOULDER: button = .Right_Shoulder
  84. case .RTRIGGER: button = .Right_Trigger
  85. case .BACK: button = .Middle_Face_Left
  86. // Not sure you can get the "middle button" with XInput
  87. case .START: button = .Middle_Face_Right
  88. case .LTHUMB_PRESS: button = .Left_Stick_Press
  89. case .RTHUMB_PRESS: button = .Right_Stick_Press
  90. }
  91. b := button.? or_continue
  92. evt: Window_Event
  93. if .KEYDOWN in gp_event.Flags {
  94. evt = Window_Event_Gamepad_Button_Went_Down {
  95. gamepad = gamepad,
  96. button = b,
  97. }
  98. } else if .KEYUP in gp_event.Flags {
  99. evt = Window_Event_Gamepad_Button_Went_Up {
  100. gamepad = gamepad,
  101. button = b,
  102. }
  103. }
  104. if evt != nil {
  105. append(&s.events, evt)
  106. }
  107. }
  108. }
  109. }
  110. win32_get_events :: proc() -> []Window_Event {
  111. return s.events[:]
  112. }
  113. win32_clear_events :: proc() {
  114. runtime.clear(&s.events)
  115. }
  116. win32_set_position :: proc(x: int, y: int) {
  117. // TODO: Does x, y respect monitor DPI?
  118. win32.SetWindowPos(
  119. s.hwnd,
  120. {},
  121. i32(x),
  122. i32(y),
  123. 0,
  124. 0,
  125. win32.SWP_NOACTIVATE | win32.SWP_NOZORDER | win32.SWP_NOSIZE,
  126. )
  127. }
  128. win32_set_size :: proc(w, h: int) {
  129. win32.SetWindowPos(
  130. s.hwnd,
  131. {},
  132. 0,
  133. 0,
  134. i32(w),
  135. i32(h),
  136. win32.SWP_NOACTIVATE | win32.SWP_NOZORDER | win32.SWP_NOMOVE,
  137. )
  138. }
  139. win32_set_flags :: proc(flags: Window_Flags) {
  140. s.flags = flags
  141. style := style_from_flags(flags)
  142. win32.SetWindowLongW(s.hwnd, win32.GWL_STYLE, i32(style))
  143. }
  144. win32_set_internal_state :: proc(state: rawptr) {
  145. assert(state != nil)
  146. s = (^Win32_State)(state)
  147. }
  148. Win32_State :: struct {
  149. allocator: runtime.Allocator,
  150. custom_context: runtime.Context,
  151. hwnd: win32.HWND,
  152. flags: Window_Flags,
  153. events: [dynamic]Window_Event,
  154. }
  155. style_from_flags :: proc(flags: Window_Flags) -> win32.DWORD {
  156. style := win32.WS_OVERLAPPED | win32.WS_CAPTION | win32.WS_SYSMENU |
  157. win32.WS_MINIMIZEBOX | win32.WS_MAXIMIZEBOX | win32.WS_VISIBLE
  158. if .Resizable in flags {
  159. style |= win32.WS_THICKFRAME
  160. }
  161. return style
  162. }
  163. s: ^Win32_State
  164. window_proc :: proc "stdcall" (hwnd: win32.HWND, msg: win32.UINT, wparam: win32.WPARAM, lparam: win32.LPARAM) -> win32.LRESULT {
  165. context = s.custom_context
  166. switch msg {
  167. case win32.WM_DESTROY:
  168. win32.PostQuitMessage(0)
  169. case win32.WM_CLOSE:
  170. append(&s.events, Window_Event_Close_Wanted{})
  171. case win32.WM_KEYDOWN:
  172. key := WIN32_VK_MAP[wparam]
  173. append(&s.events, Window_Event_Key_Went_Down {
  174. key = key,
  175. })
  176. return 0
  177. case win32.WM_KEYUP:
  178. key := WIN32_VK_MAP[wparam]
  179. append(&s.events, Window_Event_Key_Went_Up {
  180. key = key,
  181. })
  182. return 0
  183. case win32.WM_MOUSEMOVE:
  184. x := win32.GET_X_LPARAM(lparam)
  185. y := win32.GET_Y_LPARAM(lparam)
  186. append(&s.events, Window_Event_Mouse_Move {
  187. position = {f32(x), f32(y)},
  188. })
  189. return 0
  190. case win32.WM_MOUSEWHEEL:
  191. delta := f32(win32.GET_WHEEL_DELTA_WPARAM(wparam))/win32.WHEEL_DELTA
  192. append(&s.events, Window_Event_Mouse_Wheel {
  193. delta = delta,
  194. })
  195. case win32.WM_LBUTTONDOWN:
  196. append(&s.events, Window_Event_Mouse_Button_Went_Down {
  197. button = .Left,
  198. })
  199. case win32.WM_LBUTTONUP:
  200. append(&s.events, Window_Event_Mouse_Button_Went_Up {
  201. button = .Left,
  202. })
  203. case win32.WM_MBUTTONDOWN:
  204. append(&s.events, Window_Event_Mouse_Button_Went_Down {
  205. button = .Middle,
  206. })
  207. case win32.WM_MBUTTONUP:
  208. append(&s.events, Window_Event_Mouse_Button_Went_Up {
  209. button = .Middle,
  210. })
  211. case win32.WM_RBUTTONDOWN:
  212. append(&s.events, Window_Event_Mouse_Button_Went_Down {
  213. button = .Right,
  214. })
  215. case win32.WM_RBUTTONUP:
  216. append(&s.events, Window_Event_Mouse_Button_Went_Up {
  217. button = .Right,
  218. })
  219. case win32.WM_SIZE:
  220. width := win32.LOWORD(lparam)
  221. height := win32.HIWORD(lparam)
  222. append(&s.events, Window_Event_Resize {
  223. width = int(width),
  224. height = int(height),
  225. })
  226. }
  227. return win32.DefWindowProcW(hwnd, msg, wparam, lparam)
  228. }
  229. WIN32_VK_MAP := [255]Keyboard_Key {
  230. win32.VK_F1 = .F1,
  231. win32.VK_F2 = .F2,
  232. win32.VK_F3 = .F3,
  233. win32.VK_F4 = .F4,
  234. win32.VK_F5 = .F5,
  235. win32.VK_F6 = .F6,
  236. win32.VK_F7 = .F7,
  237. win32.VK_F8 = .F8,
  238. win32.VK_F9 = .F9,
  239. win32.VK_F10 = .F10,
  240. win32.VK_F11 = .F11,
  241. win32.VK_F12 = .F12,
  242. win32.VK_A = .A,
  243. win32.VK_B = .B,
  244. win32.VK_C = .C,
  245. win32.VK_D = .D,
  246. win32.VK_E = .E,
  247. win32.VK_F = .F,
  248. win32.VK_G = .G,
  249. win32.VK_H = .H,
  250. win32.VK_I = .I,
  251. win32.VK_J = .J,
  252. win32.VK_K = .K,
  253. win32.VK_L = .L,
  254. win32.VK_M = .M,
  255. win32.VK_N = .N,
  256. win32.VK_O = .O,
  257. win32.VK_P = .P,
  258. win32.VK_Q = .Q,
  259. win32.VK_R = .R,
  260. win32.VK_S = .S,
  261. win32.VK_T = .T,
  262. win32.VK_U = .U,
  263. win32.VK_V = .V,
  264. win32.VK_W = .W,
  265. win32.VK_X = .X,
  266. win32.VK_Y = .Y,
  267. win32.VK_Z = .Z,
  268. win32.VK_SPACE = .Space,
  269. win32.VK_LEFT = .Left,
  270. win32.VK_RIGHT = .Right,
  271. win32.VK_UP = .Up,
  272. win32.VK_DOWN = .Down,
  273. win32.VK_RETURN = .Enter,
  274. }