From 9dcf950f2a6d5c2a8c63e0d6577dd4569d681a4a Mon Sep 17 00:00:00 2001 From: melancholytron Date: Sat, 28 Feb 2026 09:09:35 -0600 Subject: [PATCH] Add in-VR numpad for IP/port input, update default server to 10.0.0.77 Quest system keyboard doesn't work in immersive XR mode, so added a numpad overlay that appears when tapping input fields. Co-Authored-By: Claude Opus 4.6 --- scenes/start_screen.tscn | 2 +- scripts/start_screen.gd | 77 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 78 insertions(+), 1 deletion(-) diff --git a/scenes/start_screen.tscn b/scenes/start_screen.tscn index 8ea5c03..d766077 100644 --- a/scenes/start_screen.tscn +++ b/scenes/start_screen.tscn @@ -71,7 +71,7 @@ text = "Server:" [node name="HostInput" type="LineEdit" parent="UIMesh/SubViewport/PanelContainer/MarginContainer/VBox/ServerRow"] layout_mode = 2 size_flags_horizontal = 3 -text = "10.0.0.64" +text = "10.0.0.77" placeholder_text = "IP address or hostname" virtual_keyboard_enabled = true diff --git a/scripts/start_screen.gd b/scripts/start_screen.gd index 46444e5..68122d0 100644 --- a/scripts/start_screen.gd +++ b/scripts/start_screen.gd @@ -2,6 +2,7 @@ extends Node3D ## VR start screen UI panel. ## Renders a 2D UI in a SubViewport on a QuadMesh in VR space. ## Allows user to enter server URL/port, connect, and launch AR mode. +## Includes an in-VR numpad since the Quest system keyboard doesn't work in XR mode. signal connect_requested(host: String, port: int) signal launch_ar_requested() @@ -13,8 +14,11 @@ signal launch_ar_requested() @onready var connect_button: Button = $UIMesh/SubViewport/PanelContainer/MarginContainer/VBox/ConnectButton @onready var status_label: Label = $UIMesh/SubViewport/PanelContainer/MarginContainer/VBox/StatusLabel @onready var launch_ar_button: Button = $UIMesh/SubViewport/PanelContainer/MarginContainer/VBox/LaunchARButton +@onready var vbox: VBoxContainer = $UIMesh/SubViewport/PanelContainer/MarginContainer/VBox var _is_connected: bool = false +var _numpad_container: VBoxContainer +var _active_input: LineEdit # Which input field the numpad types into func _ready() -> void: @@ -22,6 +26,13 @@ func _ready() -> void: connect_button.pressed.connect(_on_connect_pressed) launch_ar_button.pressed.connect(_on_launch_ar_pressed) + # Show numpad when input fields are focused + host_input.focus_entered.connect(_on_input_focused.bind(host_input)) + port_input.focus_entered.connect(_on_input_focused.bind(port_input)) + + # Build the in-VR numpad + _build_numpad() + # Set up the mesh material to display the SubViewport var material := StandardMaterial3D.new() material.shading_mode = BaseMaterial3D.SHADING_MODE_UNSHADED @@ -32,7 +43,73 @@ func _ready() -> void: print("[StartScreen] Ready") +func _build_numpad() -> void: + _numpad_container = VBoxContainer.new() + _numpad_container.add_theme_constant_override("separation", 6) + _numpad_container.visible = false + + # Button rows: [1,2,3] [4,5,6] [7,8,9] [.,0,<-] [Clear, Done] + var rows := [ + ["1", "2", "3"], + ["4", "5", "6"], + ["7", "8", "9"], + [".", "0", "<"], + ["Clear", "Done"], + ] + + for row in rows: + var hbox := HBoxContainer.new() + hbox.add_theme_constant_override("separation", 6) + hbox.alignment = BoxContainer.ALIGNMENT_CENTER + for key in row: + var btn := Button.new() + btn.text = key + btn.custom_minimum_size = Vector2(80, 55) + btn.size_flags_horizontal = Control.SIZE_EXPAND_FILL + if key == "Clear" or key == "Done": + btn.custom_minimum_size = Vector2(130, 55) + btn.add_theme_font_size_override("font_size", 26) + btn.pressed.connect(_on_numpad_key.bind(key)) + hbox.add_child(btn) + _numpad_container.add_child(hbox) + + # Insert numpad after the PortRow + var port_row_idx := port_input.get_parent().get_index() + vbox.add_child(_numpad_container) + vbox.move_child(_numpad_container, port_row_idx + 1) + + +func _on_input_focused(input: LineEdit) -> void: + _active_input = input + _numpad_container.visible = true + + +func _on_numpad_key(key: String) -> void: + if _active_input == null: + return + + if key == "<": + # Backspace + var t := _active_input.text + if t.length() > 0: + _active_input.text = t.substr(0, t.length() - 1) + _active_input.caret_column = _active_input.text.length() + elif key == "Clear": + _active_input.text = "" + _active_input.caret_column = 0 + elif key == "Done": + _numpad_container.visible = false + _active_input.release_focus() + _active_input = null + else: + _active_input.text += key + _active_input.caret_column = _active_input.text.length() + + func _on_connect_pressed() -> void: + # Hide numpad if open + _numpad_container.visible = false + var host := host_input.text.strip_edges() if host.is_empty(): update_status("Please enter a server address")