events.odin 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474
  1. #+build js wasm32, js wasm64p32
  2. package wasm_js_interface
  3. foreign import dom_lib "odin_dom"
  4. Event_Kind :: enum u32 {
  5. Invalid,
  6. Load,
  7. Unload,
  8. Error,
  9. Resize,
  10. Visibility_Change,
  11. Fullscreen_Change,
  12. Fullscreen_Error,
  13. Click,
  14. Double_Click,
  15. Mouse_Move,
  16. Mouse_Over,
  17. Mouse_Out,
  18. Mouse_Up,
  19. Mouse_Down,
  20. Key_Up,
  21. Key_Down,
  22. Key_Press,
  23. Scroll,
  24. Wheel,
  25. Focus,
  26. Focus_In,
  27. Focus_Out,
  28. Submit,
  29. Blur,
  30. Change,
  31. Hash_Change,
  32. Select,
  33. Animation_Start,
  34. Animation_End,
  35. Animation_Iteration,
  36. Animation_Cancel,
  37. Copy,
  38. Cut,
  39. Paste,
  40. // Drag,
  41. // Drag_Start,
  42. // Drag_End,
  43. // Drag_Enter,
  44. // Drag_Leave,
  45. // Drag_Over,
  46. // Drop,
  47. Pointer_Cancel,
  48. Pointer_Down,
  49. Pointer_Enter,
  50. Pointer_Leave,
  51. Pointer_Move,
  52. Pointer_Over,
  53. Pointer_Up,
  54. Got_Pointer_Capture,
  55. Lost_Pointer_Capture,
  56. Pointer_Lock_Change,
  57. Pointer_Lock_Error,
  58. Selection_Change,
  59. Selection_Start,
  60. Touch_Cancel,
  61. Touch_End,
  62. Touch_Move,
  63. Touch_Start,
  64. Transition_Start,
  65. Transition_End,
  66. Transition_Run,
  67. Transition_Cancel,
  68. Context_Menu,
  69. Gamepad_Connected,
  70. Gamepad_Disconnected,
  71. Custom,
  72. }
  73. event_kind_string := [Event_Kind]string{
  74. .Invalid = "",
  75. .Load = "load",
  76. .Unload = "unload",
  77. .Error = "error",
  78. .Resize = "resize",
  79. .Visibility_Change = "visibilitychange",
  80. .Fullscreen_Change = "fullscreenchange",
  81. .Fullscreen_Error = "fullscreenerror",
  82. .Click = "click",
  83. .Double_Click = "dblclick",
  84. .Mouse_Move = "mousemove",
  85. .Mouse_Over = "mouseover",
  86. .Mouse_Out = "mouseout",
  87. .Mouse_Up = "mouseup",
  88. .Mouse_Down = "mousedown",
  89. .Key_Up = "keyup",
  90. .Key_Down = "keydown",
  91. .Key_Press = "keypress",
  92. .Scroll = "scroll",
  93. .Wheel = "wheel",
  94. .Focus = "focus",
  95. .Focus_In = "focusin",
  96. .Focus_Out = "focusout",
  97. .Submit = "submit",
  98. .Blur = "blur",
  99. .Change = "change",
  100. .Hash_Change = "hashchange",
  101. .Select = "select",
  102. .Animation_Start = "animationstart",
  103. .Animation_End = "animationend",
  104. .Animation_Iteration = "animationiteration",
  105. .Animation_Cancel = "animationcancel",
  106. .Copy = "copy",
  107. .Cut = "cut",
  108. .Paste = "paste",
  109. // .Drag, = "drag",
  110. // .Drag_Start, = "dragstart",
  111. // .Drag_End, = "dragend",
  112. // .Drag_Enter, = "dragenter",
  113. // .Drag_Leave, = "dragleave",
  114. // .Drag_Over, = "dragover",
  115. // .Drop, = "drop",
  116. .Pointer_Cancel = "pointercancel",
  117. .Pointer_Down = "pointerdown",
  118. .Pointer_Enter = "pointerenter",
  119. .Pointer_Leave = "pointerleave",
  120. .Pointer_Move = "pointermove",
  121. .Pointer_Over = "pointerover",
  122. .Pointer_Up = "pointerup",
  123. .Got_Pointer_Capture = "gotpointercapture",
  124. .Lost_Pointer_Capture = "lostpointercapture",
  125. .Pointer_Lock_Change = "pointerlockchange",
  126. .Pointer_Lock_Error = "pointerlockerror",
  127. .Selection_Change = "selectionchange",
  128. .Selection_Start = "selectionstart",
  129. .Transition_Start = "transitionstart",
  130. .Transition_End = "transitionend",
  131. .Transition_Run = "transitionrun",
  132. .Transition_Cancel = "transitioncancel",
  133. .Touch_Cancel = "touchcancel",
  134. .Touch_End = "touchend",
  135. .Touch_Move = "touchmove",
  136. .Touch_Start = "touchstart",
  137. .Context_Menu = "contextmenu",
  138. .Gamepad_Connected = "gamepadconnected",
  139. .Gamepad_Disconnected = "gamepaddisconnected",
  140. .Custom = "?custom?",
  141. }
  142. Delta_Mode :: enum u32 {
  143. Pixel = 0,
  144. Line = 1,
  145. Page = 2,
  146. }
  147. Key_Location :: enum u8 {
  148. Standard = 0,
  149. Left = 1,
  150. Right = 2,
  151. Numpad = 3,
  152. }
  153. KEYBOARD_MAX_KEY_SIZE :: 32
  154. KEYBOARD_MAX_CODE_SIZE :: 32
  155. GAMEPAD_MAX_ID_SIZE :: 96
  156. GAMEPAD_MAX_MAPPING_SIZE :: 64
  157. GAMEPAD_MAX_BUTTONS :: 64
  158. GAMEPAD_MAX_AXES :: 16
  159. Event_Target_Kind :: enum u32 {
  160. Element = 0,
  161. Document = 1,
  162. Window = 2,
  163. }
  164. Event_Phase :: enum u8 {
  165. None = 0,
  166. Capturing_Phase = 1,
  167. At_Target = 2,
  168. Bubbling_Phase = 3,
  169. }
  170. Event_Option :: enum u8 {
  171. Bubbles = 0,
  172. Cancelable = 1,
  173. Composed = 2,
  174. }
  175. Event_Options :: distinct bit_set[Event_Option; u8]
  176. Gamepad_Button :: struct {
  177. value: f64,
  178. pressed: bool,
  179. touched: bool,
  180. }
  181. Gamepad_State :: struct {
  182. id: string,
  183. mapping: string,
  184. index: int,
  185. connected: bool,
  186. timestamp: f64,
  187. button_count: int,
  188. axis_count: int,
  189. buttons: [GAMEPAD_MAX_BUTTONS]Gamepad_Button `fmt:"v,button_count"`,
  190. axes: [GAMEPAD_MAX_AXES]f64 `fmt:"v,axes_count"`,
  191. _id_len: int `fmt:"-"`,
  192. _mapping_len: int `fmt:"-"`,
  193. _id_buf: [GAMEPAD_MAX_ID_SIZE]byte `fmt:"-"`,
  194. _mapping_buf: [GAMEPAD_MAX_MAPPING_SIZE]byte `fmt:"-"`,
  195. }
  196. Pointer_Type :: enum u8 {
  197. Mouse,
  198. Pen,
  199. Touch,
  200. }
  201. Event :: struct {
  202. kind: Event_Kind,
  203. target_kind: Event_Target_Kind,
  204. current_target_kind: Event_Target_Kind,
  205. id: string,
  206. timestamp: f64,
  207. phase: Event_Phase,
  208. options: Event_Options,
  209. is_composing: bool,
  210. is_trusted: bool,
  211. using data: struct #raw_union #align(8) {
  212. scroll: struct {
  213. delta: [2]f64,
  214. },
  215. visibility_change: struct {
  216. is_visible: bool,
  217. },
  218. wheel: struct {
  219. delta: [3]f64,
  220. delta_mode: Delta_Mode,
  221. },
  222. key: struct {
  223. key: string,
  224. code: string,
  225. location: Key_Location,
  226. ctrl: bool,
  227. shift: bool,
  228. alt: bool,
  229. meta: bool,
  230. repeat: bool,
  231. char: rune,
  232. _key_len: int `fmt:"-"`,
  233. _code_len: int `fmt:"-"`,
  234. _key_buf: [KEYBOARD_MAX_KEY_SIZE]byte `fmt:"-"`,
  235. _code_buf: [KEYBOARD_MAX_KEY_SIZE]byte `fmt:"-"`,
  236. },
  237. mouse: struct {
  238. screen: [2]i64,
  239. client: [2]i64,
  240. offset: [2]i64,
  241. page: [2]i64,
  242. movement: [2]i64,
  243. ctrl: bool,
  244. shift: bool,
  245. alt: bool,
  246. meta: bool,
  247. button: i16,
  248. buttons: bit_set[0..<16; u16],
  249. pointer: struct {
  250. altitude_angle: f64,
  251. azimuth_angle: f64,
  252. persistent_device_id: int,
  253. pointer_id: int,
  254. width: int,
  255. height: int,
  256. pressure: f64,
  257. tangential_pressure: f64,
  258. tilt: [2]f64,
  259. twist: f64,
  260. pointer_type: Pointer_Type,
  261. is_primary: bool,
  262. },
  263. },
  264. gamepad: Gamepad_State,
  265. },
  266. user_data: rawptr,
  267. callback: proc(e: Event),
  268. }
  269. @(default_calling_convention="contextless")
  270. foreign dom_lib {
  271. event_stop_propagation :: proc() ---
  272. event_stop_immediate_propagation :: proc() ---
  273. event_prevent_default :: proc() ---
  274. dispatch_custom_event :: proc(id: string, name: string, options := Event_Options{}) -> bool ---
  275. }
  276. add_event_listener :: proc(id: string, kind: Event_Kind, user_data: rawptr, callback: proc(e: Event), use_capture := false) -> bool {
  277. @(default_calling_convention="contextless")
  278. foreign dom_lib {
  279. @(link_name="add_event_listener")
  280. _add_event_listener :: proc(id: string, name: string, name_code: Event_Kind, user_data: rawptr, callback: proc "odin" (Event), use_capture: bool) -> bool ---
  281. }
  282. // TODO: Pointer_Lock_Change etc related stuff for all different browsers
  283. return _add_event_listener(id, event_kind_string[kind], kind, user_data, callback, use_capture)
  284. }
  285. remove_event_listener :: proc(id: string, kind: Event_Kind, user_data: rawptr, callback: proc(e: Event), use_capture := false) -> bool {
  286. @(default_calling_convention="contextless")
  287. foreign dom_lib {
  288. @(link_name="remove_event_listener")
  289. _remove_event_listener :: proc(id: string, name: string, user_data: rawptr, callback: proc "odin" (Event), use_capture: bool) -> bool ---
  290. }
  291. return _remove_event_listener(id, event_kind_string[kind], user_data, callback, use_capture)
  292. }
  293. add_window_event_listener :: proc(kind: Event_Kind, user_data: rawptr, callback: proc(e: Event), use_capture := false) -> bool {
  294. @(default_calling_convention="contextless")
  295. foreign dom_lib {
  296. @(link_name="add_window_event_listener")
  297. _add_window_event_listener :: proc(name: string, name_code: Event_Kind, user_data: rawptr, callback: proc "odin" (Event), use_capture: bool) -> bool ---
  298. }
  299. return _add_window_event_listener(event_kind_string[kind], kind, user_data, callback, use_capture)
  300. }
  301. remove_window_event_listener :: proc(kind: Event_Kind, user_data: rawptr, callback: proc(e: Event), use_capture := false) -> bool {
  302. @(default_calling_convention="contextless")
  303. foreign dom_lib {
  304. @(link_name="remove_window_event_listener")
  305. _remove_window_event_listener :: proc(name: string, user_data: rawptr, callback: proc "odin" (Event), use_capture: bool) -> bool ---
  306. }
  307. return _remove_window_event_listener(event_kind_string[kind], user_data, callback, use_capture)
  308. }
  309. add_document_event_listener :: proc(kind: Event_Kind, user_data: rawptr, callback: proc(e: Event), use_capture := false) -> bool {
  310. @(default_calling_convention="contextless")
  311. foreign dom_lib {
  312. @(link_name="add_document_event_listener")
  313. _add_document_event_listener :: proc(name: string, name_code: Event_Kind, user_data: rawptr, callback: proc "odin" (Event), use_capture: bool) -> bool ---
  314. }
  315. return _add_document_event_listener(event_kind_string[kind], kind, user_data, callback, use_capture)
  316. }
  317. remove_document_event_listener :: proc(kind: Event_Kind, user_data: rawptr, callback: proc(e: Event), use_capture := false) -> bool {
  318. @(default_calling_convention="contextless")
  319. foreign dom_lib {
  320. @(link_name="remove_document_event_listener")
  321. _remove_document_event_listener :: proc(name: string, user_data: rawptr, callback: proc "odin" (Event), use_capture: bool) -> bool ---
  322. }
  323. return _remove_document_event_listener(event_kind_string[kind], user_data, callback, use_capture)
  324. }
  325. remove_event_listener_from_event :: proc(e: Event) -> bool {
  326. from_use_capture_false: bool
  327. from_use_capture_true: bool
  328. if e.id == "" {
  329. from_use_capture_false = remove_window_event_listener(e.kind, e.user_data, e.callback, false)
  330. from_use_capture_true = remove_window_event_listener(e.kind, e.user_data, e.callback, true)
  331. from_use_capture_false |= remove_document_event_listener(e.kind, e.user_data, e.callback, false)
  332. from_use_capture_true |= remove_document_event_listener(e.kind, e.user_data, e.callback, true)
  333. } else {
  334. from_use_capture_false = remove_event_listener(e.id, e.kind, e.user_data, e.callback, false)
  335. from_use_capture_true = remove_event_listener(e.id, e.kind, e.user_data, e.callback, true)
  336. }
  337. return from_use_capture_false || from_use_capture_true
  338. }
  339. add_custom_event_listener :: proc(id: string, name: string, user_data: rawptr, callback: proc(e: Event), use_capture := false) -> bool {
  340. @(default_calling_convention="contextless")
  341. foreign dom_lib {
  342. @(link_name="add_event_listener")
  343. _add_event_listener :: proc(id: string, name: string, name_code: Event_Kind, user_data: rawptr, callback: proc "odin" (Event), use_capture: bool) -> bool ---
  344. }
  345. return _add_event_listener(id, name, .Custom, user_data, callback, use_capture)
  346. }
  347. remove_custom_event_listener :: proc(id: string, name: string, user_data: rawptr, callback: proc(e: Event), use_capture := false) -> bool {
  348. @(default_calling_convention="contextless")
  349. foreign dom_lib {
  350. @(link_name="remove_event_listener")
  351. _remove_event_listener :: proc(id: string, name: string, user_data: rawptr, callback: proc "odin" (Event), use_capture: bool) -> bool ---
  352. }
  353. return _remove_event_listener(id, name, user_data, callback, use_capture)
  354. }
  355. get_gamepad_state :: proc "contextless" (index: int, s: ^Gamepad_State) -> bool {
  356. @(default_calling_convention="contextless")
  357. foreign dom_lib {
  358. @(link_name="get_gamepad_state")
  359. _get_gamepad_state :: proc(index: int, s: ^Gamepad_State) -> bool ---
  360. }
  361. if s == nil {
  362. return false
  363. }
  364. if !_get_gamepad_state(index, s) {
  365. return false
  366. }
  367. s.id = string(s._id_buf[:s._id_len])
  368. s.mapping = string(s._mapping_buf[:s._mapping_len])
  369. return true
  370. }
  371. @(export, link_name="odin_dom_do_event_callback")
  372. do_event_callback :: proc(user_data: rawptr, callback: proc(e: Event)) {
  373. @(default_calling_convention="contextless")
  374. foreign dom_lib {
  375. init_event_raw :: proc(e: ^Event) ---
  376. }
  377. if callback != nil {
  378. event := Event{
  379. user_data = user_data,
  380. callback = callback,
  381. }
  382. init_event_raw(&event)
  383. #partial switch event.kind {
  384. case .Key_Up, .Key_Down, .Key_Press:
  385. event.key.key = string(event.key._key_buf[:event.key._key_len])
  386. event.key.code = string(event.key._code_buf[:event.key._code_len])
  387. case .Gamepad_Connected, .Gamepad_Disconnected:
  388. event.gamepad.id = string(event.gamepad._id_buf[:event.gamepad._id_len])
  389. event.gamepad.mapping = string(event.gamepad._mapping_buf[:event.gamepad._mapping_len])
  390. }
  391. callback(event)
  392. }
  393. }