Skip to content

Commit

Permalink
add touch screen drag&drop support
Browse files Browse the repository at this point in the history
  • Loading branch information
MikeSchulze committed Aug 16, 2024
1 parent 2a06604 commit 7c52644
Show file tree
Hide file tree
Showing 8 changed files with 243 additions and 50 deletions.
74 changes: 70 additions & 4 deletions addons/gdUnit4/src/GdUnitSceneRunner.gd
Original file line number Diff line number Diff line change
Expand Up @@ -131,31 +131,97 @@ func simulate_mouse_button_release(buttonIndex :MouseButton) -> GdUnitSceneRunne
return self



## Simulates a screen touch is pressed.[br]
## [member index] : The touch index in the case of a multi-touch event. One index = one finger.
## [member index] : The touch index in the case of a multi-touch event. One index = one finger.[br]
## [member double_tap] : If true, the touch's state is a double tab.
@warning_ignore("unused_parameter")
func simulate_screen_touch_pressed(index :int, double_tap := false) -> GdUnitSceneRunner:
return self


## Simulates a screen touch is press.[br]
## [member index] : The touch index in the case of a multi-touch event. One index = one finger.
## [member index] : The touch index in the case of a multi-touch event. One index = one finger.[br]
## [member double_tap] : If true, the touch's state is a double tab.
@warning_ignore("unused_parameter")
func simulate_screen_touch_press(index :int, double_tap := false) -> GdUnitSceneRunner:
return self


## Simulates a screen touch is released.[br]
## [member index] : The touch index in the case of a multi-touch event. One index = one finger.
## [member index] : The touch index in the case of a multi-touch event. One index = one finger.[br]
## [member double_tap] : If true, the touch's state is a double tab.
@warning_ignore("unused_parameter")
func simulate_screen_touch_release(index :int, double_tap := false) -> GdUnitSceneRunner:
return self


## Starts the simulate of drag&drop at given position.[br]
## [member index] : The touch index in the case of a multi-touch event. One index = one finger.[br]
## [member index] : The starting position to drag
@warning_ignore("unused_parameter")
func simulate_screen_touch_drag_begin(index :int, position :Vector2) -> GdUnitSceneRunner:
return self


## Simulates a touch screen drag&drop to the relative coordinates (offset).[br]
## [color=yellow]You must use [b]await[/b] to wait until the simulated drag&drop is complete.[/color][br]
## [br]
## [member relative] : The relative position, indicating the drag&drop position offset.[br]
## [member time] : The time to move to the relative position in seconds (default is 1 second).[br]
## [member trans_type] : Sets the type of transition used (default is TRANS_LINEAR).[br]
## [codeblock]
## func test_touch_drag_drop():
## var runner = scene_runner("res://scenes/simple_scene.tscn")
## # start drag at position 50,50
## runner.simulate_screen_touch_drag_begin(1, Vector2(50, 50))
## # and drop it at final at 150,50 relative (50,50 + 100,0)
## await runner.simulate_screen_touch_drag_relative(1, Vector2(100,0))
## [/codeblock]
@warning_ignore("unused_parameter")
func simulate_screen_touch_drag_relative(index :int, relative: Vector2, time: float = 1.0, trans_type: Tween.TransitionType = Tween.TRANS_LINEAR) -> GdUnitSceneRunner:
await Engine.get_main_loop().process_frame
return self


## Simulates a touch screen drop to the absolute coordinates (offset).[br]
## [color=yellow]You must use [b]await[/b] to wait until the simulated drop is complete.[/color][br]
## [br]
## [member position] : The final position, indicating the drop position.[br]
## [member time] : The time to move to the final position in seconds (default is 1 second).[br]
## [member trans_type] : Sets the type of transition used (default is TRANS_LINEAR).[br]
## [codeblock]
## func test_touch_drag_drop():
## var runner = scene_runner("res://scenes/simple_scene.tscn")
## # start drag at position 50,50
## runner.simulate_screen_touch_drag_begin(1, Vector2(50, 50))
## # and drop it at 100,50
## await runner.simulate_screen_touch_drag_absolute(1, Vector2(100,50))
## [/codeblock]
@warning_ignore("unused_parameter")
func simulate_screen_touch_drag_absolute(index :int, position: Vector2, time: float = 1.0, trans_type: Tween.TransitionType = Tween.TRANS_LINEAR) -> GdUnitSceneRunner:
await Engine.get_main_loop().process_frame
return self


## Simulates a touch screen drop&drop to the absolute coordinates (offset).[br]
## [color=yellow]You must use [b]await[/b] to wait until the simulated drop is complete.[/color][br]
## [br]
## [member position] : The drag start position, indicating the drag position.[br]
## [member drop_position] : The drop position, indicating the drop position.[br]
## [member time] : The time to move to the final position in seconds (default is 1 second).[br]
## [member trans_type] : Sets the type of transition used (default is TRANS_LINEAR).[br]
## [codeblock]
## func test_touch_drag_drop():
## var runner = scene_runner("res://scenes/simple_scene.tscn")
## # start drag at position 50,50 and drop it at 100,50
## await runner.simulate_screen_touch_drag_drop(1, Vector2(50, 50), Vector2(100,50))
## [/codeblock]
@warning_ignore("unused_parameter")
func simulate_screen_touch_drag_drop(index :int, position: Vector2, drop_position: Vector2, time: float = 1.0, trans_type: Tween.TransitionType = Tween.TRANS_LINEAR) -> GdUnitSceneRunner:
await Engine.get_main_loop().process_frame
return self


## Sets how fast or slow the scene simulation is processed (clock ticks versus the real).[br]
## It defaults to 1.0. A value of 2.0 means the game moves twice as fast as real life,
## whilst a value of 0.5 means the game moves at half the regular speed.
Expand Down
83 changes: 76 additions & 7 deletions addons/gdUnit4/src/core/GdUnitSceneRunnerImpl.gd
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ var _mouse_button_on_press := []
var _key_on_press := []
var _action_on_press := []
var _curent_mouse_position :Vector2
var _current_touch_drag_position :Vector2

# time factor settings
var _time_factor := 1.0
Expand Down Expand Up @@ -250,27 +251,95 @@ func simulate_screen_touch_pressed(index :int, double_tap := false) -> GdUnitSce


func simulate_screen_touch_press(index :int, double_tap := false) -> GdUnitSceneRunner:
# we need to simulate in addition to the touch the mouse events
simulate_mouse_button_press(MOUSE_BUTTON_LEFT)
# push touch press event at position
var event := InputEventScreenTouch.new()
event.window_id = scene().get_viewport().get_window_id()
event.index = index
event.position = get_mouse_position()
event.double_tap = double_tap
event.pressed = true
event.window_id = scene().get_viewport().get_window_id()
if ProjectSettings.get_setting("input_devices/pointing/emulate_touch_from_mouse") == true:
_mouse_button_on_press.append(index)
return _handle_input_event(event)
_current_scene.get_viewport().push_input(event)
return self


func simulate_screen_touch_release(index :int, double_tap := false) -> GdUnitSceneRunner:
# we need to simulate in addition to the touch the mouse events
simulate_mouse_button_release(MOUSE_BUTTON_LEFT)
# push touch release event at position
var event := InputEventScreenTouch.new()
event.window_id = scene().get_viewport().get_window_id()
event.index = index
event.position = get_mouse_position()
event.pressed = false
event.double_tap = _last_input_event.double_tap if _last_input_event is InputEventScreenTouch else double_tap
_current_scene.get_viewport().push_input(event)
return self


func simulate_screen_touch_drag_begin(index :int, position :Vector2) -> GdUnitSceneRunner:
# we need to simulate in addition to the touch the mouse events
set_mouse_pos(position)
simulate_mouse_button_press(MOUSE_BUTTON_LEFT)

# start drag by touch it at position
var event := InputEventScreenTouch.new()
event.window_id = scene().get_viewport().get_window_id()
if ProjectSettings.get_setting("input_devices/pointing/emulate_touch_from_mouse") == true:
_mouse_button_on_press.erase(index)
return _handle_input_event(event)
event.index = index
event.position = position
event.pressed = true
_current_touch_drag_position = position
_current_scene.get_viewport().push_input(event)
return self


func simulate_screen_touch_drag_relative(index :int, relative: Vector2, time: float = 1.0, trans_type: Tween.TransitionType = Tween.TRANS_LINEAR) -> GdUnitSceneRunner:
return await _do_touch_drag_at(index, _current_touch_drag_position + relative, time, trans_type)


func simulate_screen_touch_drag_absolute(index :int, position: Vector2, time: float = 1.0, trans_type: Tween.TransitionType = Tween.TRANS_LINEAR) -> GdUnitSceneRunner:
return await _do_touch_drag_at(index, position, time, trans_type)


func simulate_screen_touch_drag_drop(index :int, position: Vector2, drop_position: Vector2, time: float = 1.0, trans_type: Tween.TransitionType = Tween.TRANS_LINEAR) -> GdUnitSceneRunner:
simulate_screen_touch_drag_begin(index, position)
return await _do_touch_drag_at(index, drop_position, time, trans_type)


func _do_touch_drag_at(index :int, drop_position: Vector2, time: float, trans_type: Tween.TransitionType) -> GdUnitSceneRunner:
# start draging
var event := InputEventScreenDrag.new()
event.window_id = scene().get_viewport().get_window_id()
event.index = index
event.position = _current_touch_drag_position
event.pressure = 1.0

var tween := _scene_tree().create_tween()
tween.tween_property(self, "_current_touch_drag_position", drop_position, time).set_trans(trans_type)
tween.play()

while not _current_touch_drag_position.is_equal_approx(drop_position):
# we need to simulate in addition to the drag the mouse move events
simulate_mouse_move(event.position)
# send touche drag event to new position
event.relative = _current_touch_drag_position - event.position
event.velocity = event.relative / _scene_tree().root.get_process_delta_time()
event.position = _current_touch_drag_position
_current_scene.get_viewport().push_input(event)
await _scene_tree().process_frame

# finaly drop it
simulate_mouse_move(drop_position)
simulate_mouse_button_release(MOUSE_BUTTON_LEFT)
var touch_drop_event := InputEventScreenTouch.new()
touch_drop_event.window_id = event.window_id
touch_drop_event.index = event.index
touch_drop_event.position = drop_position
touch_drop_event.pressed = false
_current_scene.get_viewport().push_input(touch_drop_event)
await _scene_tree().process_frame
return self


func set_time_factor(time_factor := 1.0) -> GdUnitSceneRunner:
Expand Down
34 changes: 0 additions & 34 deletions addons/gdUnit4/test/core/GdUnitSceneRunnerInputEventTest.gd
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,6 @@ func before_test() -> void:
reset(_scene_spy)


func after_test() -> void:
set_mouse_as_touch_device(false)


# asserts to action strings
func assert_initial_action_state() -> void:
for action in InputMap.get_actions():
Expand Down Expand Up @@ -568,9 +564,6 @@ func test_simulate_mouse_button_press_and_release() -> void:


func test_simulate_screen_touch_press() -> void:
# we need to simmulate the mouse as a touch device
set_mouse_as_touch_device(true)

_runner.set_mouse_pos(Vector2(683, 339))
# simulate one finger is touching the screen
_runner.simulate_screen_touch_press(1)
Expand All @@ -588,9 +581,6 @@ func test_simulate_screen_touch_press() -> void:


func test_simulate_screen_touch_press_double_click() -> void:
# we need to simmulate the mouse as a touch device
set_mouse_as_touch_device(true)

_runner.set_mouse_pos(Vector2(683, 339))
# simulate that two fingers have touched the touch screen as a double click
_runner.simulate_screen_touch_press(2, true)
Expand All @@ -608,9 +598,6 @@ func test_simulate_screen_touch_press_double_click() -> void:


func test_simulate_screen_touch_pressed() -> void:
# we need to simmulate the mouse as a touch device
set_mouse_as_touch_device(true)

_runner.set_mouse_pos(Vector2(683, 339))
# simulate that a finger has touched the screen
_runner.simulate_screen_touch_pressed(1)
Expand All @@ -630,31 +617,17 @@ func test_simulate_screen_touch_pressed() -> void:


func test_simulate_screen_touch_pressed_double_click() -> void:
# we need to simmulate the mouse as a touch device
set_mouse_as_touch_device(true)

_runner.set_mouse_pos(Vector2(683, 339))
# simulate that two fingers have touched the touch screen as a double click
_runner.simulate_screen_touch_pressed(2, true)
await await_idle_frame()

# verify the InputEventScreenTouch is emitted
var event := InputEventScreenTouch.new()
event.position = Vector2(683, 339)
event.pressed = true
event.index = 2
event.double_tap = true
verify(_scene_spy, 1)._input(event)
event.pressed = false
verify(_scene_spy, 1)._input(event)
verify(_scene_spy, 1)._on_touch_1_pressed()
verify(_scene_spy, 1)._on_touch_1_released()


func test_simulate_screen_touch_release() -> void:
# we need to simmulate the mouse as a touch device
set_mouse_as_touch_device(true)

_runner.set_mouse_pos(Vector2(683, 339))
# simulate that the finger no longer touches the screen
_runner.simulate_screen_touch_release(1)
Expand All @@ -671,9 +644,6 @@ func test_simulate_screen_touch_release() -> void:


func test_simulate_screen_touch_release_double_click() -> void:
# we need to simmulate the mouse as a touch device
set_mouse_as_touch_device(true)

_runner.set_mouse_pos(Vector2(683, 339))
# simulate that two fingers no longer touches the screen as a double click
_runner.simulate_screen_touch_release(2, true)
Expand All @@ -687,7 +657,3 @@ func test_simulate_screen_touch_release_double_click() -> void:
event.double_tap = true
verify(_scene_spy, 1)._input(event)
verify(_scene_spy, 0)._on_touch_1_pressed()


func set_mouse_as_touch_device(enabled := false) -> void:
ProjectSettings.set_setting("input_devices/pointing/emulate_touch_from_mouse", enabled)
Loading

0 comments on commit 7c52644

Please sign in to comment.