# input_key_test —— ClientVS22 game.py 键盘映射的离线回归。 # 覆盖 macOS Command / Windows Ctrl 表情键、快捷栏分页、按住攻击、 # 相机按住/释放、名称显示和几个窗口/坐骑入口。 extends SceneTree const GameScene = preload("res://game_scene.gd") const UiManager = preload("res://ui/ui_manager.gd") class FakeClient extends Node: var emotes := [] var commands := [] var used_items := [] var main := 1000 func send_emoticon(index: int) -> bool: emotes.append(index); return true func say(_type: int, text: String) -> bool: commands.append(text); return true func get_main_vid() -> int: return main func get_entity(_vid: int) -> Dictionary: return {"mount_vnum": 123} func get_inventory() -> Array: return [{"cell": 7, "vnum": 71114}] func use_item(_window: int, cell: int) -> bool: used_items.append(cell); return true class FakeQuickbar extends Node: var activated := [] var pages := [] func activate(slot: int) -> void: activated.append(slot) func set_page(page: int) -> void: pages.append(page) class FakeNetPlay extends Node: var attack_states := [] func set_attack_key(down: bool) -> void: attack_states.append(down) class FakeCamera extends Camera3D: var orbit := [] var zoom := [] var pitch := [] func set_key_orbit(direction: int) -> void: orbit.append(direction) func set_key_zoom(direction: int) -> void: zoom.append(direction) func set_key_pitch(direction: int) -> void: pitch.append(direction) class FakeWorld extends Node: var names := [] func set_names_visible(visible: bool) -> void: names.append(visible) class FakeChat extends Node: var toggles := 0 func is_typing() -> bool: return false func focus_input() -> void: pass func toggle_log() -> void: toggles += 1 class FakeStatus extends Node: var states := [] func open(state: String) -> void: states.append(state) class FakeToggle extends Node: var toggles := 0 var button_toggles := 0 func toggle() -> void: toggles += 1 func toggle_help() -> void: toggles += 1 func toggle_buttons() -> void: button_toggles += 1 var _fail := 0 func _ck(condition: bool, message: String) -> void: if not condition: _fail += 1 printerr("FAIL: " + message) func _key(code: Key, pressed := true, ctrl := false, meta := false) -> InputEventKey: var event := InputEventKey.new() event.keycode = code event.pressed = pressed event.echo = false event.ctrl_pressed = ctrl event.meta_pressed = meta return event func _init() -> void: await _run() if _fail == 0: print("PASS: input_key_test (ClientVS22 desktop key map)") quit(0) else: printerr("%d check(s) failed" % _fail) quit(1) func _run() -> void: var client := FakeClient.new() var qb := FakeQuickbar.new() var np := FakeNetPlay.new() var camera := FakeCamera.new() var world := FakeWorld.new() var chat := FakeChat.new() var status := FakeStatus.new() var help := FakeToggle.new() var quest := FakeToggle.new() var gs: Node = GameScene.new() gs.client = client gs.quickbar = qb gs.net_play = np gs.cam = camera gs.net_world = world gs.chat = chat gs.char_status_ui = status gs.system_menu_ui = help gs.quest_log = quest get_root().add_child(gs) gs._unhandled_input(_key(KEY_1, true, true, false)) gs._unhandled_input(_key(KEY_9, true, false, true)) _ck(client.emotes == [0, 8], "Ctrl/Command+number -> matching emoticon") gs._unhandled_input(_key(KEY_1)) gs._unhandled_input(_key(KEY_F1)) gs._unhandled_input(_key(KEY_F4)) _ck(qb.activated == [0, 4, 7], "number/F1-F4 -> reference local quick slots") gs._unhandled_input(_key(KEY_SHIFT)) gs._unhandled_input(_key(KEY_4)) gs._unhandled_input(_key(KEY_SHIFT, false)) _ck(qb.pages == [3], "held Shift + number -> quick page 4") gs._unhandled_input(_key(KEY_SPACE)) gs._unhandled_input(_key(KEY_SPACE, false)) _ck(np.attack_states == [true, false], "Space press/release -> attack key state") gs._unhandled_input(_key(KEY_Q)) gs._unhandled_input(_key(KEY_Q, false)) gs._unhandled_input(_key(KEY_R)) gs._unhandled_input(_key(KEY_R, false)) _ck(camera.orbit == [-1, 0] and camera.zoom == [-1, 0], "camera Q/R release stops continuous motion") gs._unhandled_input(_key(KEY_ALT)) gs._unhandled_input(_key(KEY_ALT, false)) _ck(world.names == [true, false], "Alt press/release -> ShowName/HideName") gs._unhandled_input(_key(KEY_B)) gs._unhandled_input(_key(KEY_V)) gs._unhandled_input(_key(KEY_C)) gs._unhandled_input(_key(KEY_H)) gs._unhandled_input(_key(KEY_N)) _ck(status.states == ["EMOTICON", "SKILL", "STATUS"], "character tabs match B/V/C") _ck(help.toggles == 1 and quest.toggles == 1, "H help and N quest log") gs._unhandled_input(_key(KEY_Q, true, true)) _ck(quest.button_toggles == 1, "Ctrl+Q toggles quest buttons") gs._unhandled_input(_key(KEY_L)) _ck(chat.toggles == 1, "L toggles chat log") gs._unhandled_input(_key(KEY_H, true, true)) gs._unhandled_input(_key(KEY_B, true, false, true)) gs._unhandled_input(_key(KEY_J, true, true)) _ck(client.commands == ["/user_horse_ride", "/user_horse_back", "/unmount"], "Ctrl/Command horse commands follow reference") # CWindowManager::RunKeyDown:只有 LockWindow(模态)或返回 True 的 ActiveWindow(输入框) # 截键;普通打开的窗口(技能窗 / 背包)不吞键,1-4 / F1-F4 照样落到 game.py 快捷栏。 var ui_manager: CanvasLayer = UiManager.new() get_root().add_child(ui_manager) await process_frame gs.ui = ui_manager var skill_window := Panel.new() ui_manager.open(skill_window) qb.activated.clear() gs._unhandled_input(_key(KEY_2)) gs._unhandled_input(_key(KEY_F2)) _ck(qb.activated == [1, 5], "non-modal window open keeps number/F-key quick slots: %s" % [qb.activated]) var confirm := Panel.new() ui_manager.open(confirm, true) gs._unhandled_input(_key(KEY_3)) _ck(qb.activated == [1, 5], "modal lock window still swallows quick slot keys") gs.ui = null