Fix controller text entry without native keyboards

This commit is contained in:
Alexander Sellite 2026-08-15 09:53:39 -04:00
parent 57df54d82d
commit abedd64782
5 changed files with 79 additions and 11 deletions

View file

@ -199,6 +199,7 @@ var _virtual_mouse_trigger_rest_by_device: Dictionary[int, float] = {}
var _shared_trigger_rest_by_device: Dictionary[int, float] = {}
var _controller_mapping_manager: ControllerMappingManagerType
var _settings_manager: PlayerSettingsManagerType
var _controller_text_entry_request: Callable
func _ready() -> void:
@ -252,6 +253,10 @@ func _ready() -> void:
Input.joy_connection_changed.connect(_on_controller_connection_changed)
func set_controller_text_entry_request(request: Callable) -> void:
_controller_text_entry_request = request
func setup(
player: PlayerType,
inventory: FishInventoryType,
@ -600,6 +605,11 @@ func _handle_controller_chat_controls(event: InputEvent) -> bool:
_chat_ui.refocus_gameplay()
return true
if accept_pressed:
if (
_controller_text_entry_request.is_valid()
and bool(_controller_text_entry_request.call())
):
return true
return _chat_ui.request_virtual_keyboard()
return false

View file

@ -50,20 +50,30 @@ func _ready() -> void:
func set_enabled(enabled: bool) -> void:
_enabled = enabled
if not _enabled and visible:
if not _is_available_for_controller() and visible:
_close_keyboard(false)
func is_enabled() -> bool:
return _enabled
return _is_available_for_controller()
func is_open() -> bool:
return visible
func request_for_focused_control() -> bool:
if not _is_available_for_controller() or visible:
return false
var focus_owner: Control = get_viewport().gui_get_focus_owner()
if not _can_edit(focus_owner):
return false
_open_for(focus_owner)
return true
func _input(event: InputEvent) -> void:
if not _enabled:
if not _is_available_for_controller():
return
if visible:
var joy_motion := event as InputEventJoypadMotion
@ -98,12 +108,27 @@ func _input(event: InputEvent) -> void:
)
):
return
var focus_owner: Control = get_viewport().gui_get_focus_owner()
if _can_edit(focus_owner):
_open_for(focus_owner)
if request_for_focused_control():
get_viewport().set_input_as_handled()
func _is_available_for_controller() -> bool:
return should_enable_for_controller(
_enabled,
DisplayServer.has_feature(DisplayServer.FEATURE_VIRTUAL_KEYBOARD),
)
static func should_enable_for_controller(
preference_enabled: bool,
native_virtual_keyboard_available: bool,
) -> bool:
# A controller user must always have one viable text-entry path. Android
# and any future display backend with native support can keep using the
# platform keyboard unless the in-game keyboard is explicitly requested.
return preference_enabled or not native_virtual_keyboard_available
func _can_edit(control: Control) -> bool:
if control is LineEdit:
return (control as LineEdit).editable

View file

@ -19,6 +19,7 @@ signal effective_pixel_size_changed(
)
@onready var _ui_viewport: SubViewport = $UIViewport
@onready var _game_ui: GameUI = $UIViewport/GameUI
@onready var _ui_root: Control = $UIViewport/GameUI/UIRoot
@onready var _canonical_stage: Control = (
$UIViewport/GameUI/UIRoot/CanonicalStage
@ -42,6 +43,9 @@ var _on_screen_keyboard: OnScreenKeyboardType
func _ready() -> void:
_on_screen_keyboard = OnScreenKeyboardType.new()
_ui_root.add_child(_on_screen_keyboard)
_game_ui.set_controller_text_entry_request(
Callable(_on_screen_keyboard, "request_for_focused_control")
)
var controller_focus_recovery := ControllerFocusRecoveryType.new()
_ui_root.add_child(controller_focus_recovery)
var controller_focus_presentation := ControllerFocusPresentationType.new()