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 signal on_scroll 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, ON_SCROLL, } class PointerInputData: var target: PointerInputSensor var event: InputEvent 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 scroll := 0.0 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_exited", 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 pointer.event = event pointer.action = PointerInputAction.UNDEFINED pointer.velocity = Vector2.ZERO pointer.relative_position = Vector2.ZERO pointer.scroll = 0.0 pointer.current_position = get_global_mouse_position() if event is InputEventScreenTouch && (pointer.is_pressed == false || pointer.index == event.index): var touch := event as InputEventScreenTouch pointer.is_pressed = event.pressed if pointer.is_pressed: pointer.index = touch.index pointer.initial_position = pointer.current_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.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) if event is InputEventMouseButton && event.is_pressed(): if event.button_index == BUTTON_WHEEL_UP || event.button_index == BUTTON_WHEEL_DOWN: pointer.scroll = -1.0 if event.button_index == BUTTON_WHEEL_UP else 1.0 pointer.action = PointerInputAction.ON_SCROLL emit_signal("on_scroll", pointer)