// 输入:IWBT 经典键位(Shift 跳 / Z 跳 / X 射击 / R 重来)。 // 与 web 版 input.js 1:1 对应。键码沿用 Web 的 KeyboardEvent.code 字符串, // 由 UI 层的键盘监听器把 Flutter 按键翻译成 code 后喂给 onKey()。 import 'dart:convert'; class Input { /// 动作 -> 默认绑定的按键 code 列表。 static final Map> bind = { 'left': ['ArrowLeft', 'KeyA'], 'right': ['ArrowRight', 'KeyD'], 'up': ['ArrowUp', 'KeyW'], 'down': ['ArrowDown', 'KeyS'], 'jump': ['ShiftLeft', 'ShiftRight', 'Space', 'KeyZ', 'KeyN'], 'shoot': ['KeyX', 'KeyJ', 'KeyC', 'KeyM'], 'suicide': ['KeyR'], // IWBT 标准:自杀并回到最近存档点 'restart': ['Backspace'], // 整关从头再来(放弃所有存档点) 'pause': ['Escape', 'KeyP'], 'menu': ['KeyQ'], }; static final List actions = bind.keys.toList(); // ['left','right',...] static final Map> _defaultBind = { for (final e in bind.entries) e.key: List.from(e.value), }; static final Set down = {}; // 当前按住的原始 code static final Map now = {for (final a in bind.keys) a: false}; static final Map prev = {for (final a in bind.keys) a: false}; static final Map touch = {}; // 触屏虚拟按键 action -> bool static bool enabled = true; static bool held(String a) => now[a] ?? false; static bool hit(String a) => (now[a] ?? false) && !(prev[a] ?? false); static bool released(String a) => !(now[a] ?? false) && (prev[a] ?? false); static bool raw(String c) => down.contains(c); static bool anyHit() { for (final k in now.keys) { if (now[k]! && !(prev[k] ?? false)) return true; } return false; } static void clear() { down.clear(); for (final k in now.keys) now[k] = false; for (final k in prev.keys) prev[k] = false; } /// 每逻辑帧末尾调用。 static void endFrame() { for (final k in now.keys) prev[k] = now[k]!; } static void _refresh() { for (final act in bind.keys) { bool v = false; for (final c in bind[act]!) { if (down.contains(c)) { v = true; break; } } if (touch[act] ?? false) v = true; now[act] = enabled ? v : false; } } /// 原始键盘事件(Web code 字符串)。 static void onKey(String code, bool isDown) { if (isDown) { down.add(code); } else { down.remove(code); } _refresh(); } // ---------------- 触屏虚拟按键 ---------------- static void setTouch(String action, bool on) { touch.putIfAbsent(action, () => false); if (touch[action] == on) return; touch[action] = on; _refresh(); } static void clearTouch() { bool any = false; for (final k in touch.keys) { if (touch[k]!) { touch[k] = false; any = true; } } if (any) _refresh(); } // ---------------- 键位自定义(设置界面调用)---------------- static Map> defaultBindings() => {for (final e in bind.entries) e.key: List.from(e.value)}; static Map> snapshotBindings() => {for (final e in bind.entries) e.key: List.from(e.value)}; static void applyBindings(Map>? map) { if (map == null) return; for (final act in map.keys) { if (bind.containsKey(act)) bind[act] = List.from(map[act]!); } } /// 持久化用:转 JSON 字符串。 static String toJson() => jsonEncode(bind); static void fromJson(String? s) { if (s == null) return; try { final m = (jsonDecode(s) as Map).cast(); final decoded = m.map((k, v) => MapEntry(k, List.from(v as List))); applyBindings(decoded); } catch (_) {} } }