extends Control class_name PointerInputSensor # All on_ACTION signals have a single argument of type PointerInputData. signal on_press signal on_release #signal on_release_outside signal on_click signal on_enter signal on_exit #signal on_exit_app_window signal on_begin_drag signal on_drag signal on_end_drag enum PointerInputAction { UNDEFINED, ON_PRESS, ON_RELEASE, # ON_RELEASE_OUTSIDE, ON_CLICK, ON_ENTER, ON_EXIT, # ON_EXIT_APP_WINDOW, ON_BEGIN_DRAG, ON_DRAG, ON_END_DRAG, } class PointerInputData: var target: PointerInputSensor var index := -1 var initial_position := Vector2.ZERO var current_position := Vector2.ZERO var relative_position := Vector2.ZERO var velocity := Vector2.ZERO var was_dragged := false var is_pressed := false var action: int = PointerInputAction.UNDEFINED export var drag_threshold_cm: float = 0.250 var pointer: PointerInputData var screen_dpcm: float func _ready(): screen_dpcm = float(OS.get_screen_dpi()) / 2.54 pointer = PointerInputData.new() pointer.target = self connect("mouse_entered", self, "_on_enter_exit", [true]) connect("mouse_entered", self, "_on_enter_exit", [false]) func _on_enter_exit(is_inside: bool): pointer.action = PointerInputAction.ON_ENTER if is_inside else PointerInputAction.ON_EXIT emit_signal("on_enter" if is_inside else "on_exit", pointer) func _gui_input(event: InputEvent): # @DAM A bug on GODOT-3.X makes events from non-mouse-emulated pointers (index > 0) unreliable. if event is InputEventScreenTouch || event is InputEventScreenDrag: if event.index != 0: return if event is InputEventScreenTouch && (pointer.is_pressed == false || pointer.index == event.index): var touch := event as InputEventScreenTouch pointer.is_pressed = event.pressed pointer.current_position = get_global_mouse_position() if pointer.is_pressed: pointer.index = touch.index pointer.initial_position = get_global_mouse_position() pointer.action = PointerInputAction.ON_PRESS emit_signal("on_press", pointer) else: pointer.action = PointerInputAction.ON_RELEASE emit_signal("on_release", pointer) if pointer.was_dragged == false: pointer.action = PointerInputAction.ON_CLICK emit_signal("on_click", pointer) else: pointer.action = PointerInputAction.ON_END_DRAG emit_signal("on_end_drag", pointer) pointer.index = -1 pointer.was_dragged = false if event is InputEventScreenDrag && event.index == pointer.index: var drag := event as InputEventScreenDrag pointer.current_position = get_global_mouse_position() pointer.velocity = drag.speed pointer.relative_position = drag.relative if pointer.was_dragged == false && pointer.current_position.distance_to(pointer.initial_position) > drag_threshold_cm * screen_dpcm: pointer.was_dragged = true pointer.action = PointerInputAction.ON_BEGIN_DRAG emit_signal("on_begin_drag", pointer) pointer.action = PointerInputAction.ON_DRAG emit_signal("on_drag", pointer)