Files
recordingtest/src/Recordingtest.Recorder/KeyTranslator.cs

92 lines
3.9 KiB
C#

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);
}
}