-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathInputHelper.cs
More file actions
204 lines (189 loc) · 9.92 KB
/
InputHelper.cs
File metadata and controls
204 lines (189 loc) · 9.92 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
namespace OuterWildsAccess
{
/// <summary>
/// Returns user-friendly display names for input commands.
///
/// Priority chain:
/// 1. Physical button name(s) joined from all UI textures (e.g. "L2 + R2", "Cross")
/// 2. Localized action name from Loc._keyLabels (e.g. "Interact")
/// 3. Sanitized raw GetLabel result (e.g. "Match Velocity")
///
/// Texture naming conventions observed in this game:
/// Keyboard : "Keyboard_Black_E", "Keyboard_Black_Return", …
/// Xbox : "XboxOne_A", "XboxOne_B", "XboxOne_Menu", …
/// PS4/PS5 : "PS4_Cross", "PS5_Circle", "DualSense_L2", …
///
/// Debug mode logs raw texture names AND raw GetLabel values — use them to
/// expand Loc._keyLabels when encountering unmapped actions in-game.
/// </summary>
public static class InputHelper
{
/// <summary>
/// Returns the best available display label for the given command,
/// or null if nothing meaningful could be determined.
/// Supports multi-button combos (all textures joined with " + ").
/// </summary>
public static string GetCommandLabel(IInputCommands cmd)
{
if (cmd == null) return null;
try
{
bool gamepad = OWInput.UsingGamepad();
var textures = cmd.GetUITextures(gamepad);
if (textures != null && textures.Count > 0)
{
// Collect a label for every texture (multi-button combo support)
var parts = new System.Collections.Generic.List<string>(textures.Count);
foreach (var tex in textures)
{
if (tex == null) continue;
DebugLogger.Log(LogCategory.State, "InputHelper", $"Texture: {tex.name}");
string p = GetPhysicalButtonName(tex.name);
if (!string.IsNullOrEmpty(p)) parts.Add(p);
}
if (parts.Count > 0)
return string.Join(" + ", parts);
}
// Fallback 1: localized action name from our dictionary
string rawLabel = InputTransitionUtil.GetLabel(cmd.CommandType);
DebugLogger.Log(LogCategory.State, "InputHelper", $"GetLabel: {rawLabel}");
string localized = Loc.LocalizeKeyLabel(rawLabel);
if (!string.IsNullOrEmpty(localized) && localized != rawLabel)
return TextUtils.CleanText(localized);
// Fallback 2: sanitize the raw label so the screen reader reads something useful
// e.g. "MATCH_VELOCITY" → "Match Velocity"
return SanitizeRawLabel(rawLabel);
}
catch { return null; }
}
/// <summary>
/// Converts an all-caps underscored label into a readable title-case string.
/// Returns null if the result would be empty.
/// </summary>
private static string SanitizeRawLabel(string raw)
{
if (string.IsNullOrWhiteSpace(raw)) return null;
string spaced = raw.Replace("_", " ").Trim();
if (spaced.Length == 0) return null;
// Title case: uppercase first letter of each word, lowercase the rest
var words = spaced.Split(' ');
for (int i = 0; i < words.Length; i++)
{
if (words[i].Length == 0) continue;
words[i] = char.ToUpper(words[i][0]) +
(words[i].Length > 1 ? words[i].Substring(1).ToLower() : "");
}
return string.Join(" ", words);
}
/// <summary>
/// Maps a texture asset name to a localized button label.
/// Returns null if the name is unknown.
/// </summary>
public static string GetPhysicalButtonName(string textureName)
{
if (string.IsNullOrEmpty(textureName)) return null;
if (textureName.StartsWith("Keyboard_"))
{
// Strip colour prefixes: "Keyboard_Black_", "Keyboard_White_", "Keyboard_"
string key = textureName;
foreach (string prefix in new[] { "Keyboard_Black_", "Keyboard_White_", "Keyboard_" })
{
if (key.StartsWith(prefix)) { key = key.Substring(prefix.Length); break; }
}
return MapKeyboardKey(key);
}
if (textureName.StartsWith("XboxOne_"))
return MapXboxButton(textureName.Substring("XboxOne_".Length));
// All known PlayStation prefixes (PS4, PS5, DualSense, DualShock)
foreach (string psPrefix in new[] { "PS5_", "PS4_", "DualSense_", "DualShock4_", "DualShock_", "PS_" })
{
if (textureName.StartsWith(psPrefix))
return MapPSButton(textureName.Substring(psPrefix.Length));
}
// Unknown prefix — log in debug mode so we can add a mapping later
DebugLogger.Log(LogCategory.State, "InputHelper", $"Unknown texture: {textureName}");
return null;
}
// ─────────────────────────────────────────────────────────────────────
// Keyboard
// ─────────────────────────────────────────────────────────────────────
private static string MapKeyboardKey(string key)
{
switch (key)
{
case "Return":
case "Enter": return Loc.Get("btn_enter");
case "Space": return Loc.Get("btn_space");
case "Escape": return Loc.Get("btn_escape");
case "Backspace": return Loc.Get("btn_backspace");
case "Tab": return "Tab";
case "Delete": return Loc.Get("btn_delete");
case "Up": return Loc.Get("btn_up");
case "Down": return Loc.Get("btn_down");
case "Left": return Loc.Get("btn_left");
case "Right": return Loc.Get("btn_right");
case "LeftShift":
case "RightShift": return "Shift";
case "LeftControl":
case "RightControl":return "Ctrl";
case "LeftAlt":
case "RightAlt": return "Alt";
default: return key; // single letter, F1-F12, etc.
}
}
// ─────────────────────────────────────────────────────────────────────
// Xbox One / Xbox Series
// ─────────────────────────────────────────────────────────────────────
private static string MapXboxButton(string btn)
{
switch (btn)
{
case "A": return "A";
case "B": return "B";
case "X": return "X";
case "Y": return "Y";
case "LB": return "LB";
case "RB": return "RB";
case "LT": return "LT";
case "RT": return "RT";
case "Menu": return "Menu";
case "View": return Loc.Get("btn_xbox_view");
case "LS": return "LS";
case "RS": return "RS";
case "DPad_Up": return Loc.Get("btn_dpad_up");
case "DPad_Down": return Loc.Get("btn_dpad_down");
case "DPad_Left": return Loc.Get("btn_dpad_left");
case "DPad_Right": return Loc.Get("btn_dpad_right");
default: return btn;
}
}
// ─────────────────────────────────────────────────────────────────────
// PlayStation 4 / 5
// ─────────────────────────────────────────────────────────────────────
private static string MapPSButton(string btn)
{
switch (btn)
{
case "Cross": return Loc.Get("btn_ps_cross");
case "Circle": return Loc.Get("btn_ps_circle");
case "Square": return Loc.Get("btn_ps_square");
case "Triangle": return "Triangle";
case "L1": return "L1";
case "R1": return "R1";
case "L2": return "L2";
case "R2": return "R2";
case "L3": return "L3";
case "R3": return "R3";
case "Options": return "Options";
case "Share": return Loc.Get("btn_ps_share");
case "Create": return Loc.Get("btn_ps_create");
case "Touchpad": return Loc.Get("btn_ps_touchpad");
case "DPad_Up": return Loc.Get("btn_dpad_up");
case "DPad_Down": return Loc.Get("btn_dpad_down");
case "DPad_Left": return Loc.Get("btn_dpad_left");
case "DPad_Right": return Loc.Get("btn_dpad_right");
default: return btn;
}
}
}
}