mirror of
https://github.com/livingcomputermuseum/ContrAlto.git
synced 2026-02-28 09:17:53 +00:00
Initial commit of changes for 1.2.3. This includes:
- Scripting support: Allows for recording and playback of mouse/keyboard input and various system control actions. Simple (i.e. basic) scripting format. - Fix for stale packets left in ethernet input queue; packets received by pcap while Alto's receiver is off are discarded. - Mouse input made more accurate, and tweaked to avoid Alto microcode bug that causes erroneous mouse inputs under very rare circumstances on real hardware, but much more frequently under emulation. - Small code cleanup here and there. Moved many UI strings to resources, many more to go.
This commit is contained in:
701
Contralto/Scripting/ScriptAction.cs
Normal file
701
Contralto/Scripting/ScriptAction.cs
Normal file
@@ -0,0 +1,701 @@
|
||||
using Contralto.IO;
|
||||
using Contralto.SdlUI;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Contralto.Scripting
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// Base class for scripting actions.
|
||||
/// "Timestamp" provides a relative timestamp (in nsec) for the action.
|
||||
/// "Completed" indicates whether the action completed during the last execution.
|
||||
/// Actions can run multiple times by leaving Completed = false and adjusting the
|
||||
/// Timestamp appropriately; the playback engine will reschedule it in this case.
|
||||
/// </summary>
|
||||
public abstract class ScriptAction
|
||||
{
|
||||
public ScriptAction(ulong timestamp)
|
||||
{
|
||||
_timestamp = timestamp;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Relative timestamp for this action.
|
||||
/// </summary>
|
||||
public ulong Timestamp
|
||||
{
|
||||
get { return _timestamp; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Whether the action has completed after the last
|
||||
/// Replay action
|
||||
/// </summary>
|
||||
public bool Completed
|
||||
{
|
||||
get { return _completed; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Replays a single step of the action. If the action is completed,
|
||||
/// Completed will be true afterwards.
|
||||
/// </summary>
|
||||
/// <param name="system"></param>
|
||||
/// <param name="controller"></param>
|
||||
public abstract void Replay(AltoSystem system, ExecutionController controller);
|
||||
|
||||
/// <summary>
|
||||
/// Constructs the proper ScriptAction from a given line of text
|
||||
/// </summary>
|
||||
/// <param name="line"></param>
|
||||
/// <returns></returns>
|
||||
public static ScriptAction Parse(string line)
|
||||
{
|
||||
//
|
||||
// An Action consists of a line in the format:
|
||||
// <timestamp> <Action Type> [args]
|
||||
//
|
||||
// <timestamp> specifies a time relative to the last action, and may be:
|
||||
// - a 64-bit integer indicating a time in nanoseconds
|
||||
// - a double-precision floating point integer ending with "ms" indicating time in milliseconds
|
||||
// - a "-", indicating a relative time of zero. (a "0" also works).
|
||||
//
|
||||
string[] tokens = line.Split(new char[] { ' ', ',' });
|
||||
|
||||
if (tokens.Length < 2)
|
||||
{
|
||||
throw new InvalidOperationException("Invalid Action format.");
|
||||
}
|
||||
|
||||
ulong timestamp = 0;
|
||||
|
||||
if (tokens[0] != "-")
|
||||
{
|
||||
if (tokens[0].ToLowerInvariant().EndsWith("ms"))
|
||||
{
|
||||
// timestamp in msec
|
||||
double fstamp = double.Parse(tokens[0].Substring(0, tokens[0].Length - 2));
|
||||
|
||||
timestamp = (ulong)(fstamp * Conversion.MsecToNsec);
|
||||
}
|
||||
else
|
||||
{
|
||||
// assume timestamp in nsec
|
||||
timestamp = ulong.Parse(tokens[0]);
|
||||
}
|
||||
}
|
||||
|
||||
switch(tokens[1])
|
||||
{
|
||||
case "KeyDown":
|
||||
return KeyAction.Parse(timestamp, true, tokens);
|
||||
|
||||
case "KeyUp":
|
||||
return KeyAction.Parse(timestamp, false, tokens);
|
||||
|
||||
case "MouseDown":
|
||||
return MouseButtonAction.Parse(timestamp, true, tokens);
|
||||
|
||||
case "MouseUp":
|
||||
return MouseButtonAction.Parse(timestamp, false, tokens);
|
||||
|
||||
case "MouseMove":
|
||||
return MouseMoveAction.Parse(timestamp, false, tokens);
|
||||
|
||||
case "MouseMoveAbsolute":
|
||||
return MouseMoveAction.Parse(timestamp, true, tokens);
|
||||
|
||||
case "Command":
|
||||
return CommandAction.Parse(timestamp, tokens);
|
||||
|
||||
case "KeyStroke":
|
||||
return KeyStrokeAction.Parse(timestamp, tokens);
|
||||
|
||||
case "Type":
|
||||
return TypeAction.Parse(timestamp, false, tokens);
|
||||
|
||||
case "TypeLine":
|
||||
return TypeAction.Parse(timestamp, true, tokens);
|
||||
|
||||
case "Wait":
|
||||
return WaitAction.Parse(timestamp, true, tokens);
|
||||
|
||||
default:
|
||||
throw new InvalidOperationException("Invalid Action");
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
protected ulong _timestamp;
|
||||
protected bool _completed;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Injects a single key action (up or down) into the Alto's keyboard.
|
||||
/// </summary>
|
||||
public class KeyAction : ScriptAction
|
||||
{
|
||||
public KeyAction(ulong timestamp, AltoKey key, bool keyDown) : base(timestamp)
|
||||
{
|
||||
_key = key;
|
||||
_keyDown = keyDown;
|
||||
}
|
||||
|
||||
public override void Replay(AltoSystem system, ExecutionController controller)
|
||||
{
|
||||
if (_keyDown)
|
||||
{
|
||||
system.Keyboard.KeyDown(_key);
|
||||
}
|
||||
else
|
||||
{
|
||||
system.Keyboard.KeyUp(_key);
|
||||
}
|
||||
|
||||
_completed = true;
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return String.Format("{0} {1} {2}", _timestamp, _keyDown ? "KeyDown" : "KeyUp", _key);
|
||||
}
|
||||
|
||||
public static KeyAction Parse(ulong timestamp, bool keyDown, string[] tokens)
|
||||
{
|
||||
if (tokens.Length != 3)
|
||||
{
|
||||
throw new InvalidOperationException("Invalid KeyAction syntax.");
|
||||
}
|
||||
|
||||
AltoKey key = (AltoKey)Enum.Parse(typeof(AltoKey), tokens[2]);
|
||||
|
||||
return new KeyAction(timestamp, key, keyDown);
|
||||
|
||||
}
|
||||
|
||||
private AltoKey _key;
|
||||
private bool _keyDown;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Injects a single mouse button action (up or down) into the Alto's Mouse.
|
||||
/// </summary>
|
||||
public class MouseButtonAction : ScriptAction
|
||||
{
|
||||
public MouseButtonAction(ulong timestamp, AltoMouseButton buttons, bool mouseDown) : base(timestamp)
|
||||
{
|
||||
_buttons = buttons;
|
||||
_mouseDown = mouseDown;
|
||||
}
|
||||
|
||||
public override void Replay(AltoSystem system, ExecutionController controller)
|
||||
{
|
||||
if (_mouseDown)
|
||||
{
|
||||
system.MouseAndKeyset.MouseDown(_buttons);
|
||||
}
|
||||
else
|
||||
{
|
||||
system.MouseAndKeyset.MouseUp(_buttons);
|
||||
}
|
||||
|
||||
_completed = true;
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return String.Format("{0} {1} {2}", _timestamp, _mouseDown ? "MouseDown" : "MouseUp", _buttons);
|
||||
}
|
||||
|
||||
public static MouseButtonAction Parse(ulong timestamp, bool mouseDown, string[] tokens)
|
||||
{
|
||||
if (tokens.Length != 3)
|
||||
{
|
||||
throw new InvalidOperationException("Invalid MouseButtonAction syntax.");
|
||||
}
|
||||
|
||||
AltoMouseButton button = (AltoMouseButton)Enum.Parse(typeof(AltoMouseButton), tokens[2]);
|
||||
|
||||
return new MouseButtonAction(timestamp, button, mouseDown);
|
||||
|
||||
}
|
||||
|
||||
private AltoMouseButton _buttons;
|
||||
private bool _mouseDown;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Injects a mouse movement into the Alto's mouse.
|
||||
/// </summary>
|
||||
public class MouseMoveAction : ScriptAction
|
||||
{
|
||||
public MouseMoveAction(ulong timestamp, int dx, int dy, bool absolute) : base(timestamp)
|
||||
{
|
||||
_dx = dx;
|
||||
_dy = dy;
|
||||
_absolute = absolute;
|
||||
}
|
||||
|
||||
public override void Replay(AltoSystem system, ExecutionController controller)
|
||||
{
|
||||
if (_absolute)
|
||||
{
|
||||
//
|
||||
// We stuff the x/y coordinates into the well-defined memory locations for the mouse coordinates.
|
||||
//
|
||||
system.Memory.Load(0x114, (ushort)_dx, CPU.TaskType.Emulator, false);
|
||||
system.Memory.Load(0x115, (ushort)_dy, CPU.TaskType.Emulator, false);
|
||||
}
|
||||
else
|
||||
{
|
||||
system.MouseAndKeyset.MouseMove(_dx, _dy);
|
||||
}
|
||||
|
||||
_completed = true;
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return String.Format("{0} {1} {2},{3}", _timestamp, _absolute ? "MouseMoveAbsolute" : "MouseMove", _dx, _dy);
|
||||
}
|
||||
|
||||
public static MouseMoveAction Parse(ulong timestamp, bool absolute, string[] tokens)
|
||||
{
|
||||
if (tokens.Length != 4)
|
||||
{
|
||||
throw new InvalidOperationException("Invalid MouseMoveAction syntax.");
|
||||
}
|
||||
|
||||
int dx = int.Parse(tokens[2]);
|
||||
int dy = int.Parse(tokens[3]);
|
||||
|
||||
return new MouseMoveAction(timestamp, dx, dy, absolute);
|
||||
}
|
||||
|
||||
private int _dx;
|
||||
private int _dy;
|
||||
private bool _absolute;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Injects a command execution to control the Alto system. See ControlCommands for
|
||||
/// the actual commands.
|
||||
/// </summary>
|
||||
public class CommandAction : ScriptAction
|
||||
{
|
||||
public CommandAction(ulong timestamp, string commandString) : base(timestamp)
|
||||
{
|
||||
_commandString = commandString;
|
||||
}
|
||||
|
||||
public override void Replay(AltoSystem system, ExecutionController controller)
|
||||
{
|
||||
//
|
||||
// Execute the command.
|
||||
//
|
||||
// TODO: recreating these objects each time through is uncool.
|
||||
//
|
||||
ControlCommands controlCommands = new ControlCommands(system, controller);
|
||||
CommandExecutor executor = new CommandExecutor(controlCommands);
|
||||
|
||||
CommandResult res = executor.ExecuteCommand(_commandString);
|
||||
|
||||
if (res == CommandResult.Quit ||
|
||||
res == CommandResult.QuitNoSave)
|
||||
{
|
||||
//
|
||||
// Force an exit, commit disks if result was Quit.
|
||||
//
|
||||
throw new ShutdownException(res == CommandResult.Quit);
|
||||
}
|
||||
|
||||
_completed = true;
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return String.Format("{0} Command {1}", _timestamp, _commandString);
|
||||
}
|
||||
|
||||
public static CommandAction Parse(ulong timestamp, string[] tokens)
|
||||
{
|
||||
if (tokens.Length < 3)
|
||||
{
|
||||
throw new InvalidOperationException("Invalid Command syntax.");
|
||||
}
|
||||
|
||||
StringBuilder commandString = new StringBuilder();
|
||||
|
||||
for (int i = 2; i < tokens.Length; i++)
|
||||
{
|
||||
commandString.AppendFormat("{0} ", tokens[i]);
|
||||
}
|
||||
|
||||
return new CommandAction(timestamp, commandString.ToString());
|
||||
|
||||
}
|
||||
|
||||
private string _commandString;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Injects one or more simultaneous keystrokes (keydown followed by keyup) into the
|
||||
/// Alto's keyboard.
|
||||
/// </summary>
|
||||
public class KeyStrokeAction : ScriptAction
|
||||
{
|
||||
public KeyStrokeAction(ulong timestamp, AltoKey[] keys) : base(timestamp)
|
||||
{
|
||||
_keys = keys;
|
||||
_keyDown = true;
|
||||
}
|
||||
|
||||
public override void Replay(AltoSystem system, ExecutionController controller)
|
||||
{
|
||||
//
|
||||
// Press all requested keys simultaneously, then release them.
|
||||
//
|
||||
foreach(AltoKey key in _keys)
|
||||
{
|
||||
if (_keyDown)
|
||||
{
|
||||
system.Keyboard.KeyDown(key);
|
||||
}
|
||||
else
|
||||
{
|
||||
system.Keyboard.KeyUp(key);
|
||||
}
|
||||
}
|
||||
|
||||
if (_keyDown)
|
||||
{
|
||||
// Delay 50ms, then repeat for keyup
|
||||
_keyDown = false;
|
||||
_completed = false;
|
||||
_timestamp = 50 * Conversion.MsecToNsec;
|
||||
}
|
||||
else
|
||||
{
|
||||
_completed = true;
|
||||
}
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
StringBuilder keyString = new StringBuilder();
|
||||
|
||||
foreach(AltoKey key in _keys)
|
||||
{
|
||||
keyString.AppendFormat("{0} ", key);
|
||||
}
|
||||
|
||||
return String.Format("{0} KeyStroke {1}", _timestamp, keyString.ToString());
|
||||
}
|
||||
|
||||
public static KeyStrokeAction Parse(ulong timestamp, string[] tokens)
|
||||
{
|
||||
if (tokens.Length < 3)
|
||||
{
|
||||
throw new InvalidOperationException("Invalid KeyStroke syntax.");
|
||||
}
|
||||
|
||||
AltoKey[] keys = new AltoKey[tokens.Length - 2];
|
||||
|
||||
for (int i = 2; i < tokens.Length; i++)
|
||||
{
|
||||
keys[i - 2] = (AltoKey)Enum.Parse(typeof(AltoKey), tokens[i]);
|
||||
}
|
||||
|
||||
return new KeyStrokeAction(timestamp, keys);
|
||||
}
|
||||
|
||||
private AltoKey[] _keys;
|
||||
private bool _keyDown;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Injects a sequence of keystrokes corresponding to the keystrokes needed to
|
||||
/// type the provided string.
|
||||
/// </summary>
|
||||
public class TypeAction : ScriptAction
|
||||
{
|
||||
static TypeAction()
|
||||
{
|
||||
BuildKeyMap();
|
||||
}
|
||||
|
||||
public TypeAction(ulong timestamp, string text, bool cr) : base(timestamp)
|
||||
{
|
||||
_text = text;
|
||||
_cr = cr;
|
||||
_currentStroke = 0;
|
||||
|
||||
BuildStrokeList(text);
|
||||
}
|
||||
|
||||
public override void Replay(AltoSystem system, ExecutionController controller)
|
||||
{
|
||||
if (_currentStroke >= _strokes.Count)
|
||||
{
|
||||
_completed = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
Keystroke stroke = _strokes[_currentStroke++];
|
||||
|
||||
if (stroke.Type == StrokeType.KeyDown)
|
||||
{
|
||||
system.Keyboard.KeyDown(stroke.Key);
|
||||
}
|
||||
else
|
||||
{
|
||||
system.Keyboard.KeyUp(stroke.Key);
|
||||
}
|
||||
|
||||
// Delay 50ms before the next key
|
||||
_timestamp = 50 * Conversion.MsecToNsec;
|
||||
}
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return String.Format("{0} {1} {2}", _timestamp, _cr ? "TypeLine" : "Type", _text);
|
||||
}
|
||||
|
||||
public static TypeAction Parse(ulong timestamp, bool cr, string[] tokens)
|
||||
{
|
||||
if (tokens.Length < 2)
|
||||
{
|
||||
throw new InvalidOperationException("Invalid TypeAction syntax.");
|
||||
}
|
||||
|
||||
StringBuilder commandString = new StringBuilder();
|
||||
|
||||
for (int i = 2; i < tokens.Length; i++)
|
||||
{
|
||||
commandString.AppendFormat(i == tokens.Length - 1 ? "{0}" : "{0} ", tokens[i]);
|
||||
}
|
||||
|
||||
return new TypeAction(timestamp, commandString.ToString(), cr);
|
||||
|
||||
}
|
||||
|
||||
private void BuildStrokeList(string text)
|
||||
{
|
||||
_strokes = new List<Keystroke>();
|
||||
|
||||
foreach (char c in text)
|
||||
{
|
||||
//
|
||||
// For capital letters or shifted symbols, we need to depress Shift first
|
||||
// (and release it when done).
|
||||
//
|
||||
bool shifted = _shiftedKeyMap.ContainsKey(c);
|
||||
AltoKey charKey;
|
||||
if (shifted)
|
||||
{
|
||||
Keystroke shift = new Keystroke(StrokeType.KeyDown, AltoKey.RShift);
|
||||
_strokes.Add(shift);
|
||||
|
||||
charKey = _shiftedKeyMap[c];
|
||||
}
|
||||
else
|
||||
{
|
||||
if (_unmodifiedKeyMap.ContainsKey(c))
|
||||
{
|
||||
charKey = _unmodifiedKeyMap[c];
|
||||
}
|
||||
else
|
||||
{
|
||||
// Ignore this keystroke.
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
_strokes.Add(new Keystroke(StrokeType.KeyDown, charKey));
|
||||
_strokes.Add(new Keystroke(StrokeType.KeyUp, charKey));
|
||||
|
||||
if (shifted)
|
||||
{
|
||||
Keystroke unshift = new Keystroke(StrokeType.KeyUp, AltoKey.RShift);
|
||||
_strokes.Add(unshift);
|
||||
}
|
||||
}
|
||||
|
||||
if (_cr)
|
||||
{
|
||||
// Add a Return keystroke to the end
|
||||
_strokes.Add(new Keystroke(StrokeType.KeyDown, AltoKey.Return));
|
||||
_strokes.Add(new Keystroke(StrokeType.KeyUp, AltoKey.Return));
|
||||
}
|
||||
}
|
||||
|
||||
private enum StrokeType
|
||||
{
|
||||
KeyDown,
|
||||
KeyUp
|
||||
}
|
||||
|
||||
private struct Keystroke
|
||||
{
|
||||
public Keystroke(StrokeType type, AltoKey key)
|
||||
{
|
||||
Type = type;
|
||||
Key = key;
|
||||
}
|
||||
|
||||
public StrokeType Type;
|
||||
public AltoKey Key;
|
||||
}
|
||||
|
||||
|
||||
private static void BuildKeyMap()
|
||||
{
|
||||
_unmodifiedKeyMap = new Dictionary<char, AltoKey>();
|
||||
_shiftedKeyMap = new Dictionary<char, AltoKey>();
|
||||
|
||||
// characters requiring no modifiers
|
||||
_unmodifiedKeyMap.Add('1', AltoKey.D1);
|
||||
_unmodifiedKeyMap.Add('2', AltoKey.D2);
|
||||
_unmodifiedKeyMap.Add('3', AltoKey.D3);
|
||||
_unmodifiedKeyMap.Add('4', AltoKey.D4);
|
||||
_unmodifiedKeyMap.Add('5', AltoKey.D5);
|
||||
_unmodifiedKeyMap.Add('6', AltoKey.D6);
|
||||
_unmodifiedKeyMap.Add('7', AltoKey.D7);
|
||||
_unmodifiedKeyMap.Add('8', AltoKey.D8);
|
||||
_unmodifiedKeyMap.Add('9', AltoKey.D9);
|
||||
_unmodifiedKeyMap.Add('0', AltoKey.D0);
|
||||
_unmodifiedKeyMap.Add('-', AltoKey.Minus);
|
||||
_unmodifiedKeyMap.Add('=', AltoKey.Plus);
|
||||
_unmodifiedKeyMap.Add('\\', AltoKey.BSlash);
|
||||
_unmodifiedKeyMap.Add('q', AltoKey.Q);
|
||||
_unmodifiedKeyMap.Add('w', AltoKey.W);
|
||||
_unmodifiedKeyMap.Add('e', AltoKey.E);
|
||||
_unmodifiedKeyMap.Add('r', AltoKey.R);
|
||||
_unmodifiedKeyMap.Add('t', AltoKey.T);
|
||||
_unmodifiedKeyMap.Add('y', AltoKey.Y);
|
||||
_unmodifiedKeyMap.Add('u', AltoKey.U);
|
||||
_unmodifiedKeyMap.Add('i', AltoKey.I);
|
||||
_unmodifiedKeyMap.Add('o', AltoKey.O);
|
||||
_unmodifiedKeyMap.Add('p', AltoKey.P);
|
||||
_unmodifiedKeyMap.Add('[', AltoKey.LBracket);
|
||||
_unmodifiedKeyMap.Add(']', AltoKey.RBracket);
|
||||
_unmodifiedKeyMap.Add('_', AltoKey.Arrow);
|
||||
_unmodifiedKeyMap.Add('a', AltoKey.A);
|
||||
_unmodifiedKeyMap.Add('s', AltoKey.S);
|
||||
_unmodifiedKeyMap.Add('d', AltoKey.D);
|
||||
_unmodifiedKeyMap.Add('f', AltoKey.F);
|
||||
_unmodifiedKeyMap.Add('g', AltoKey.G);
|
||||
_unmodifiedKeyMap.Add('h', AltoKey.H);
|
||||
_unmodifiedKeyMap.Add('j', AltoKey.J);
|
||||
_unmodifiedKeyMap.Add('k', AltoKey.K);
|
||||
_unmodifiedKeyMap.Add('l', AltoKey.L);
|
||||
_unmodifiedKeyMap.Add(';', AltoKey.Semicolon);
|
||||
_unmodifiedKeyMap.Add('\'', AltoKey.Quote);
|
||||
_unmodifiedKeyMap.Add('z', AltoKey.Z);
|
||||
_unmodifiedKeyMap.Add('x', AltoKey.X);
|
||||
_unmodifiedKeyMap.Add('c', AltoKey.C);
|
||||
_unmodifiedKeyMap.Add('v', AltoKey.V);
|
||||
_unmodifiedKeyMap.Add('b', AltoKey.B);
|
||||
_unmodifiedKeyMap.Add('n', AltoKey.N);
|
||||
_unmodifiedKeyMap.Add('m', AltoKey.M);
|
||||
_unmodifiedKeyMap.Add(',', AltoKey.Comma);
|
||||
_unmodifiedKeyMap.Add('.', AltoKey.Period);
|
||||
_unmodifiedKeyMap.Add('/', AltoKey.FSlash);
|
||||
_unmodifiedKeyMap.Add(' ', AltoKey.Space);
|
||||
|
||||
// characters requiring a shift modifier
|
||||
_shiftedKeyMap.Add('!', AltoKey.D1);
|
||||
_shiftedKeyMap.Add('@', AltoKey.D2);
|
||||
_shiftedKeyMap.Add('#', AltoKey.D3);
|
||||
_shiftedKeyMap.Add('$', AltoKey.D4);
|
||||
_shiftedKeyMap.Add('%', AltoKey.D5);
|
||||
_shiftedKeyMap.Add('~', AltoKey.D6);
|
||||
_shiftedKeyMap.Add('&', AltoKey.D7);
|
||||
_shiftedKeyMap.Add('*', AltoKey.D8);
|
||||
_shiftedKeyMap.Add('(', AltoKey.D9);
|
||||
_shiftedKeyMap.Add(')', AltoKey.D0);
|
||||
_shiftedKeyMap.Add('|', AltoKey.BSlash);
|
||||
_shiftedKeyMap.Add('Q', AltoKey.Q);
|
||||
_shiftedKeyMap.Add('W', AltoKey.W);
|
||||
_shiftedKeyMap.Add('E', AltoKey.E);
|
||||
_shiftedKeyMap.Add('R', AltoKey.R);
|
||||
_shiftedKeyMap.Add('T', AltoKey.T);
|
||||
_shiftedKeyMap.Add('Y', AltoKey.Y);
|
||||
_shiftedKeyMap.Add('U', AltoKey.U);
|
||||
_shiftedKeyMap.Add('I', AltoKey.I);
|
||||
_shiftedKeyMap.Add('O', AltoKey.O);
|
||||
_shiftedKeyMap.Add('P', AltoKey.P);
|
||||
_shiftedKeyMap.Add('{', AltoKey.LBracket);
|
||||
_shiftedKeyMap.Add('}', AltoKey.RBracket);
|
||||
_shiftedKeyMap.Add('^', AltoKey.Arrow);
|
||||
_shiftedKeyMap.Add('A', AltoKey.A);
|
||||
_shiftedKeyMap.Add('S', AltoKey.S);
|
||||
_shiftedKeyMap.Add('D', AltoKey.D);
|
||||
_shiftedKeyMap.Add('F', AltoKey.F);
|
||||
_shiftedKeyMap.Add('G', AltoKey.G);
|
||||
_shiftedKeyMap.Add('H', AltoKey.H);
|
||||
_shiftedKeyMap.Add('J', AltoKey.J);
|
||||
_shiftedKeyMap.Add('K', AltoKey.K);
|
||||
_shiftedKeyMap.Add('L', AltoKey.L);
|
||||
_shiftedKeyMap.Add(':', AltoKey.Semicolon);
|
||||
_shiftedKeyMap.Add('"', AltoKey.Quote);
|
||||
_shiftedKeyMap.Add('Z', AltoKey.Z);
|
||||
_shiftedKeyMap.Add('X', AltoKey.X);
|
||||
_shiftedKeyMap.Add('C', AltoKey.C);
|
||||
_shiftedKeyMap.Add('V', AltoKey.V);
|
||||
_shiftedKeyMap.Add('B', AltoKey.B);
|
||||
_shiftedKeyMap.Add('N', AltoKey.N);
|
||||
_shiftedKeyMap.Add('M', AltoKey.M);
|
||||
_shiftedKeyMap.Add('<', AltoKey.Comma);
|
||||
_shiftedKeyMap.Add('>', AltoKey.Period);
|
||||
_shiftedKeyMap.Add('?', AltoKey.FSlash);
|
||||
}
|
||||
|
||||
|
||||
private string _text;
|
||||
private List<Keystroke> _strokes;
|
||||
private int _currentStroke;
|
||||
private bool _cr;
|
||||
|
||||
private static Dictionary<char, AltoKey> _unmodifiedKeyMap;
|
||||
private static Dictionary<char, AltoKey> _shiftedKeyMap;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Causes the Playback engine to wait until the Alto executes a wakeup STARTF.
|
||||
/// </summary>
|
||||
public class WaitAction : ScriptAction
|
||||
{
|
||||
public WaitAction(ulong timestamp) : base(timestamp)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public override void Replay(AltoSystem system, ExecutionController controller)
|
||||
{
|
||||
// This is a no-op.
|
||||
_completed = true;
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return String.Format("{0} Wait", _timestamp);
|
||||
}
|
||||
|
||||
public static WaitAction Parse(ulong timestamp, bool keyDown, string[] tokens)
|
||||
{
|
||||
if (tokens.Length != 2)
|
||||
{
|
||||
throw new InvalidOperationException("Invalid WaitAction syntax.");
|
||||
}
|
||||
|
||||
return new WaitAction(timestamp);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user