Fix smoke gaps: recorder target + VK translation, player enum + null guard (#11)
This commit is contained in:
91
src/Recordingtest.Recorder/KeyTranslator.cs
Normal file
91
src/Recordingtest.Recorder/KeyTranslator.cs
Normal file
@@ -0,0 +1,91 @@
|
||||
using System.Globalization;
|
||||
|
||||
namespace Recordingtest.Recorder;
|
||||
|
||||
/// <summary>
|
||||
/// Translates Win32 virtual-key codes into human-readable strings for
|
||||
/// scenario yaml. See issue #11 — prior recorder emitted raw VK ints which
|
||||
/// broke replay. Rules:
|
||||
/// - modifiers (Ctrl/Shift/Alt/Win) are tracked separately and not emitted as standalone steps
|
||||
/// - printable keys (letters/digits/space) become single-character strings
|
||||
/// - other named keys become lowercase names (enter, tab, esc, f1..f12, arrows, ...)
|
||||
/// </summary>
|
||||
public static class KeyTranslator
|
||||
{
|
||||
public enum KeyCategory
|
||||
{
|
||||
Modifier,
|
||||
Printable,
|
||||
Named,
|
||||
}
|
||||
|
||||
public readonly record struct Translated(KeyCategory Category, string Text, uint RawVk);
|
||||
|
||||
// Convention chosen for issue #11: printable letters are emitted UPPERCASE
|
||||
// matching VK semantics (VK for 'A' is 0x41). Case handling is the player's
|
||||
// concern (Shift state is tracked separately as a modifier).
|
||||
public static Translated Translate(uint vk)
|
||||
{
|
||||
switch (vk)
|
||||
{
|
||||
case 0x10: // VK_SHIFT
|
||||
case 0xA0: // VK_LSHIFT
|
||||
case 0xA1: // VK_RSHIFT
|
||||
return new Translated(KeyCategory.Modifier, "shift", vk);
|
||||
case 0x11: // VK_CONTROL
|
||||
case 0xA2: // VK_LCONTROL
|
||||
case 0xA3: // VK_RCONTROL
|
||||
return new Translated(KeyCategory.Modifier, "ctrl", vk);
|
||||
case 0x12: // VK_MENU (Alt)
|
||||
case 0xA4: // VK_LMENU
|
||||
case 0xA5: // VK_RMENU
|
||||
return new Translated(KeyCategory.Modifier, "alt", vk);
|
||||
case 0x5B: // VK_LWIN
|
||||
case 0x5C: // VK_RWIN
|
||||
return new Translated(KeyCategory.Modifier, "win", vk);
|
||||
|
||||
case 0x08: return new Translated(KeyCategory.Named, "backspace", vk);
|
||||
case 0x09: return new Translated(KeyCategory.Named, "tab", vk);
|
||||
case 0x0D: return new Translated(KeyCategory.Named, "enter", vk);
|
||||
case 0x1B: return new Translated(KeyCategory.Named, "escape", vk);
|
||||
case 0x20: return new Translated(KeyCategory.Printable, " ", vk);
|
||||
case 0x21: return new Translated(KeyCategory.Named, "pageup", vk);
|
||||
case 0x22: return new Translated(KeyCategory.Named, "pagedown", vk);
|
||||
case 0x23: return new Translated(KeyCategory.Named, "end", vk);
|
||||
case 0x24: return new Translated(KeyCategory.Named, "home", vk);
|
||||
case 0x25: return new Translated(KeyCategory.Named, "left", vk);
|
||||
case 0x26: return new Translated(KeyCategory.Named, "up", vk);
|
||||
case 0x27: return new Translated(KeyCategory.Named, "right", vk);
|
||||
case 0x28: return new Translated(KeyCategory.Named, "down", vk);
|
||||
case 0x2D: return new Translated(KeyCategory.Named, "insert", vk);
|
||||
case 0x2E: return new Translated(KeyCategory.Named, "delete", vk);
|
||||
}
|
||||
|
||||
// Letters A-Z (VK 0x41..0x5A)
|
||||
if (vk >= 0x41 && vk <= 0x5A)
|
||||
{
|
||||
var c = (char)vk;
|
||||
return new Translated(KeyCategory.Printable, c.ToString(CultureInfo.InvariantCulture), vk);
|
||||
}
|
||||
// Top-row digits 0-9 (VK 0x30..0x39)
|
||||
if (vk >= 0x30 && vk <= 0x39)
|
||||
{
|
||||
var c = (char)vk;
|
||||
return new Translated(KeyCategory.Printable, c.ToString(CultureInfo.InvariantCulture), vk);
|
||||
}
|
||||
// Numpad digits (VK 0x60..0x69)
|
||||
if (vk >= 0x60 && vk <= 0x69)
|
||||
{
|
||||
var c = (char)('0' + (vk - 0x60));
|
||||
return new Translated(KeyCategory.Printable, c.ToString(CultureInfo.InvariantCulture), vk);
|
||||
}
|
||||
// F1..F24 (VK 0x70..0x87)
|
||||
if (vk >= 0x70 && vk <= 0x87)
|
||||
{
|
||||
var n = (int)(vk - 0x70) + 1;
|
||||
return new Translated(KeyCategory.Named, "f" + n.ToString(CultureInfo.InvariantCulture), vk);
|
||||
}
|
||||
|
||||
return new Translated(KeyCategory.Named, "vk" + vk.ToString(CultureInfo.InvariantCulture), vk);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user