diff --git a/core/systems/input/input_manager.gd b/core/systems/input/input_manager.gd index a77d8762..174b1405 100644 --- a/core/systems/input/input_manager.gd +++ b/core/systems/input/input_manager.gd @@ -36,6 +36,9 @@ var popup_state := preload("res://assets/state/states/popup.tres") as State ## Map of pressed actions to prevent double inputs var actions_pressed := {} +## Number of currently pressed touches +var current_touches := 0 + ## Will show logger events with the prefix InputManager var logger := Log.get_logger("InputManager", Log.LEVEL.INFO) @@ -53,6 +56,11 @@ func _init_inputplumber() -> void: _watch_dbus_device(device) +## Returns true if the given event is an InputPlumber event +static func is_inputplumber_event(event: InputEvent) -> bool: + return event.has_meta("dbus_path") + + ## Queue a release event for the given action func action_release(dbus_path: String, action: String, strength: float = 1.0) -> void: Input.action_release(action) @@ -76,10 +84,26 @@ func _send_input(dbus_path: String, action: String, pressed: bool, strength: flo Input.parse_input_event(input_action) -## Process all unhandled input, possibly preventing the input from propagating further. -## https://docs.godotengine.org/en/latest/tutorials/inputs/inputevent.html#how-does-it-work +## Process all window input. Window input is processed before all _input and +## _gui_input node methods. +## @tutorial https://docs.godotengine.org/en/latest/tutorials/inputs/inputevent.html#how-does-it-work func _input(event: InputEvent) -> void: logger.debug("Got input event to handle: " + str(event)) + + # Keep track of the current number of touch inputs + if event is InputEventScreenTouch: + if event.is_pressed(): + self.current_touches += 1 + else: + self.current_touches -= 1 + + # Don't process Godot events if InputPlumber is running + if input_plumber.is_running() and not is_inputplumber_event(event): + if event is InputEventJoypadButton or event is InputEventJoypadMotion: + logger.debug("Skipping Godot event while InputPlumber is running:", event) + get_viewport().set_input_as_handled() + return + var dbus_path := event.get_meta("dbus_path", "") as String # Consume double inputs for controllers with DPads that have TRIGGER_HAPPY events @@ -275,18 +299,18 @@ func _audio_input(event: InputEvent) -> void: func _watch_dbus_device(device: CompositeDevice) -> void: - for target in device.dbus_devices: - if target.input_event.is_connected(_on_dbus_input_event.bind(device.dbus_path)): - continue - logger.debug("Adding watch for " + device.name + " " + target.dbus_path) - logger.debug(str(target.get_instance_id())) - logger.debug(str(target.get_rid())) - target.input_event.connect(_on_dbus_input_event.bind(device.dbus_path)) + for target in device.dbus_devices: + if target.input_event.is_connected(_on_dbus_input_event.bind(device.dbus_path)): + continue + logger.debug("Adding watch for " + device.name + " " + target.dbus_path) + logger.debug(str(target.get_instance_id())) + logger.debug(str(target.get_rid())) + target.input_event.connect(_on_dbus_input_event.bind(device.dbus_path)) func _on_dbus_input_event(event: String, value: float, dbus_path: String) -> void: var pressed := value == 1.0 - logger.debug("Handling dbus input event from" + dbus_path + ": " + event + " pressed: " + str(pressed)) + logger.debug("Handling dbus input event from '" + dbus_path + "': " + event + " pressed: " + str(pressed)) var action := event match event: diff --git a/core/systems/input/overlay_mode_input_manager.gd b/core/systems/input/overlay_mode_input_manager.gd index 4bdb6159..a31b4495 100644 --- a/core/systems/input/overlay_mode_input_manager.gd +++ b/core/systems/input/overlay_mode_input_manager.gd @@ -75,7 +75,19 @@ func _send_input(dbus_path: String, action: String, pressed: bool, strength: flo ## https://docs.godotengine.org/en/latest/tutorials/inputs/inputevent.html#how-does-it-work func _input(event: InputEvent) -> void: logger.debug("Got input event to handle: " + str(event)) + # Don't process Godot events if InputPlumber is running + if input_plumber.is_running() and not InputManager.is_inputplumber_event(event): + if event is InputEventJoypadButton or event is InputEventJoypadMotion: + logger.debug("Skipping Godot event while InputPlumber is running:", event) + get_viewport().set_input_as_handled() + return + var dbus_path := event.get_meta("dbus_path", "") as String + + # Don't process Godot events if InputPlumber is running + if input_plumber.is_running() and not InputManager.is_inputplumber_event(event): + logger.trace("Skipping Godot event while InputPlumber is running:", event) + return # Consume double inputs for controllers with DPads that have TRIGGER_HAPPY events const possible_doubles := ["ui_left", "ui_right", "ui_up", "ui_down"] diff --git a/core/systems/launcher/interactive_process.gd b/core/systems/launcher/interactive_process.gd index 58f47ef6..0071939d 100644 --- a/core/systems/launcher/interactive_process.gd +++ b/core/systems/launcher/interactive_process.gd @@ -1,3 +1,4 @@ +@icon("res://assets/editor-icons/devicon-plain--bash.svg") extends Resource class_name InteractiveProcess diff --git a/core/ui/card_ui/card_ui.tscn b/core/ui/card_ui/card_ui.tscn index deef5555..2dbe0ded 100644 --- a/core/ui/card_ui/card_ui.tscn +++ b/core/ui/card_ui/card_ui.tscn @@ -91,8 +91,6 @@ grow_horizontal = 2 grow_vertical = 2 script = ExtResource("1_f8851") -[node name="InputManager" parent="." instance=ExtResource("1_34t85")] - [node name="InputIconProcessor" type="Node" parent="."] script = ExtResource("3_y116l") @@ -231,7 +229,6 @@ size_flags_vertical = 8 layout_mode = 2 [node name="ContextBar" parent="MenuContent/BottomMargin/VBoxContainer" instance=ExtResource("12_bstc8")] -visible = false layout_mode = 2 [node name="MenuContainer" type="MarginContainer" parent="MenuContent"] @@ -363,4 +360,6 @@ grow_vertical = 2 stream = ExtResource("21_s3peg") autoplay = true +[node name="InputManager" parent="." instance=ExtResource("1_34t85")] + [editable path="AlwaysVisibleContent/OnScreenKeyboard"] diff --git a/core/ui/card_ui/home/cardui_home.gd b/core/ui/card_ui/home/cardui_home.gd index 41ba2809..1e4b668a 100644 --- a/core/ui/card_ui/home/cardui_home.gd +++ b/core/ui/card_ui/home/cardui_home.gd @@ -201,6 +201,15 @@ func _on_card_focused(item: LibraryItem, card: Control) -> void: player.play("fade_in") banner.texture = await BoxArtManager.get_boxart_or_placeholder(item, BoxArtProvider.LAYOUT.BANNER) library_banner.visible = false + + # Don't scroll to the card if mouse or touch is being used + var input_manager := get_tree().get_first_node_in_group("InputManager") + if input_manager: + if (input_manager as InputManager).current_touches > 0: + return + if Input.is_mouse_button_pressed(MOUSE_BUTTON_LEFT): + return + _scroll_to(card) diff --git a/core/ui/card_ui/library/library_menu.gd b/core/ui/card_ui/library/library_menu.gd index b032739c..03b55342 100644 --- a/core/ui/card_ui/library/library_menu.gd +++ b/core/ui/card_ui/library/library_menu.gd @@ -244,8 +244,17 @@ func _on_uninstalled(req: InstallManager.Request) -> void: # Called when a library card is focused func _on_focus_updated(card: Control, tab: int) -> void: + # Update the currently selected card _current_selection[tab] = card + # Don't scroll to the card if mouse or touch is being used + var input_manager := get_tree().get_first_node_in_group("InputManager") + if input_manager: + if (input_manager as InputManager).current_touches > 0: + return + if Input.is_mouse_button_pressed(MOUSE_BUTTON_LEFT): + return + # Get the scroll container for this card var scroll_container := tab_container.get_child(tab) as ScrollContainer if not scroll_container: diff --git a/core/ui/card_ui_overlay_mode/card_ui_overlay_mode.tscn b/core/ui/card_ui_overlay_mode/card_ui_overlay_mode.tscn index 775233f1..cac21de9 100644 --- a/core/ui/card_ui_overlay_mode/card_ui_overlay_mode.tscn +++ b/core/ui/card_ui_overlay_mode/card_ui_overlay_mode.tscn @@ -26,8 +26,6 @@ grow_vertical = 2 theme = ExtResource("1_0qmlq") script = ExtResource("2_3ptao") -[node name="InputManager" parent="." instance=ExtResource("3_klhmb")] - [node name="InputIconProcessor" type="Node" parent="."] script = ExtResource("4_6rltg") @@ -92,3 +90,5 @@ anchor_right = 0.5 anchor_bottom = 0.5 grow_horizontal = 2 grow_vertical = 2 + +[node name="InputManager" parent="." instance=ExtResource("3_klhmb")] diff --git a/core/ui/components/card.gd b/core/ui/components/card.gd index dd5f27eb..fef2cc62 100644 --- a/core/ui/components/card.gd +++ b/core/ui/components/card.gd @@ -35,12 +35,14 @@ signal unhighlighted progress.value = v var library_item: LibraryItem +var tapped_count := 0 var logger := Log.get_logger("GameCard") @onready var texture := $%TextureRect @onready var name_container := $%NameMargin @onready var name_label := $%NameLabel @onready var progress := $%ProgressBar as ProgressBar +@onready var tap_timer := $%TapTimer as Timer # Called when the node enters the scene tree for the first time. @@ -53,7 +55,12 @@ func _ready() -> void: focus_exited.connect(_on_unfocus) texture.mouse_entered.connect(_on_focus) texture.mouse_exited.connect(_on_unfocus) - + + # Setup a timer callback to clear number of taps on the card + var on_timeout := func(): + tapped_count = 0 + tap_timer.timeout.connect(on_timeout) + var parent := get_parent() if parent and parent is Container: parent.queue_sort() @@ -101,6 +108,14 @@ func _gui_input(event: InputEvent) -> void: if event is InputEventMouseButton: if event.is_pressed() and event.double_click: button_up.emit() + if event is InputEventScreenTouch: + if event.is_pressed(): + tapped_count += 1 + if tapped_count > 1: + tapped_count = 0 + button_up.emit() + else: + tap_timer.start() if event.is_action("ui_accept"): if event.is_pressed(): button_down.emit() diff --git a/core/ui/components/card.tscn b/core/ui/components/card.tscn index 1117e146..c99cd42e 100644 --- a/core/ui/components/card.tscn +++ b/core/ui/components/card.tscn @@ -65,6 +65,7 @@ clip_children = 1 layout_mode = 0 offset_right = 40.0 offset_bottom = 40.0 +mouse_filter = 1 theme_override_styles/panel = SubResource("StyleBoxFlat_ygsnb") [node name="TextureRect" type="TextureRect" parent="PanelContainer"] @@ -136,3 +137,8 @@ show_behind_parent = true layout_mode = 2 mouse_filter = 2 theme_override_styles/panel = SubResource("StyleBoxFlat_st1t5") + +[node name="TapTimer" type="Timer" parent="."] +unique_name_in_owner = true +wait_time = 0.5 +one_shot = true