mirror of
https://github.com/MaSzyna-EU07/StarterNG.git
synced 2026-10-29 19:17:29 +01:00
Keybinds editor
This commit is contained in:
250
StarterNG/Classes/KeyMap.cs
Normal file
250
StarterNG/Classes/KeyMap.cs
Normal file
@@ -0,0 +1,250 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Avalonia.Input;
|
||||
|
||||
namespace StarterNG.Classes;
|
||||
|
||||
/// <summary>
|
||||
/// One cap on the on-screen keyboard. <see cref="Token"/> is the simulator key
|
||||
/// token a binding would reference; when null the cap is a non-bindable filler
|
||||
/// (Shift, Ctrl, Tab …) drawn only to keep the layout recognisable.
|
||||
/// </summary>
|
||||
public sealed class KeyCap
|
||||
{
|
||||
public string Label = string.Empty;
|
||||
public string? Token; // null => filler / not bindable
|
||||
public double Width = 1.0; // relative width (1 == a standard key)
|
||||
|
||||
public KeyCap(string label, string? token = null, double width = 1.0)
|
||||
{
|
||||
Label = label;
|
||||
Token = token;
|
||||
Width = width;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Translates between physical keyboard input, simulator key tokens and the
|
||||
/// on-screen keyboard layout used by the controls visualisation.
|
||||
/// </summary>
|
||||
public static class KeyMap
|
||||
{
|
||||
/// <summary>
|
||||
/// Resolves a pressed key to its simulator token, using the physical key to
|
||||
/// disambiguate the numeric keypad. Returns null for keys with no token
|
||||
/// (e.g. bare modifiers).
|
||||
/// </summary>
|
||||
public static string? FromInput(Key key, PhysicalKey physical)
|
||||
{
|
||||
// Numeric keypad first - distinguished only by the physical key.
|
||||
switch (physical)
|
||||
{
|
||||
case PhysicalKey.NumPad0: return "num_0";
|
||||
case PhysicalKey.NumPad1: return "num_1";
|
||||
case PhysicalKey.NumPad2: return "num_2";
|
||||
case PhysicalKey.NumPad3: return "num_3";
|
||||
case PhysicalKey.NumPad4: return "num_4";
|
||||
case PhysicalKey.NumPad5: return "num_5";
|
||||
case PhysicalKey.NumPad6: return "num_6";
|
||||
case PhysicalKey.NumPad7: return "num_7";
|
||||
case PhysicalKey.NumPad8: return "num_8";
|
||||
case PhysicalKey.NumPad9: return "num_9";
|
||||
case PhysicalKey.NumPadAdd: return "num_+";
|
||||
case PhysicalKey.NumPadSubtract: return "num_-";
|
||||
case PhysicalKey.NumPadMultiply: return "num_*";
|
||||
case PhysicalKey.NumPadDivide: return "num_/";
|
||||
case PhysicalKey.NumPadDecimal: return "num_.";
|
||||
case PhysicalKey.NumPadEnter: return "num_enter";
|
||||
}
|
||||
|
||||
// Numeric keypad via the virtual key (fallback when PhysicalKey is Unknown).
|
||||
if (key >= Key.NumPad0 && key <= Key.NumPad9)
|
||||
return "num_" + (char)('0' + (key - Key.NumPad0));
|
||||
|
||||
// Letters.
|
||||
if (key >= Key.A && key <= Key.Z)
|
||||
return ((char)('a' + (key - Key.A))).ToString();
|
||||
|
||||
// Top-row digits.
|
||||
if (key >= Key.D0 && key <= Key.D9)
|
||||
return ((char)('0' + (key - Key.D0))).ToString();
|
||||
|
||||
return key switch
|
||||
{
|
||||
Key.Add => "num_+",
|
||||
Key.Subtract => "num_-",
|
||||
Key.Multiply => "num_*",
|
||||
Key.Divide => "num_/",
|
||||
Key.Decimal => "num_.",
|
||||
Key.Space => "space",
|
||||
Key.Home => "home",
|
||||
Key.End => "end",
|
||||
Key.Insert => "insert",
|
||||
Key.Delete => "delete",
|
||||
Key.Back => "backspace",
|
||||
Key.Pause => "pause",
|
||||
Key.OemPlus => "=",
|
||||
Key.OemMinus => "-",
|
||||
Key.OemComma => ",",
|
||||
Key.OemPeriod => ".",
|
||||
Key.OemQuestion => "/",
|
||||
Key.OemSemicolon => ";",
|
||||
Key.OemQuotes => "'",
|
||||
Key.OemBackslash or Key.OemPipe => "\\",
|
||||
Key.F1 => "f1", Key.F2 => "f2", Key.F3 => "f3", Key.F4 => "f4",
|
||||
Key.F5 => "f5", Key.F6 => "f6", Key.F7 => "f7", Key.F8 => "f8",
|
||||
Key.F9 => "f9", Key.F10 => "f10", Key.F11 => "f11", Key.F12 => "f12",
|
||||
_ => null
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>True for keys that only act as modifiers and never form a binding alone.</summary>
|
||||
public static bool IsModifierKey(Key key) => key is
|
||||
Key.LeftShift or Key.RightShift or
|
||||
Key.LeftCtrl or Key.RightCtrl or
|
||||
Key.LeftAlt or Key.RightAlt or
|
||||
Key.LWin or Key.RWin;
|
||||
|
||||
/// <summary>Friendly, explicit name for a token, used in the binding list text.</summary>
|
||||
public static string DisplayName(string? token)
|
||||
{
|
||||
if (string.IsNullOrEmpty(token) ||
|
||||
token.Equals("none", StringComparison.OrdinalIgnoreCase))
|
||||
return "—";
|
||||
|
||||
if (token.StartsWith("num_", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
string rest = token.Substring(4);
|
||||
return rest switch
|
||||
{
|
||||
"enter" => "Num Enter",
|
||||
"+" => "Num +",
|
||||
"-" => "Num -",
|
||||
"*" => "Num *",
|
||||
"/" => "Num /",
|
||||
"." => "Num .",
|
||||
_ => "Num " + rest
|
||||
};
|
||||
}
|
||||
|
||||
return token switch
|
||||
{
|
||||
"space" => "Space",
|
||||
"home" => "Home",
|
||||
"end" => "End",
|
||||
"insert" => "Insert",
|
||||
"delete" => "Delete",
|
||||
"pageup" => "Page Up",
|
||||
"pagedown" => "Page Down",
|
||||
"backspace" => "Backspace",
|
||||
"pause" => "Pause",
|
||||
"\\" => "\\",
|
||||
_ when token.Length == 1 => token.ToUpperInvariant(),
|
||||
_ => char.ToUpperInvariant(token[0]) + token.Substring(1)
|
||||
};
|
||||
}
|
||||
|
||||
// ── On-screen keyboard layout ──────────────────────────────────────────
|
||||
// Filler caps (Token == null) keep the shape familiar; only caps with a
|
||||
// token are coloured by assignment state.
|
||||
|
||||
/// <summary>Rows of the main (alphanumeric) keyboard block.</summary>
|
||||
public static readonly KeyCap[][] MainBlock =
|
||||
{
|
||||
// F-row keys are reserved by the simulator, so they carry no token.
|
||||
new[]
|
||||
{
|
||||
new KeyCap("Esc", null, 1.4),
|
||||
new KeyCap("F1"), new KeyCap("F2"), new KeyCap("F3"), new KeyCap("F4"),
|
||||
new KeyCap("F5"), new KeyCap("F6"), new KeyCap("F7"), new KeyCap("F8"),
|
||||
new KeyCap("F9"), new KeyCap("F10"), new KeyCap("F11"), new KeyCap("F12"),
|
||||
},
|
||||
new[]
|
||||
{
|
||||
new KeyCap("`", null),
|
||||
new KeyCap("1", "1"), new KeyCap("2", "2"), new KeyCap("3", "3"), new KeyCap("4", "4"),
|
||||
new KeyCap("5", "5"), new KeyCap("6", "6"), new KeyCap("7", "7"), new KeyCap("8", "8"),
|
||||
new KeyCap("9", "9"), new KeyCap("0", "0"),
|
||||
new KeyCap("-", "-"), new KeyCap("=", "="),
|
||||
new KeyCap("Backspace", "backspace", 2.0),
|
||||
},
|
||||
new[]
|
||||
{
|
||||
new KeyCap("Tab", null, 1.5),
|
||||
new KeyCap("Q", "q"), new KeyCap("W", "w"), new KeyCap("E", "e"), new KeyCap("R", "r"),
|
||||
new KeyCap("T", "t"), new KeyCap("Y", "y"), new KeyCap("U", "u"), new KeyCap("I", "i"),
|
||||
new KeyCap("O", "o"), new KeyCap("P", "p"),
|
||||
new KeyCap("[", null), new KeyCap("]", null),
|
||||
new KeyCap("\\", "\\", 1.5),
|
||||
},
|
||||
new[]
|
||||
{
|
||||
new KeyCap("Caps", null, 1.8),
|
||||
new KeyCap("A", "a"), new KeyCap("S", "s"), new KeyCap("D", "d"), new KeyCap("F", "f"),
|
||||
new KeyCap("G", "g"), new KeyCap("H", "h"), new KeyCap("J", "j"), new KeyCap("K", "k"),
|
||||
new KeyCap("L", "l"),
|
||||
new KeyCap(";", ";"), new KeyCap("'", "'"),
|
||||
new KeyCap("Enter", null, 2.2),
|
||||
},
|
||||
new[]
|
||||
{
|
||||
new KeyCap("Shift", null, 2.3),
|
||||
new KeyCap("Z", "z"), new KeyCap("X", "x"), new KeyCap("C", "c"), new KeyCap("V", "v"),
|
||||
new KeyCap("B", "b"), new KeyCap("N", "n"), new KeyCap("M", "m"),
|
||||
new KeyCap(",", ","), new KeyCap(".", "."), new KeyCap("/", "/"),
|
||||
new KeyCap("Shift", null, 2.7),
|
||||
},
|
||||
new[]
|
||||
{
|
||||
new KeyCap("Ctrl", null, 1.5),
|
||||
new KeyCap("Win", null, 1.3),
|
||||
new KeyCap("Alt", null, 1.3),
|
||||
new KeyCap("Space", "space", 6.0),
|
||||
new KeyCap("Alt", null, 1.3),
|
||||
new KeyCap("Ctrl", null, 1.5),
|
||||
},
|
||||
};
|
||||
|
||||
/// <summary>Rows of the numeric-keypad block, drawn to the right of the main block.</summary>
|
||||
public static readonly KeyCap[][] NumpadBlock =
|
||||
{
|
||||
new[]
|
||||
{
|
||||
new KeyCap("Num", null), new KeyCap("/", "num_/"),
|
||||
new KeyCap("*", "num_*"), new KeyCap("-", "num_-"),
|
||||
},
|
||||
new[]
|
||||
{
|
||||
new KeyCap("7", "num_7"), new KeyCap("8", "num_8"),
|
||||
new KeyCap("9", "num_9"), new KeyCap("+", "num_+"),
|
||||
},
|
||||
new[]
|
||||
{
|
||||
new KeyCap("4", "num_4"), new KeyCap("5", "num_5"),
|
||||
new KeyCap("6", "num_6"), new KeyCap("", null),
|
||||
},
|
||||
new[]
|
||||
{
|
||||
new KeyCap("1", "num_1"), new KeyCap("2", "num_2"),
|
||||
new KeyCap("3", "num_3"), new KeyCap("Ent", "num_enter"),
|
||||
},
|
||||
new[]
|
||||
{
|
||||
new KeyCap("0", "num_0", 2.0), new KeyCap(".", "num_."), new KeyCap("", null),
|
||||
},
|
||||
};
|
||||
|
||||
/// <summary>Navigation cluster (Insert/Home/PageUp · Delete/End/PageDown), drawn between the blocks.</summary>
|
||||
public static readonly KeyCap[][] NavBlock =
|
||||
{
|
||||
// PgUp / PgDn are reserved by the simulator (no token), like [ ] and Enter.
|
||||
new[]
|
||||
{
|
||||
new KeyCap("Ins", "insert"), new KeyCap("Home", "home"), new KeyCap("PgUp"),
|
||||
},
|
||||
new[]
|
||||
{
|
||||
new KeyCap("Del", "delete"), new KeyCap("End", "end"), new KeyCap("PgDn"),
|
||||
},
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user