1
0
mirror of https://github.com/livingcomputermuseum/sImlac.git synced 2026-01-15 16:07:31 +00:00

322 lines
9.5 KiB
C#

/*
This file is part of sImlac.
sImlac is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
sImlac is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with sImlac. If not, see <http://www.gnu.org/licenses/>.
*/
using System;
using System.Collections.Generic;
namespace imlac.IO
{
[Flags]
public enum ImlacKeyModifiers
{
None = 0x000,
Shift = 0x100,
Ctrl = 0x200,
Rept = 0x400,
}
public enum ImlacKey
{
None = 0x0,
DataXmit = 0x2,
Down = 0x4,
Right = 0x5,
Up = 0x6,
Left = 0x8,
Tab = 0x9,
CR = 0x0d,
FF = 0x0c,
LF = 0x0a,
PageXmit = 0xe,
Home = 0xf,
Brk = 0x19,
Esc = 0x1b,
Space = 0x20,
Comma = 0x2c,
Minus = 0x2d,
Period = 0x2e,
Slash = 0x2f,
K0 = 0x30,
K1 = 0x31,
K2 = 0x32,
K3 = 0x33,
K4 = 0x34,
K5 = 0x35,
K6 = 0x36,
K7 = 0x37,
K8 = 0x38,
K9 = 0x39,
Colon = 0x3a,
Semicolon = 0x3b,
D0 = 0x18,
D2 = 0x1a,
D4 = 0x1c,
D5 = 0x1d,
D6 = 0x1e,
Unlabeled = 0x1f,
A = 0x61,
B = 0x62,
C = 0x63,
D = 0x64,
E = 0x65,
F = 0x66,
G = 0x67,
H = 0x68,
I = 0x69,
J = 0x6a,
K = 0x6b,
L = 0x6c,
M = 0x6d,
N = 0x6e,
O = 0x6f,
P = 0x70,
Q = 0x71,
R = 0x72,
S = 0x73,
T = 0x74,
U = 0x75,
V = 0x76,
W = 0x77,
X = 0x78,
Y = 0x79,
Z = 0x7a,
Del = 0x7f,
Invalid = 0xff,
}
public class Keyboard : IIOTDevice
{
public Keyboard(ImlacSystem system)
{
_system = system;
Reset();
}
static Keyboard()
{
BuildKeyMappings();
}
public void Clock()
{
// If we do not already have a key latched and one has been pressed,
// we will raise the Ready flag now.
if (!_keyReady)
{
if (_system.Display.NewKeyPressed)
{
_keyReady = true;
}
}
}
public void Reset()
{
_keyReady = false;
}
public int[] GetHandledIOTs()
{
return _handledIOTs;
}
public bool KeyReady
{
get { return _keyReady; }
}
public void ExecuteIOT(int iotCode)
{
switch (iotCode)
{
case 0x11:
_system.Processor.AC |= GetScancodeForCurrentKey();
Trace.Log(LogType.Keyboard, "Key OR'd into AC {0}", Helpers.ToOctal(_system.Processor.AC));
break;
case 0x12:
_keyReady = false;
_system.Display.UnlatchKey();
Trace.Log(LogType.Keyboard, "Keyboard flag reset.");
break;
case 0x13:
_system.Processor.AC |= GetScancodeForCurrentKey();
_keyReady = false;
_system.Display.UnlatchKey();
Trace.Log(LogType.Keyboard, "Key OR'd into AC {0}, keyboard flag reset.", Helpers.ToOctal(_system.Processor.AC));
break;
}
}
private ushort GetScancodeForCurrentKey()
{
ushort scanCode = 0;
ImlacKey key = _system.Display.Key;
ImlacKeyModifiers modifiers = _system.Display.KeyModifiers;
Trace.Log(LogType.Keyboard, "Keypress is {0}", key);
if (key != ImlacKey.Invalid)
{
scanCode = (modifiers & ImlacKeyModifiers.Shift) != 0 ? _keyMappings[key].ShiftedCode : _keyMappings[key].NormalCode;
if (scanCode == 0)
{
// no code for shifted key, just use normal one.
scanCode = _keyMappings[key].NormalCode;
}
// bit 8 is always set
scanCode = (ushort)(scanCode | 0x80);
//
// The Repeat, Control, and Shift keys correspond to bits 5, 6, and 7 of the
// scancode returned.
//
if ((modifiers & ImlacKeyModifiers.Rept) != 0)
{
scanCode |= 0x400;
}
if ((modifiers & ImlacKeyModifiers.Ctrl) != 0)
{
scanCode |= 0x200;
}
if ((modifiers & ImlacKeyModifiers.Shift) != 0)
{
scanCode |= 0x100;
}
Trace.Log(LogType.Keyboard, "Final keycode is {0}", Helpers.ToOctal(scanCode));
}
return scanCode;
}
private readonly int[] _handledIOTs = { 0x11, 0x12, 0x13 };
private bool _keyReady;
private ImlacSystem _system;
private struct ImlacKeyMapping
{
public ImlacKeyMapping(ImlacKey key, byte normal, byte shifted)
{
Key = key;
NormalCode = normal;
ShiftedCode = shifted;
}
public ImlacKey Key;
public byte NormalCode;
public byte ShiftedCode;
}
private static void BuildKeyMappings()
{
_keyMappings = new Dictionary<ImlacKey, ImlacKeyMapping>();
AddMapping(ImlacKey.None, 0x0, 0x0);
AddMapping(ImlacKey.DataXmit, 0x2, 0x0);
AddMapping(ImlacKey.Down, 0x4, 0x0);
AddMapping(ImlacKey.Right, 0x5, 0x0);
AddMapping(ImlacKey.Up, 0x6, 0x0);
AddMapping(ImlacKey.Left, 0x8, 0x0);
AddMapping(ImlacKey.Tab, 0x9, 0x0);
AddMapping(ImlacKey.CR, 0x0d, 0x0);
AddMapping(ImlacKey.FF, 0x0c, 0x0);
AddMapping(ImlacKey.LF, 0x0a, 0x0);
AddMapping(ImlacKey.PageXmit, 0xe, 0x0);
AddMapping(ImlacKey.Home, 0xf, 0x0);
AddMapping(ImlacKey.Brk, 0x19, 0x0);
AddMapping(ImlacKey.Esc, 0x1b, 0x0);
AddMapping(ImlacKey.Space, 0x20, 0x0);
AddMapping(ImlacKey.Comma, 0x2c, 0x3c);
AddMapping(ImlacKey.Minus, 0x2d, 0x3d);
AddMapping(ImlacKey.Period, 0x2e, 0x3e);
AddMapping(ImlacKey.Slash, 0x2f, 0x3f);
AddMapping(ImlacKey.K0, 0x30, 0x0);
AddMapping(ImlacKey.K1, 0x31, 0x21);
AddMapping(ImlacKey.K2, 0x32, 0x22);
AddMapping(ImlacKey.K3, 0x33, 0x23);
AddMapping(ImlacKey.K4, 0x34, 0x24);
AddMapping(ImlacKey.K5, 0x35, 0x25);
AddMapping(ImlacKey.K6, 0x36, 0x26);
AddMapping(ImlacKey.K7, 0x37, 0x27);
AddMapping(ImlacKey.K8, 0x38, 0x28);
AddMapping(ImlacKey.K9, 0x39, 0x29);
AddMapping(ImlacKey.Colon, 0x3a, 0x2a);
AddMapping(ImlacKey.Semicolon, 0x3b, 0x2b);
AddMapping(ImlacKey.D0, 0x18, 0x0);
AddMapping(ImlacKey.D2, 0x1a, 0x0);
AddMapping(ImlacKey.D4, 0x1c, 0x0);
AddMapping(ImlacKey.D5, 0x1d, 0x0);
AddMapping(ImlacKey.D6, 0x1e, 0x0);
AddMapping(ImlacKey.Unlabeled, 0x1f, 0x0);
AddMapping(ImlacKey.A, 0x61, 0x41);
AddMapping(ImlacKey.B, 0x62, 0x42);
AddMapping(ImlacKey.C, 0x63, 0x43);
AddMapping(ImlacKey.D, 0x64, 0x44);
AddMapping(ImlacKey.E, 0x65, 0x45);
AddMapping(ImlacKey.F, 0x66, 0x46);
AddMapping(ImlacKey.G, 0x67, 0x47);
AddMapping(ImlacKey.H, 0x68, 0x48);
AddMapping(ImlacKey.I, 0x69, 0x49);
AddMapping(ImlacKey.J, 0x6a, 0x4a);
AddMapping(ImlacKey.K, 0x6b, 0x4b);
AddMapping(ImlacKey.L, 0x6c, 0x4c);
AddMapping(ImlacKey.M, 0x6d, 0x4d);
AddMapping(ImlacKey.N, 0x6e, 0x4e);
AddMapping(ImlacKey.O, 0x6f, 0x4f);
AddMapping(ImlacKey.P, 0x70, 0x50);
AddMapping(ImlacKey.Q, 0x71, 0x51);
AddMapping(ImlacKey.R, 0x72, 0x52);
AddMapping(ImlacKey.S, 0x73, 0x53);
AddMapping(ImlacKey.T, 0x74, 0x54);
AddMapping(ImlacKey.U, 0x75, 0x55);
AddMapping(ImlacKey.V, 0x76, 0x56);
AddMapping(ImlacKey.W, 0x77, 0x57);
AddMapping(ImlacKey.X, 0x78, 0x58);
AddMapping(ImlacKey.Y, 0x79, 0x59);
AddMapping(ImlacKey.Z, 0x7a, 0x5a);
AddMapping(ImlacKey.Del, 0x7f, 0x0);
}
private static void AddMapping(ImlacKey key, byte normal, byte shifted)
{
_keyMappings.Add(key, new ImlacKeyMapping(key, normal, shifted));
}
private static Dictionary<ImlacKey, ImlacKeyMapping> _keyMappings;
}
}