1
0
mirror of https://github.com/livingcomputermuseum/ContrAlto.git synced 2026-01-17 08:34:15 +00:00

249 lines
8.0 KiB
C#

using System.Collections.Generic;
using Contralto.Memory;
using Contralto.CPU;
namespace Contralto.IO
{
public enum AltoKey
{
None = 0,
A,
B,
C,
D,
E,
F,
G,
H,
I,
J,
K,
L,
M,
N,
O,
P,
Q,
R,
S,
T,
U,
V,
W,
X,
Y,
Z,
D0,
D1,
D2,
D3,
D4,
D5,
D6,
D7,
D8,
D9,
Space,
Plus,
Minus,
Comma,
Period,
Semicolon,
Quote,
LBracket,
RBracket,
FSlash,
BSlash,
Arrow,
Lock,
LShift,
RShift,
LF,
BS,
DEL,
ESC,
TAB,
CTRL,
Return,
BlankTop,
BlankMiddle,
BlankBottom,
}
public struct AltoKeyBit
{
public AltoKeyBit(int word, ushort mask)
{
Word = word;
Bitmask = mask;
}
public int Word;
public ushort Bitmask;
}
/// <summary>
/// Implements the Alto's keyboard and its encodings. It also provides
/// functionality for automatically pressing boot address key combinations.
/// </summary>
public class Keyboard : IMemoryMappedDevice
{
public Keyboard()
{
InitMap();
Reset();
}
public void Reset()
{
_keyWords = new ushort[4];
_bootKeysPressed = false;
}
public ushort Read(int address, TaskType task, bool extendedMemoryReference)
{
// keyboard word is inverted
return (ushort)~_keyWords[address - 0xfe1c]; // TODO: move to constant.
}
public void Load(int address, ushort data, TaskType task, bool extendedMemoryReference)
{
// nothing
}
public void KeyDown(AltoKey key)
{
//
// If we had been holding boot keys, release them now that a real user is pressing a key.
if (_bootKeysPressed)
{
Reset();
}
AltoKeyBit bits = _keyMap[key];
_keyWords[bits.Word] |= _keyMap[key].Bitmask;
}
public void KeyUp(AltoKey key)
{
AltoKeyBit bits = _keyMap[key];
_keyWords[bits.Word] &= (ushort)~_keyMap[key].Bitmask;
}
public void PressBootKeys(ushort bootAddress, bool netBoot)
{
for (int i = 0; i < 16; i++)
{
if ((bootAddress & (0x8000 >> i)) != 0)
{
KeyDown(_bootKeys[i]);
}
}
if (netBoot)
{
// BS is held for netbooting
KeyDown(AltoKey.BS);
}
_bootKeysPressed = true;
}
public MemoryRange[] Addresses
{
get { return _addresses; }
}
private readonly MemoryRange[] _addresses =
{
new MemoryRange(0xfe1c, 0xfe1f), // 177034-177037
};
private void InitMap()
{
_keyMap = new Dictionary<AltoKey, AltoKeyBit>();
_keyMap.Add(AltoKey.D5, new AltoKeyBit(0, 0x8000));
_keyMap.Add(AltoKey.D4, new AltoKeyBit(0, 0x4000));
_keyMap.Add(AltoKey.D6, new AltoKeyBit(0, 0x2000));
_keyMap.Add(AltoKey.E, new AltoKeyBit(0, 0x1000));
_keyMap.Add(AltoKey.D7, new AltoKeyBit(0, 0x0800));
_keyMap.Add(AltoKey.D, new AltoKeyBit(0, 0x0400));
_keyMap.Add(AltoKey.U, new AltoKeyBit(0, 0x0200));
_keyMap.Add(AltoKey.V, new AltoKeyBit(0, 0x0100));
_keyMap.Add(AltoKey.D0, new AltoKeyBit(0, 0x0080));
_keyMap.Add(AltoKey.K, new AltoKeyBit(0, 0x0040));
_keyMap.Add(AltoKey.Minus, new AltoKeyBit(0, 0x0020));
_keyMap.Add(AltoKey.P, new AltoKeyBit(0, 0x0010));
_keyMap.Add(AltoKey.FSlash, new AltoKeyBit(0, 0x0008));
_keyMap.Add(AltoKey.BSlash, new AltoKeyBit(0, 0x0004));
_keyMap.Add(AltoKey.LF, new AltoKeyBit(0, 0x0002));
_keyMap.Add(AltoKey.BS, new AltoKeyBit(0, 0x0001));
_keyMap.Add(AltoKey.D3, new AltoKeyBit(1, 0x8000));
_keyMap.Add(AltoKey.D2, new AltoKeyBit(1, 0x4000));
_keyMap.Add(AltoKey.W, new AltoKeyBit(1, 0x2000));
_keyMap.Add(AltoKey.Q, new AltoKeyBit(1, 0x1000));
_keyMap.Add(AltoKey.S, new AltoKeyBit(1, 0x0800));
_keyMap.Add(AltoKey.A, new AltoKeyBit(1, 0x0400));
_keyMap.Add(AltoKey.D9, new AltoKeyBit(1, 0x0200));
_keyMap.Add(AltoKey.I, new AltoKeyBit(1, 0x0100));
_keyMap.Add(AltoKey.X, new AltoKeyBit(1, 0x0080));
_keyMap.Add(AltoKey.O, new AltoKeyBit(1, 0x0040));
_keyMap.Add(AltoKey.L, new AltoKeyBit(1, 0x0020));
_keyMap.Add(AltoKey.Comma, new AltoKeyBit(1, 0x0010));
_keyMap.Add(AltoKey.Quote, new AltoKeyBit(1, 0x0008));
_keyMap.Add(AltoKey.RBracket, new AltoKeyBit(1, 0x0004));
_keyMap.Add(AltoKey.BlankMiddle, new AltoKeyBit(1, 0x0002));
_keyMap.Add(AltoKey.BlankTop, new AltoKeyBit(1, 0x0001));
_keyMap.Add(AltoKey.D1, new AltoKeyBit(2, 0x8000));
_keyMap.Add(AltoKey.ESC, new AltoKeyBit(2, 0x4000));
_keyMap.Add(AltoKey.TAB, new AltoKeyBit(2, 0x2000));
_keyMap.Add(AltoKey.F, new AltoKeyBit(2, 0x1000));
_keyMap.Add(AltoKey.CTRL, new AltoKeyBit(2, 0x0800));
_keyMap.Add(AltoKey.C, new AltoKeyBit(2, 0x0400));
_keyMap.Add(AltoKey.J, new AltoKeyBit(2, 0x0200));
_keyMap.Add(AltoKey.B, new AltoKeyBit(2, 0x0100));
_keyMap.Add(AltoKey.Z, new AltoKeyBit(2, 0x0080));
_keyMap.Add(AltoKey.LShift, new AltoKeyBit(2, 0x0040));
_keyMap.Add(AltoKey.Period, new AltoKeyBit(2, 0x0020));
_keyMap.Add(AltoKey.Semicolon, new AltoKeyBit(2, 0x0010));
_keyMap.Add(AltoKey.Return, new AltoKeyBit(2, 0x0008));
_keyMap.Add(AltoKey.Arrow, new AltoKeyBit(2, 0x0004));
_keyMap.Add(AltoKey.DEL, new AltoKeyBit(2, 0x0002));
_keyMap.Add(AltoKey.R, new AltoKeyBit(3, 0x8000));
_keyMap.Add(AltoKey.T, new AltoKeyBit(3, 0x4000));
_keyMap.Add(AltoKey.G, new AltoKeyBit(3, 0x2000));
_keyMap.Add(AltoKey.Y, new AltoKeyBit(3, 0x1000));
_keyMap.Add(AltoKey.H, new AltoKeyBit(3, 0x0800));
_keyMap.Add(AltoKey.D8, new AltoKeyBit(3, 0x0400));
_keyMap.Add(AltoKey.N, new AltoKeyBit(3, 0x0200));
_keyMap.Add(AltoKey.M, new AltoKeyBit(3, 0x0100));
_keyMap.Add(AltoKey.Lock, new AltoKeyBit(3, 0x0080));
_keyMap.Add(AltoKey.Space, new AltoKeyBit(3, 0x0040));
_keyMap.Add(AltoKey.LBracket, new AltoKeyBit(3, 0x0020));
_keyMap.Add(AltoKey.Plus, new AltoKeyBit(3, 0x0010));
_keyMap.Add(AltoKey.RShift, new AltoKeyBit(3, 0x0008));
_keyMap.Add(AltoKey.BlankBottom, new AltoKeyBit(3, 0x0004));
}
private ushort[] _keyWords;
private Dictionary<AltoKey, AltoKeyBit> _keyMap;
/// <summary>
/// The keys used to specify a 16-bit boot address, from MSB to LSB
/// </summary>
private AltoKey[] _bootKeys = new AltoKey[]
{
AltoKey.D3, AltoKey.D2, AltoKey.W, AltoKey.Q, AltoKey.S, AltoKey.A, AltoKey.D9, AltoKey.I,
AltoKey.X, AltoKey.O, AltoKey.L, AltoKey.Comma, AltoKey.Quote, AltoKey.RBracket, AltoKey.BlankMiddle, AltoKey.BlankTop
};
private bool _bootKeysPressed;
}
}