From 1ad5856380f801a1ba4047b21625705cafa1f3ca Mon Sep 17 00:00:00 2001 From: EliteMasterEric Date: Thu, 13 Jun 2024 16:15:07 -0400 Subject: [PATCH 1/2] Create event functions for precise input handling. --- project/include/system/System.h | 1 + project/include/ui/GamepadEvent.h | 1 + project/include/ui/KeyEvent.h | 1 + project/src/ExternalInterface.cpp | 18 ++++++- project/src/backend/sdl/SDLApplication.cpp | 6 +++ project/src/backend/sdl/SDLSystem.cpp | 7 +++ project/src/ui/GamepadEvent.cpp | 5 ++ project/src/ui/KeyEvent.cpp | 4 ++ .../backend/html5/HTML5Application.hx | 11 ++++- .../backend/native/NativeApplication.hx | 29 +++++++++--- .../_internal/backend/native/NativeCFFI.hx | 9 ++++ src/lime/app/Application.hx | 47 +++++++++++++++++++ src/lime/ui/Gamepad.hx | 3 ++ src/lime/ui/Window.hx | 2 + 14 files changed, 134 insertions(+), 10 deletions(-) diff --git a/project/include/system/System.h b/project/include/system/System.h index ec67cdd16e..fc0a77c383 100644 --- a/project/include/system/System.h +++ b/project/include/system/System.h @@ -30,6 +30,7 @@ namespace lime { static void GCExitBlocking (); static void GCTryEnterBlocking (); static void GCTryExitBlocking (); + static int GetTicks (); static bool GetAllowScreenTimeout (); static std::wstring* GetDeviceModel (); static std::wstring* GetDeviceVendor (); diff --git a/project/include/ui/GamepadEvent.h b/project/include/ui/GamepadEvent.h index 607ef9cfc8..79f95583d1 100644 --- a/project/include/ui/GamepadEvent.h +++ b/project/include/ui/GamepadEvent.h @@ -28,6 +28,7 @@ namespace lime { int id; GamepadEventType type; double axisValue; + int timestamp; static ValuePointer* callback; static ValuePointer* eventObject; diff --git a/project/include/ui/KeyEvent.h b/project/include/ui/KeyEvent.h index 28e6fcc6fd..803a6290a9 100644 --- a/project/include/ui/KeyEvent.h +++ b/project/include/ui/KeyEvent.h @@ -25,6 +25,7 @@ namespace lime { int modifier; KeyEventType type; int windowID; + int timestamp; static ValuePointer* callback; static ValuePointer* eventObject; diff --git a/project/src/ExternalInterface.cpp b/project/src/ExternalInterface.cpp index fc1fdf1b41..7d8e7fdad4 100644 --- a/project/src/ExternalInterface.cpp +++ b/project/src/ExternalInterface.cpp @@ -2648,6 +2648,18 @@ namespace lime { } + int lime_sdl_get_ticks () { + + return System::GetTicks(); + + } + + + HL_PRIM int HL_NAME(hl_sdl_get_ticks) () { + + return System::GetTicks(); + + } bool lime_system_get_allow_screen_timeout () { @@ -3997,6 +4009,7 @@ namespace lime { DEFINE_PRIME3 (lime_png_decode_file); DEFINE_PRIME2v (lime_render_event_manager_register); DEFINE_PRIME2v (lime_sensor_event_manager_register); + DEFINE_PRIME0 (lime_sdl_get_ticks); DEFINE_PRIME0 (lime_system_get_allow_screen_timeout); DEFINE_PRIME0 (lime_system_get_device_model); DEFINE_PRIME0 (lime_system_get_device_vendor); @@ -4069,9 +4082,9 @@ namespace lime { #define _TCLIPBOARD_EVENT _OBJ (_I32) #define _TDISPLAYMODE _OBJ (_I32 _I32 _I32 _I32) #define _TDROP_EVENT _OBJ (_BYTES _I32) - #define _TGAMEPAD_EVENT _OBJ (_I32 _I32 _I32 _I32 _F64) + #define _TGAMEPAD_EVENT _OBJ (_I32 _I32 _I32 _I32 _F64 _I32) #define _TJOYSTICK_EVENT _OBJ (_I32 _I32 _I32 _I32 _F64 _F64) - #define _TKEY_EVENT _OBJ (_F64 _I32 _I32 _I32) + #define _TKEY_EVENT _OBJ (_F64 _I32 _I32 _I32 _I32) #define _TMOUSE_EVENT _OBJ (_I32 _F64 _F64 _I32 _I32 _F64 _F64 _I32) #define _TRECTANGLE _OBJ (_F64 _F64 _F64 _F64) #define _TRENDER_EVENT _OBJ (_I32) @@ -4185,6 +4198,7 @@ namespace lime { DEFINE_HL_PRIM (_TIMAGEBUFFER, hl_png_decode_file, _STRING _BOOL _TIMAGEBUFFER); DEFINE_HL_PRIM (_VOID, hl_render_event_manager_register, _FUN (_VOID, _NO_ARG) _TRENDER_EVENT); DEFINE_HL_PRIM (_VOID, hl_sensor_event_manager_register, _FUN (_VOID, _NO_ARG) _TSENSOR_EVENT); + DEFINE_HL_PRIM (_I32, hl_sdl_get_ticks, _NO_ARG); DEFINE_HL_PRIM (_BOOL, hl_system_get_allow_screen_timeout, _NO_ARG); DEFINE_HL_PRIM (_BYTES, hl_system_get_device_model, _NO_ARG); DEFINE_HL_PRIM (_BYTES, hl_system_get_device_vendor, _NO_ARG); diff --git a/project/src/backend/sdl/SDLApplication.cpp b/project/src/backend/sdl/SDLApplication.cpp index 53674f53a9..1380119f5b 100644 --- a/project/src/backend/sdl/SDLApplication.cpp +++ b/project/src/backend/sdl/SDLApplication.cpp @@ -401,6 +401,7 @@ namespace lime { gamepadsAxisMap[event->caxis.which][event->caxis.axis] = event->caxis.value; gamepadEvent.axisValue = event->caxis.value / (event->caxis.value > 0 ? 32767.0 : 32768.0); + gamepadEvent.timestamp = event->common.timestamp; GamepadEvent::Dispatch (&gamepadEvent); break; @@ -410,6 +411,7 @@ namespace lime { gamepadEvent.type = GAMEPAD_BUTTON_DOWN; gamepadEvent.button = event->cbutton.button; gamepadEvent.id = event->cbutton.which; + gamepadEvent.timestamp = event->common.timestamp; GamepadEvent::Dispatch (&gamepadEvent); break; @@ -419,6 +421,7 @@ namespace lime { gamepadEvent.type = GAMEPAD_BUTTON_UP; gamepadEvent.button = event->cbutton.button; gamepadEvent.id = event->cbutton.which; + gamepadEvent.timestamp = event->common.timestamp; GamepadEvent::Dispatch (&gamepadEvent); break; @@ -429,6 +432,7 @@ namespace lime { gamepadEvent.type = GAMEPAD_CONNECT; gamepadEvent.id = SDLGamepad::GetInstanceID (event->cdevice.which); + gamepadEvent.timestamp = event->common.timestamp; GamepadEvent::Dispatch (&gamepadEvent); @@ -440,6 +444,7 @@ namespace lime { gamepadEvent.type = GAMEPAD_DISCONNECT; gamepadEvent.id = event->cdevice.which; + gamepadEvent.timestamp = event->common.timestamp; GamepadEvent::Dispatch (&gamepadEvent); SDLGamepad::Disconnect (event->cdevice.which); @@ -561,6 +566,7 @@ namespace lime { keyEvent.keyCode = event->key.keysym.sym; keyEvent.modifier = event->key.keysym.mod; keyEvent.windowID = event->key.windowID; + keyEvent.timestamp = event->common.timestamp; if (keyEvent.type == KEY_DOWN) { diff --git a/project/src/backend/sdl/SDLSystem.cpp b/project/src/backend/sdl/SDLSystem.cpp index 058f2d3dd8..6f784eee6f 100644 --- a/project/src/backend/sdl/SDLSystem.cpp +++ b/project/src/backend/sdl/SDLSystem.cpp @@ -91,6 +91,13 @@ namespace lime { } + int System::GetTicks () { + + return SDL_GetTicks (); + + } + + bool System::GetAllowScreenTimeout () { return SDL_IsScreenSaverEnabled (); diff --git a/project/src/ui/GamepadEvent.cpp b/project/src/ui/GamepadEvent.cpp index 64fa1c5384..cb7819b0bb 100644 --- a/project/src/ui/GamepadEvent.cpp +++ b/project/src/ui/GamepadEvent.cpp @@ -13,6 +13,7 @@ namespace lime { static int id_id; static int id_type; static int id_value; + static int id_timestamp; static bool init = false; @@ -23,6 +24,7 @@ namespace lime { button = 0; id = 0; type = GAMEPAD_AXIS_MOVE; + timestamp = 0; } @@ -40,6 +42,7 @@ namespace lime { id_id = val_id ("id"); id_type = val_id ("type"); id_value = val_id ("axisValue"); + id_timestamp = val_id ("timestamp"); init = true; } @@ -51,6 +54,7 @@ namespace lime { alloc_field (object, id_id, alloc_int (event->id)); alloc_field (object, id_type, alloc_int (event->type)); alloc_field (object, id_value, alloc_float (event->axisValue)); + alloc_field (object, id_timestamp, alloc_int (event->timestamp)); } else { @@ -61,6 +65,7 @@ namespace lime { eventObject->id = event->id; eventObject->type = event->type; eventObject->axisValue = event->axisValue; + eventObject->timestamp = event->timestamp; } diff --git a/project/src/ui/KeyEvent.cpp b/project/src/ui/KeyEvent.cpp index 42acd15560..81ad7551c4 100644 --- a/project/src/ui/KeyEvent.cpp +++ b/project/src/ui/KeyEvent.cpp @@ -12,6 +12,7 @@ namespace lime { static int id_modifier; static int id_type; static int id_windowID; + static int id_timestamp; static bool init = false; @@ -21,6 +22,7 @@ namespace lime { modifier = 0; type = KEY_DOWN; windowID = 0; + timestamp = 0; } @@ -37,6 +39,7 @@ namespace lime { id_modifier = val_id ("modifier"); id_type = val_id ("type"); id_windowID = val_id ("windowID"); + id_timestamp = val_id ("timestamp"); init = true; } @@ -47,6 +50,7 @@ namespace lime { alloc_field (object, id_modifier, alloc_int (event->modifier)); alloc_field (object, id_type, alloc_int (event->type)); alloc_field (object, id_windowID, alloc_int (event->windowID)); + alloc_field (object, id_timestamp, alloc_int (event->timestamp)); } else { diff --git a/src/lime/_internal/backend/html5/HTML5Application.hx b/src/lime/_internal/backend/html5/HTML5Application.hx index 3b137e92b1..751c84aa3c 100644 --- a/src/lime/_internal/backend/html5/HTML5Application.hx +++ b/src/lime/_internal/backend/html5/HTML5Application.hx @@ -412,12 +412,14 @@ class HTML5Application var keyCode = cast convertKeyCode(event.keyCode != null ? event.keyCode : event.which); var modifier = (event.shiftKey ? (KeyModifier.SHIFT) : 0) | (event.ctrlKey ? (KeyModifier.CTRL) : 0) | (event.altKey ? (KeyModifier.ALT) : 0) | (event.metaKey ? (KeyModifier.META) : 0); + var timestamp = haxe.Int64.fromFloat(event.timeStamp); if (event.type == "keydown") { parent.window.onKeyDown.dispatch(keyCode, modifier); + parent.window.onKeyDownPrecise.dispatch(keyCode, modifier, timestamp); - if (parent.window.onKeyDown.canceled && event.cancelable) + if ((parent.window.onKeyDown.canceled || parent.window.onKeyDownPrecise.canceled) && event.cancelable) { event.preventDefault(); } @@ -425,8 +427,9 @@ class HTML5Application else { parent.window.onKeyUp.dispatch(keyCode, modifier); + parent.window.onKeyUpPrecise.dispatch(keyCode, modifier, timestamp); - if (parent.window.onKeyUp.canceled && event.cancelable) + if ((parent.window.onKeyUp.canceled || parent.window.onKeyUpPrecise.canceled) && event.cancelable) { event.preventDefault(); } @@ -615,13 +618,17 @@ class HTML5Application default: continue; } + var timestamp = haxe.Int64.fromFloat(js.Browser.window.performance.now()); + if (value > 0) { gamepad.onButtonDown.dispatch(button); + gamepad.onButtonDownPrecise.dispatch(button, timestamp); } else { gamepad.onButtonUp.dispatch(button); + gamepad.onButtonUpPrecise.dispatch(button, timestamp); } } } diff --git a/src/lime/_internal/backend/native/NativeApplication.hx b/src/lime/_internal/backend/native/NativeApplication.hx index 2208624bfb..ee92dd5ac1 100644 --- a/src/lime/_internal/backend/native/NativeApplication.hx +++ b/src/lime/_internal/backend/native/NativeApplication.hx @@ -198,15 +198,24 @@ class NativeApplication { case AXIS_MOVE: var gamepad = Gamepad.devices.get(gamepadEventInfo.id); - if (gamepad != null) gamepad.onAxisMove.dispatch(gamepadEventInfo.axis, gamepadEventInfo.axisValue); + if (gamepad != null) { + gamepad.onAxisMove.dispatch(gamepadEventInfo.axis, gamepadEventInfo.axisValue); + gamepad.onAxisMovePrecise.dispatch(gamepadEventInfo.axis, gamepadEventInfo.axisValue, gamepadEventInfo.timestamp); + } case BUTTON_DOWN: var gamepad = Gamepad.devices.get(gamepadEventInfo.id); - if (gamepad != null) gamepad.onButtonDown.dispatch(gamepadEventInfo.button); + if (gamepad != null) { + gamepad.onButtonDown.dispatch(gamepadEventInfo.button); + gamepad.onButtonDownPrecise.dispatch(gamepadEventInfo.button, gamepadEventInfo.timestamp); + } case BUTTON_UP: var gamepad = Gamepad.devices.get(gamepadEventInfo.id); - if (gamepad != null) gamepad.onButtonUp.dispatch(gamepadEventInfo.button); + if (gamepad != null) { + gamepad.onButtonUp.dispatch(gamepadEventInfo.button); + gamepad.onButtonUpPrecise.dispatch(gamepadEventInfo.button, gamepadEventInfo.timestamp); + } case CONNECT: Gamepad.__connect(gamepadEventInfo.id); @@ -696,13 +705,17 @@ class NativeApplication public var type:GamepadEventType; public var axisValue:Float; - public function new(type:GamepadEventType = null, id:Int = 0, button:Int = 0, axis:Int = 0, value:Float = 0) + // TODO: This should probably be an Int64 + public var timestamp:Int = 0; + + public function new(type:GamepadEventType = null, id:Int = 0, button:Int = 0, axis:Int = 0, value:Float = 0, timestamp:Int = 0) { this.type = type; this.id = id; this.button = button; this.axis = axis; this.axisValue = value; + this.timestamp = timestamp; } public function clone():GamepadEventInfo @@ -762,17 +775,21 @@ class NativeApplication public var type:KeyEventType; public var windowID:Int; - public function new(type:KeyEventType = null, windowID:Int = 0, keyCode: Float = 0, modifier:Int = 0) + // TODO: This should probably be an Int64 + public var timestamp:Int = 0; + + public function new(type:KeyEventType = null, windowID:Int = 0, keyCode: Float = 0, modifier:Int = 0, timestamp:Int = 0) { this.type = type; this.windowID = windowID; this.keyCode = keyCode; this.modifier = modifier; + this.timestamp = timestamp; } public function clone():KeyEventInfo { - return new KeyEventInfo(type, windowID, keyCode, modifier); + return new KeyEventInfo(type, windowID, keyCode, modifier, timestamp); } } diff --git a/src/lime/_internal/backend/native/NativeCFFI.hx b/src/lime/_internal/backend/native/NativeCFFI.hx index 33ce3df541..a9e302a659 100644 --- a/src/lime/_internal/backend/native/NativeCFFI.hx +++ b/src/lime/_internal/backend/native/NativeCFFI.hx @@ -241,6 +241,8 @@ class NativeCFFI @:cffi private static function lime_sensor_event_manager_register(callback:Dynamic, eventObject:Dynamic):Void; + @:cffi private static function lime_sdl_get_ticks():Int; + @:cffi private static function lime_system_get_allow_screen_timeout():Bool; @:cffi private static function lime_system_set_allow_screen_timeout(value:Bool):Bool; @@ -520,6 +522,7 @@ class NativeCFFI "lime_render_event_manager_register", "oov", false)); private static var lime_sensor_event_manager_register = new cpp.Callablecpp.Object->cpp.Void>(cpp.Prime._loadPrime("lime", "lime_sensor_event_manager_register", "oov", false)); + private static var lime_sdl_get_ticks = new cpp.CallableInt>(cpp.Prime._loadPrime("lime", "lime_sdl_get_ticks", "i", false)); private static var lime_system_get_allow_screen_timeout = new cpp.CallableBool>(cpp.Prime._loadPrime("lime", "lime_system_get_allow_screen_timeout", "b", false)); private static var lime_system_set_allow_screen_timeout = new cpp.CallableBool>(cpp.Prime._loadPrime("lime", @@ -716,6 +719,7 @@ class NativeCFFI private static var lime_png_decode_file = CFFI.load("lime", "lime_png_decode_file", 3); private static var lime_render_event_manager_register = CFFI.load("lime", "lime_render_event_manager_register", 2); private static var lime_sensor_event_manager_register = CFFI.load("lime", "lime_sensor_event_manager_register", 2); + private static var lime_sdl_get_ticks = CFFI.load("lime", "lime_sdl_get_ticks", 0); private static var lime_system_get_allow_screen_timeout = CFFI.load("lime", "lime_system_get_allow_screen_timeout", 0); private static var lime_system_set_allow_screen_timeout = CFFI.load("lime", "lime_system_set_allow_screen_timeout", 1); private static var lime_system_get_device_model = CFFI.load("lime", "lime_system_get_device_model", 0); @@ -1164,6 +1168,11 @@ class NativeCFFI @:hlNative("lime", "hl_sensor_event_manager_register") private static function lime_sensor_event_manager_register(callback:Void->Void, eventObject:SensorEventInfo):Void {} + @:hlNative("lime", "hl_sdl_get_ticks") private static function lime_sdl_get_ticks():Int + { + return 0; + } + @:hlNative("lime", "hl_system_get_allow_screen_timeout") private static function lime_system_get_allow_screen_timeout():Bool { return false; diff --git a/src/lime/app/Application.hx b/src/lime/app/Application.hx index 87cf6ce6d1..f915bc2f50 100644 --- a/src/lime/app/Application.hx +++ b/src/lime/app/Application.hx @@ -1,5 +1,6 @@ package lime.app; +import haxe.Int64; import lime.graphics.RenderContext; import lime.system.System; import lime.ui.Gamepad; @@ -172,6 +173,31 @@ class Application extends Module **/ public function onGamepadButtonUp(gamepad:Gamepad, button:GamepadButton):Void {} + /** + Called when a gamepad axis move event is fired + @param gamepad The current gamepad + @param axis The axis that was moved + @param value The axis value (between 0 and 1) + @param timestamp The timestamp of the event + **/ + public function onGamepadAxisMovePrecise(gamepad:Gamepad, axis:GamepadAxis, value:Float, timestamp:Int64):Void {} + + /** + Called when a gamepad button down event is fired + @param gamepad The current gamepad + @param button The button that was pressed + @param timestamp The timestamp of the event + **/ + public function onGamepadButtonDownPrecise(gamepad:Gamepad, button:GamepadButton, timestamp:Int64):Void {} + + /** + Called when a gamepad button up event is fired + @param gamepad The current gamepad + @param button The button that was released + @param timestamp The timestamp of the event + **/ + public function onGamepadButtonUpPrecise(gamepad:Gamepad, button:GamepadButton, timestamp:Int64):Void {} + /** Called when a gamepad is connected @param gamepad The gamepad that was connected @@ -240,6 +266,22 @@ class Application extends Module **/ public function onKeyUp(keyCode:KeyCode, modifier:KeyModifier):Void {} + /** + Called when a key down event is fired on the primary window + @param keyCode The code of the key that was pressed + @param modifier The modifier of the key that was pressed + @param timestamp The timestamp of the event + **/ + public function onKeyDownPrecise(keyCode:KeyCode, modifier:KeyModifier, timestamp:Int64):Void {} + + /** + Called when a key up event is fired on the primary window + @param keyCode The code of the key that was released + @param modifier The modifier of the key that was released + @param timestamp The timestamp of the event + **/ + public function onKeyUpPrecise(keyCode:KeyCode, modifier:KeyModifier, timestamp:Int64):Void {} + /** Called when the module is exiting **/ @@ -473,6 +515,8 @@ class Application extends Module window.onFullscreen.add(onWindowFullscreen); window.onKeyDown.add(onKeyDown); window.onKeyUp.add(onKeyUp); + window.onKeyDownPrecise.add(onKeyDownPrecise); + window.onKeyUpPrecise.add(onKeyUpPrecise); window.onLeave.add(onWindowLeave); window.onMinimize.add(onWindowMinimize); window.onMouseDown.add(onMouseDown); @@ -564,6 +608,9 @@ class Application extends Module gamepad.onAxisMove.add(onGamepadAxisMove.bind(gamepad)); gamepad.onButtonDown.add(onGamepadButtonDown.bind(gamepad)); gamepad.onButtonUp.add(onGamepadButtonUp.bind(gamepad)); + gamepad.onAxisMovePrecise.add(onGamepadAxisMovePrecise.bind(gamepad)); + gamepad.onButtonDownPrecise.add(onGamepadButtonDownPrecise.bind(gamepad)); + gamepad.onButtonUpPrecise.add(onGamepadButtonUpPrecise.bind(gamepad)); gamepad.onDisconnect.add(onGamepadDisconnect.bind(gamepad)); } diff --git a/src/lime/ui/Gamepad.hx b/src/lime/ui/Gamepad.hx index f2b424fccb..9bccf6b695 100644 --- a/src/lime/ui/Gamepad.hx +++ b/src/lime/ui/Gamepad.hx @@ -22,6 +22,9 @@ class Gamepad public var onAxisMove = new EventFloat->Void>(); public var onButtonDown = new EventVoid>(); public var onButtonUp = new EventVoid>(); + public var onAxisMovePrecise = new EventFloat->haxe.Int64->Void>(); + public var onButtonDownPrecise = new Eventhaxe.Int64->Void>(); + public var onButtonUpPrecise = new Eventhaxe.Int64->Void>(); public var onDisconnect = new EventVoid>(); public function new(id:Int) diff --git a/src/lime/ui/Window.hx b/src/lime/ui/Window.hx index 64810eba3b..b2f2ef6c5f 100644 --- a/src/lime/ui/Window.hx +++ b/src/lime/ui/Window.hx @@ -69,6 +69,8 @@ class Window public var onHide(default, null) = new EventVoid>(); public var onKeyDown(default, null) = new EventKeyModifier->Void>(); public var onKeyUp(default, null) = new EventKeyModifier->Void>(); + public var onKeyDownPrecise(default, null) = new EventKeyModifier->haxe.Int64->Void>(); + public var onKeyUpPrecise(default, null) = new EventKeyModifier->haxe.Int64->Void>(); public var onLeave(default, null) = new EventVoid>(); public var onMaximize(default, null) = new EventVoid>(); public var onMinimize(default, null) = new EventVoid>(); From 4b06c346cc7dcc3a00c9091424f35e98c33dfb11 Mon Sep 17 00:00:00 2001 From: EliteMasterEric Date: Tue, 25 Jun 2024 17:46:59 -0400 Subject: [PATCH 2/2] Add missing onKeyPrecise events dispatcher. --- src/lime/_internal/backend/native/NativeApplication.hx | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/lime/_internal/backend/native/NativeApplication.hx b/src/lime/_internal/backend/native/NativeApplication.hx index ee92dd5ac1..6d41b37026 100644 --- a/src/lime/_internal/backend/native/NativeApplication.hx +++ b/src/lime/_internal/backend/native/NativeApplication.hx @@ -263,14 +263,17 @@ class NativeApplication var int32:Float = keyEventInfo.keyCode; var keyCode:KeyCode = Std.int(int32); var modifier:KeyModifier = keyEventInfo.modifier; + var timestamp = keyEventInfo.timestamp; switch (type) { case KEY_DOWN: window.onKeyDown.dispatch(keyCode, modifier); + window.onKeyDownPrecise.dispatch(keyCode, modifier, timestamp); case KEY_UP: window.onKeyUp.dispatch(keyCode, modifier); + window.onKeyUpPrecise.dispatch(keyCode, modifier, timestamp); } #if (windows || linux)