92 lines
3.9 KiB
C#
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);
|
|
}
|
|
}
|