From 338904fffe334a09a5bf44586020231078a9c9f7 Mon Sep 17 00:00:00 2001
From: Thomas Harte <thomas.harte@gmail.com>
Date: Sat, 5 Nov 2016 15:07:57 -0400
Subject: [PATCH] Made similar cleanings of the Electron and Vic.

---
 Machines/Commodore/Vic-20/Typer.cpp           |  87 ++++++++++++++
 Machines/Commodore/Vic-20/Vic20.cpp           | 106 ------------------
 Machines/Commodore/Vic-20/Vic20.hpp           |   4 +-
 Machines/Electron/Electron.cpp                |  95 ----------------
 Machines/Electron/Electron.hpp                |   6 +-
 Machines/Electron/Typer.cpp                   | 100 +++++++++++++++++
 Machines/Oric/Typer.cpp                       |   2 -
 .../Clock Signal.xcodeproj/project.pbxproj    |   8 ++
 8 files changed, 199 insertions(+), 209 deletions(-)
 create mode 100644 Machines/Commodore/Vic-20/Typer.cpp
 create mode 100644 Machines/Electron/Typer.cpp

diff --git a/Machines/Commodore/Vic-20/Typer.cpp b/Machines/Commodore/Vic-20/Typer.cpp
new file mode 100644
index 000000000..efcfbca00
--- /dev/null
+++ b/Machines/Commodore/Vic-20/Typer.cpp
@@ -0,0 +1,87 @@
+//
+//  Typer.cpp
+//  Clock Signal
+//
+//  Created by Thomas Harte on 05/11/2016.
+//  Copyright © 2016 Thomas Harte. All rights reserved.
+//
+
+#include "Vic20.hpp"
+
+uint16_t *Commodore::Vic20::Machine::sequence_for_character(Utility::Typer *typer, char character)
+{
+#define KEYS(...)	{__VA_ARGS__, TerminateSequence}
+#define SHIFT(...)	{KeyLShift, __VA_ARGS__, TerminateSequence}
+#define X			{NotMapped}
+	static Key key_sequences[][3] = {
+		/* NUL */	X,							/* SOH */	X,
+		/* STX */	X,							/* ETX */	X,
+		/* EOT */	X,							/* ENQ */	X,
+		/* ACK */	X,							/* BEL */	X,
+		/* BS */	KEYS(KeyDelete),			/* HT */	X,
+		/* LF */	KEYS(KeyReturn),			/* VT */	X,
+		/* FF */	X,							/* CR */	X,
+		/* SO */	X,							/* SI */	X,
+		/* DLE */	X,							/* DC1 */	X,
+		/* DC2 */	X,							/* DC3 */	X,
+		/* DC4 */	X,							/* NAK */	X,
+		/* SYN */	X,							/* ETB */	X,
+		/* CAN */	X,							/* EM */	X,
+		/* SUB */	X,							/* ESC */	X,
+		/* FS */	X,							/* GS */	X,
+		/* RS */	X,							/* US */	X,
+		/* space */	KEYS(KeySpace),				/* ! */		SHIFT(Key1),
+		/* " */		SHIFT(Key2),				/* # */		SHIFT(Key3),
+		/* $ */		SHIFT(Key4),				/* % */		SHIFT(Key5),
+		/* & */		SHIFT(Key6),				/* ' */		SHIFT(Key7),
+		/* ( */		SHIFT(Key8),				/* ) */		SHIFT(Key9),
+		/* * */		KEYS(KeyAsterisk),			/* + */		KEYS(KeyPlus),
+		/* , */		KEYS(KeyComma),				/* - */		KEYS(KeyDash),
+		/* . */		KEYS(KeyFullStop),			/* / */		KEYS(KeySlash),
+		/* 0 */		KEYS(Key0),					/* 1 */		KEYS(Key1),
+		/* 2 */		KEYS(Key2),					/* 3 */		KEYS(Key3),
+		/* 4 */		KEYS(Key4),					/* 5 */		KEYS(Key5),
+		/* 6 */		KEYS(Key6),					/* 7 */		KEYS(Key7),
+		/* 8 */		KEYS(Key8),					/* 9 */		KEYS(Key9),
+		/* : */		KEYS(KeyColon),				/* ; */		KEYS(KeySemicolon),
+		/* < */		SHIFT(KeyComma),			/* = */		KEYS(KeyEquals),
+		/* > */		SHIFT(KeyFullStop),			/* ? */		SHIFT(KeySlash),
+		/* @ */		KEYS(KeyAt),				/* A */		SHIFT(KeyA),
+		/* B */		SHIFT(KeyB),				/* C */		SHIFT(KeyC),
+		/* D */		SHIFT(KeyD),				/* E */		SHIFT(KeyE),
+		/* F */		SHIFT(KeyF),				/* G */		SHIFT(KeyG),
+		/* H */		SHIFT(KeyH),				/* I */		SHIFT(KeyI),
+		/* J */		SHIFT(KeyJ),				/* K */		SHIFT(KeyK),
+		/* L */		SHIFT(KeyL),				/* M */		SHIFT(KeyM),
+		/* N */		SHIFT(KeyN),				/* O */		SHIFT(KeyO),
+		/* P */		SHIFT(KeyP),				/* Q */		SHIFT(KeyQ),
+		/* R */		SHIFT(KeyR),				/* S */		SHIFT(KeyS),
+		/* T */		SHIFT(KeyT),				/* U */		SHIFT(KeyU),
+		/* V */		SHIFT(KeyV),				/* W */		SHIFT(KeyW),
+		/* X */		SHIFT(KeyX),				/* Y */		SHIFT(KeyY),
+		/* Z */		SHIFT(KeyZ),				/* [ */		SHIFT(KeyColon),
+		/* \ */		X,							/* ] */		SHIFT(KeyFullStop),
+		/* ^ */		X,							/* _ */		X,
+		/* ` */		X,							/* a */		KEYS(KeyA),
+		/* b */		KEYS(KeyB),					/* c */		KEYS(KeyC),
+		/* d */		KEYS(KeyD),					/* e */		KEYS(KeyE),
+		/* f */		KEYS(KeyF),					/* g */		KEYS(KeyG),
+		/* h */		KEYS(KeyH),					/* i */		KEYS(KeyI),
+		/* j */		KEYS(KeyJ),					/* k */		KEYS(KeyK),
+		/* l */		KEYS(KeyL),					/* m */		KEYS(KeyM),
+		/* n */		KEYS(KeyN),					/* o */		KEYS(KeyO),
+		/* p */		KEYS(KeyP),					/* q */		KEYS(KeyQ),
+		/* r */		KEYS(KeyR),					/* s */		KEYS(KeyS),
+		/* t */		KEYS(KeyT),					/* u */		KEYS(KeyU),
+		/* v */		KEYS(KeyV),					/* w */		KEYS(KeyW),
+		/* x */		KEYS(KeyX),					/* y */		KEYS(KeyY),
+		/* z */		KEYS(KeyZ)
+	};
+#undef KEYS
+#undef SHIFT
+#undef X
+
+	if(character > sizeof(key_sequences) / sizeof(*key_sequences)) return nullptr;
+	if(key_sequences[character][0] == NotMapped) return nullptr;
+	return (uint16_t *)key_sequences[character];
+}
diff --git a/Machines/Commodore/Vic-20/Vic20.cpp b/Machines/Commodore/Vic-20/Vic20.cpp
index 5f11246d5..8b803c752 100644
--- a/Machines/Commodore/Vic-20/Vic20.cpp
+++ b/Machines/Commodore/Vic-20/Vic20.cpp
@@ -368,112 +368,6 @@ void Machine::install_disk_rom()
 	}
 }
 
-#pragma mark - Typer
-
-int Machine::get_typer_delay()
-{
-	return get_is_resetting() ? 1*263*60*65 : 0;	// wait a second if resetting
-}
-
-int Machine::get_typer_frequency()
-{
-	return 2*263*65;	// accept a new character every two fields
-}
-
-bool Machine::typer_set_next_character(::Utility::Typer *typer, char character, int phase)
-{
-	if(!phase) clear_all_keys();
-
-	// The following table is arranged in ASCII order
-	Key key_sequences[][3] = {
-		{NotMapped},	{NotMapped},	{NotMapped},	{NotMapped},	{NotMapped},	{NotMapped},	{NotMapped},	{NotMapped},
-		{KeyDelete, TerminateSequence},
-		{NotMapped},
-		{KeyReturn, TerminateSequence},
-		{NotMapped},	{NotMapped},	{NotMapped},	{NotMapped},	{NotMapped},
-		{NotMapped},	{NotMapped},	{NotMapped},	{NotMapped},
-		{NotMapped},	{NotMapped},	{NotMapped},	{NotMapped},
-		{NotMapped},	{NotMapped},	{NotMapped},	{NotMapped},
-		{NotMapped},	{NotMapped},	{NotMapped},	{NotMapped},
-
-		{KeySpace, TerminateSequence},				// space
-
-		{KeyLShift, Key1, TerminateSequence},	{KeyLShift, Key2, TerminateSequence},		// !, "
-		{KeyLShift, Key3, TerminateSequence},	{KeyLShift, Key4, TerminateSequence},		// #, $
-		{KeyLShift, Key5, TerminateSequence},	{KeyLShift, Key6, TerminateSequence},		// %, &
-		{KeyLShift, Key7, TerminateSequence},	{KeyLShift, Key8, TerminateSequence},		// ', (
-		{KeyLShift, Key9, TerminateSequence},	{KeyAsterisk, TerminateSequence},			// ), *
-		{KeyPlus, TerminateSequence},			{KeyComma, TerminateSequence},				// +, ,
-		{KeyDash, TerminateSequence},			{KeyFullStop, TerminateSequence},			// -, .
-		{KeySlash, TerminateSequence},			// /
-
-		{Key0, TerminateSequence},				{Key1, TerminateSequence},					// 0, 1
-		{Key2, TerminateSequence},				{Key3, TerminateSequence},					// 2, 3
-		{Key4, TerminateSequence},				{Key5, TerminateSequence},					// 4, 5
-		{Key6, TerminateSequence},				{Key7, TerminateSequence},					// 6, 7
-		{Key8, TerminateSequence},				{Key9, TerminateSequence},					// 8, 9
-
-		{KeyColon, TerminateSequence},					{KeySemicolon, TerminateSequence},		// :, ;
-		{KeyLShift, KeyComma, TerminateSequence},		{KeyEquals, TerminateSequence},			// <, =
-		{KeyLShift, KeyFullStop, TerminateSequence},	{KeyLShift, KeySlash, TerminateSequence},		// >, ?
-		{KeyAt, TerminateSequence},						// @
-
-		{KeyA, TerminateSequence},	{KeyB, TerminateSequence},	{KeyC, TerminateSequence},	{KeyD, TerminateSequence},	// A, B, C, D
-		{KeyE, TerminateSequence},	{KeyF, TerminateSequence},	{KeyG, TerminateSequence},	{KeyH, TerminateSequence},	// E, F, G, H
-		{KeyI, TerminateSequence},	{KeyJ, TerminateSequence},	{KeyK, TerminateSequence},	{KeyL, TerminateSequence},	// I, J, K L
-		{KeyM, TerminateSequence},	{KeyN, TerminateSequence},	{KeyO, TerminateSequence},	{KeyP, TerminateSequence},	// M, N, O, P
-		{KeyQ, TerminateSequence},	{KeyR, TerminateSequence},	{KeyS, TerminateSequence},	{KeyT, TerminateSequence},	// Q, R, S, T
-		{KeyU, TerminateSequence},	{KeyV, TerminateSequence},	{KeyW, TerminateSequence},	{KeyX, TerminateSequence},	// U, V, W X
-		{KeyY, TerminateSequence},	{KeyZ, TerminateSequence},	// Y, Z
-
-		{KeyLShift, KeyColon, TerminateSequence},		{NotMapped},	// [, '\'
-		{KeyLShift, KeyFullStop, TerminateSequence},	{NotMapped},	// ], ^
-		{NotMapped},									{NotMapped},	// _, `
-
-		{KeyA, TerminateSequence},	{KeyB, TerminateSequence},	{KeyC, TerminateSequence},	{KeyD, TerminateSequence},	// A, B, C, D
-		{KeyE, TerminateSequence},	{KeyF, TerminateSequence},	{KeyG, TerminateSequence},	{KeyH, TerminateSequence},	// E, F, G, H
-		{KeyI, TerminateSequence},	{KeyJ, TerminateSequence},	{KeyK, TerminateSequence},	{KeyL, TerminateSequence},	// I, J, K L
-		{KeyM, TerminateSequence},	{KeyN, TerminateSequence},	{KeyO, TerminateSequence},	{KeyP, TerminateSequence},	// M, N, O, P
-		{KeyQ, TerminateSequence},	{KeyR, TerminateSequence},	{KeyS, TerminateSequence},	{KeyT, TerminateSequence},	// Q, R, S, T
-		{KeyU, TerminateSequence},	{KeyV, TerminateSequence},	{KeyW, TerminateSequence},	{KeyX, TerminateSequence},	// U, V, W X
-		{KeyY, TerminateSequence},	{KeyZ, TerminateSequence},	// Y, Z
-//		{KeyLShift, KeyA, TerminateSequence},					{KeyLShift, KeyB, TerminateSequence},					// a, b
-//		{KeyLShift, KeyC, TerminateSequence},					{KeyLShift, KeyD, TerminateSequence},					// c, d
-//		{KeyLShift, KeyE, TerminateSequence},					{KeyLShift, KeyF, TerminateSequence},					// e, f
-//		{KeyLShift, KeyG, TerminateSequence},					{KeyLShift, KeyH, TerminateSequence},					// g, h
-//		{KeyLShift, KeyI, TerminateSequence},					{KeyLShift, KeyJ, TerminateSequence},					// i, j
-//		{KeyLShift, KeyK, TerminateSequence},					{KeyLShift, KeyL, TerminateSequence},					// k, l
-//		{KeyLShift, KeyM, TerminateSequence},					{KeyLShift, KeyN, TerminateSequence},					// m, n
-//		{KeyLShift, KeyO, TerminateSequence},					{KeyLShift, KeyP, TerminateSequence},					// o, p
-//		{KeyLShift, KeyQ, TerminateSequence},					{KeyLShift, KeyR, TerminateSequence},					// q, r
-//		{KeyLShift, KeyS, TerminateSequence},					{KeyLShift, KeyT, TerminateSequence},					// s, t
-//		{KeyLShift, KeyU, TerminateSequence},					{KeyLShift, KeyV, TerminateSequence},					// u, v
-//		{KeyLShift, KeyW, TerminateSequence},					{KeyLShift, KeyX, TerminateSequence},					// w, x
-//		{KeyLShift, KeyY, TerminateSequence},					{KeyLShift, KeyZ, TerminateSequence},					// y, z
-
-	};
-	Key *key_sequence = nullptr;
-
-	character &= 0x7f;
-	if(character < sizeof(key_sequences) / sizeof(*key_sequences))
-	{
-		key_sequence = key_sequences[character];
-
-		if(key_sequence[0] != NotMapped)
-		{
-			if(phase > 0)
-			{
-				set_key_state(key_sequence[phase-1], true);
-				return key_sequence[phase] == TerminateSequence;
-			}
-			else
-				return false;
-		}
-	}
-
-	return true;
-}
-
 #pragma mark - UserPortVIA
 
 uint8_t UserPortVIA::get_port_input(Port port)
diff --git a/Machines/Commodore/Vic-20/Vic20.hpp b/Machines/Commodore/Vic-20/Vic20.hpp
index 9d1b06110..0c0b1b187 100644
--- a/Machines/Commodore/Vic-20/Vic20.hpp
+++ b/Machines/Commodore/Vic-20/Vic20.hpp
@@ -186,9 +186,7 @@ class Machine:
 		virtual void mos6522_did_change_interrupt_status(void *mos6522);
 
 		// for Utility::TypeRecipient
-		virtual int get_typer_delay();
-		virtual int get_typer_frequency();
-		virtual bool typer_set_next_character(Utility::Typer *typer, char character, int phase);
+		uint16_t *sequence_for_character(Utility::Typer *typer, char character);
 
 		// for Tape::Delegate
 		virtual void tape_did_change_input(Storage::Tape::BinaryTapePlayer *tape);
diff --git a/Machines/Electron/Electron.cpp b/Machines/Electron/Electron.cpp
index 8457a59b1..805700752 100644
--- a/Machines/Electron/Electron.cpp
+++ b/Machines/Electron/Electron.cpp
@@ -1099,98 +1099,3 @@ inline void Tape::run_for_cycles(unsigned int number_of_cycles)
 		}
 	}
 }
-
-#pragma mark - Typer
-
-int Machine::get_typer_delay()
-{
-	return get_is_resetting() ? 625*25*128 : 0;	// wait one second if resetting
-}
-
-int Machine::get_typer_frequency()
-{
-	return 625*128;	// accept a new character every frame
-}
-
-bool Machine::typer_set_next_character(::Utility::Typer *typer, char character, int phase)
-{
-	if(!phase) clear_all_keys();
-
-	// The following table is arranged in ASCII order
-	Key key_sequences[][3] = {
-		{NotMapped},	{NotMapped},	{NotMapped},	{NotMapped},	{NotMapped},	{NotMapped},	{NotMapped},	{NotMapped},
-		{KeyDelete, TerminateSequence},
-		{NotMapped},
-		{KeyReturn, TerminateSequence},
-		{NotMapped},	{NotMapped},	{NotMapped},	{NotMapped},	{NotMapped},
-		{NotMapped},	{NotMapped},	{NotMapped},	{NotMapped},
-		{NotMapped},	{NotMapped},	{NotMapped},	{NotMapped},
-		{NotMapped},	{NotMapped},	{NotMapped},	{NotMapped},
-		{NotMapped},	{NotMapped},	{NotMapped},	{NotMapped},
-
-		{KeySpace, TerminateSequence},				// space
-
-		{KeyShift, Key1, TerminateSequence},			{KeyShift, Key2, TerminateSequence},		// !, "
-		{KeyShift, Key3, TerminateSequence},			{KeyShift, Key4, TerminateSequence},		// #, $
-		{KeyShift, Key5, TerminateSequence},			{KeyShift, Key6, TerminateSequence},		// %, &
-		{KeyShift, Key7, TerminateSequence},			{KeyShift, Key8, TerminateSequence},		// ', (
-		{KeyShift, Key9, TerminateSequence},			{KeyShift, KeyColon, TerminateSequence},	// ), *
-		{KeyShift, KeySemiColon, TerminateSequence},	{KeyComma, TerminateSequence},				// +, ,
-		{KeyMinus, TerminateSequence},					{KeyFullStop, TerminateSequence},			// -, .
-		{KeySlash, TerminateSequence},			// /
-
-		{Key0, TerminateSequence},				{Key1, TerminateSequence},					// 0, 1
-		{Key2, TerminateSequence},				{Key3, TerminateSequence},					// 2, 3
-		{Key4, TerminateSequence},				{Key5, TerminateSequence},					// 4, 5
-		{Key6, TerminateSequence},				{Key7, TerminateSequence},					// 6, 7
-		{Key8, TerminateSequence},				{Key9, TerminateSequence},					// 8, 9
-
-		{KeyColon, TerminateSequence},					{KeySemiColon, TerminateSequence},			// :, ;
-		{KeyShift, KeyComma, TerminateSequence},		{KeyShift, KeyMinus, TerminateSequence},	// <, =
-		{KeyShift, KeyFullStop, TerminateSequence},		{KeyShift, KeySlash, TerminateSequence},	// >, ?
-		{KeyShift, Key0, TerminateSequence},														// @
-
-		{KeyA, TerminateSequence},	{KeyB, TerminateSequence},	{KeyC, TerminateSequence},	{KeyD, TerminateSequence},	// A, B, C, D
-		{KeyE, TerminateSequence},	{KeyF, TerminateSequence},	{KeyG, TerminateSequence},	{KeyH, TerminateSequence},	// E, F, G, H
-		{KeyI, TerminateSequence},	{KeyJ, TerminateSequence},	{KeyK, TerminateSequence},	{KeyL, TerminateSequence},	// I, J, K L
-		{KeyM, TerminateSequence},	{KeyN, TerminateSequence},	{KeyO, TerminateSequence},	{KeyP, TerminateSequence},	// M, N, O, P
-		{KeyQ, TerminateSequence},	{KeyR, TerminateSequence},	{KeyS, TerminateSequence},	{KeyT, TerminateSequence},	// Q, R, S, T
-		{KeyU, TerminateSequence},	{KeyV, TerminateSequence},	{KeyW, TerminateSequence},	{KeyX, TerminateSequence},	// U, V, W X
-		{KeyY, TerminateSequence},	{KeyZ, TerminateSequence},	// Y, Z
-
-		{KeyShift, KeyCopy, TerminateSequence},		{KeyControl, KeyRight, TerminateSequence},	// [, '\'
-		{KeyControl, KeyCopy, TerminateSequence},	{KeyShift, KeyLeft, TerminateSequence},	// ], ^
-		{KeyShift, KeyDown, TerminateSequence},		{NotMapped},	// _, `
-
-		{KeyShift, KeyA, TerminateSequence},	{KeyShift, KeyB, TerminateSequence},	{KeyShift, KeyC, TerminateSequence},	{KeyShift, KeyD, TerminateSequence},	// a, b, c, d
-		{KeyShift, KeyE, TerminateSequence},	{KeyShift, KeyF, TerminateSequence},	{KeyShift, KeyG, TerminateSequence},	{KeyShift, KeyH, TerminateSequence},	// e, f, g, h
-		{KeyShift, KeyI, TerminateSequence},	{KeyShift, KeyJ, TerminateSequence},	{KeyShift, KeyK, TerminateSequence},	{KeyShift, KeyL, TerminateSequence},	// i, j, k, l
-		{KeyShift, KeyM, TerminateSequence},	{KeyShift, KeyN, TerminateSequence},	{KeyShift, KeyO, TerminateSequence},	{KeyShift, KeyP, TerminateSequence},	// m, n, o, p
-		{KeyShift, KeyQ, TerminateSequence},	{KeyShift, KeyR, TerminateSequence},	{KeyShift, KeyS, TerminateSequence},	{KeyShift, KeyT, TerminateSequence},	// q, r, s, t
-		{KeyShift, KeyU, TerminateSequence},	{KeyShift, KeyV, TerminateSequence},	{KeyShift, KeyW, TerminateSequence},	{KeyShift, KeyX, TerminateSequence},	// u, v, w, x
-		{KeyShift, KeyY, TerminateSequence},	{KeyShift, KeyZ, TerminateSequence},	// y, z
-
-		{KeyControl, KeyUp, TerminateSequence},		{KeyShift, KeyRight, TerminateSequence},	// {, |
-		{KeyControl, KeyDown, TerminateSequence},	{KeyControl, KeyLeft, TerminateSequence},	// }, ~
-	};
-	Key *key_sequence = nullptr;
-
-	character &= 0x7f;
-	if(character < sizeof(key_sequences) / sizeof(*key_sequences))
-	{
-		key_sequence = key_sequences[character];
-
-		if(key_sequence[0] != NotMapped)
-		{
-			if(phase > 0)
-			{
-				set_key_state(key_sequence[phase-1], true);
-				return key_sequence[phase] == TerminateSequence;
-			}
-			else
-				return false;
-		}
-	}
-
-	return true;
-}
diff --git a/Machines/Electron/Electron.hpp b/Machines/Electron/Electron.hpp
index b7b02cd61..15c6b7dfc 100644
--- a/Machines/Electron/Electron.hpp
+++ b/Machines/Electron/Electron.hpp
@@ -60,9 +60,9 @@ enum Key: uint16_t {
 	KeyZ			= 0x00c0 | 0x08,	KeyA			= 0x00c0 | 0x04,	KeyQ			= 0x00c0 | 0x02,	Key1			= 0x00c0 | 0x01,
 	KeyShift		= 0x00d0 | 0x08,	KeyControl		= 0x00d0 | 0x04,	KeyFunc			= 0x00d0 | 0x02,	KeyEscape		= 0x00d0 | 0x01,
 
-	KeyBreak		= 0xffff,
+	KeyBreak		= 0xfffd,
 
-	TerminateSequence = 0, NotMapped		= 0xfffe,
+	TerminateSequence = 0xffff, NotMapped		= 0xfffe,
 };
 
 class Tape: public Storage::Tape::TapePlayer {
@@ -174,7 +174,7 @@ class Machine:
 		// for Utility::TypeRecipient
 		virtual int get_typer_delay();
 		virtual int get_typer_frequency();
-		virtual bool typer_set_next_character(Utility::Typer *typer, char character, int phase);
+		uint16_t *sequence_for_character(Utility::Typer *typer, char character);
 
 	private:
 
diff --git a/Machines/Electron/Typer.cpp b/Machines/Electron/Typer.cpp
new file mode 100644
index 000000000..6a01c77dc
--- /dev/null
+++ b/Machines/Electron/Typer.cpp
@@ -0,0 +1,100 @@
+//
+//  Typer.cpp
+//  Clock Signal
+//
+//  Created by Thomas Harte on 05/11/2016.
+//  Copyright © 2016 Thomas Harte. All rights reserved.
+//
+
+#include "Electron.hpp"
+
+int Electron::Machine::get_typer_delay()
+{
+	return get_is_resetting() ? 625*25*128 : 0;	// wait one second if resetting
+}
+
+int Electron::Machine::get_typer_frequency()
+{
+	return 625*128;	// accept a new character every frame
+}
+
+uint16_t *Electron::Machine::sequence_for_character(Utility::Typer *typer, char character)
+{
+#define KEYS(...)	{__VA_ARGS__, TerminateSequence}
+#define SHIFT(...)	{KeyShift, __VA_ARGS__, TerminateSequence}
+#define CTRL(...)	{KeyControl, __VA_ARGS__, TerminateSequence}
+#define X			{NotMapped}
+	static Key key_sequences[][3] = {
+		/* NUL */	X,							/* SOH */	X,
+		/* STX */	X,							/* ETX */	X,
+		/* EOT */	X,							/* ENQ */	X,
+		/* ACK */	X,							/* BEL */	X,
+		/* BS */	KEYS(KeyDelete),			/* HT */	X,
+		/* LF */	KEYS(KeyReturn),			/* VT */	X,
+		/* FF */	X,							/* CR */	X,
+		/* SO */	X,							/* SI */	X,
+		/* DLE */	X,							/* DC1 */	X,
+		/* DC2 */	X,							/* DC3 */	X,
+		/* DC4 */	X,							/* NAK */	X,
+		/* SYN */	X,							/* ETB */	X,
+		/* CAN */	X,							/* EM */	X,
+		/* SUB */	X,							/* ESC */	X,
+		/* FS */	X,							/* GS */	X,
+		/* RS */	X,							/* US */	X,
+		/* space */	KEYS(KeySpace),				/* ! */		SHIFT(Key1),
+		/* " */		SHIFT(Key2),				/* # */		SHIFT(Key3),
+		/* $ */		SHIFT(Key4),				/* % */		SHIFT(Key5),
+		/* & */		SHIFT(Key6),				/* ' */		SHIFT(Key7),
+		/* ( */		SHIFT(Key8),				/* ) */		SHIFT(Key9),
+		/* * */		SHIFT(KeyColon),			/* + */		SHIFT(KeySemiColon),
+		/* , */		KEYS(KeyComma),				/* - */		KEYS(KeyMinus),
+		/* . */		KEYS(KeyFullStop),			/* / */		KEYS(KeySlash),
+		/* 0 */		KEYS(Key0),					/* 1 */		KEYS(Key1),
+		/* 2 */		KEYS(Key2),					/* 3 */		KEYS(Key3),
+		/* 4 */		KEYS(Key4),					/* 5 */		KEYS(Key5),
+		/* 6 */		KEYS(Key6),					/* 7 */		KEYS(Key7),
+		/* 8 */		KEYS(Key8),					/* 9 */		KEYS(Key9),
+		/* : */		KEYS(KeyColon),				/* ; */		KEYS(KeySemiColon),
+		/* < */		SHIFT(KeyComma),			/* = */		SHIFT(KeyMinus),
+		/* > */		SHIFT(KeyFullStop),			/* ? */		SHIFT(KeySlash),
+		/* @ */		SHIFT(Key0),				/* A */		KEYS(KeyA),
+		/* B */		KEYS(KeyB),					/* C */		KEYS(KeyC),
+		/* D */		KEYS(KeyD),					/* E */		KEYS(KeyE),
+		/* F */		KEYS(KeyF),					/* G */		KEYS(KeyG),
+		/* H */		KEYS(KeyH),					/* I */		KEYS(KeyI),
+		/* J */		KEYS(KeyJ),					/* K */		KEYS(KeyK),
+		/* L */		KEYS(KeyL),					/* M */		KEYS(KeyM),
+		/* N */		KEYS(KeyN),					/* O */		KEYS(KeyO),
+		/* P */		KEYS(KeyP),					/* Q */		KEYS(KeyQ),
+		/* R */		KEYS(KeyR),					/* S */		KEYS(KeyS),
+		/* T */		KEYS(KeyT),					/* U */		KEYS(KeyU),
+		/* V */		KEYS(KeyV),					/* W */		KEYS(KeyW),
+		/* X */		KEYS(KeyX),					/* Y */		KEYS(KeyY),
+		/* Z */		KEYS(KeyZ),					/* [ */		SHIFT(KeyCopy),
+		/* \ */		CTRL(KeyRight),				/* ] */		CTRL(KeyCopy),
+		/* ^ */		SHIFT(KeyLeft),				/* _ */		SHIFT(KeyDown),
+		/* ` */		X,							/* a */		SHIFT(KeyA),
+		/* b */		SHIFT(KeyB),				/* c */		SHIFT(KeyC),
+		/* d */		SHIFT(KeyD),				/* e */		SHIFT(KeyE),
+		/* f */		SHIFT(KeyF),				/* g */		SHIFT(KeyG),
+		/* h */		SHIFT(KeyH),				/* i */		SHIFT(KeyI),
+		/* j */		SHIFT(KeyJ),				/* k */		SHIFT(KeyK),
+		/* l */		SHIFT(KeyL),				/* m */		SHIFT(KeyM),
+		/* n */		SHIFT(KeyN),				/* o */		SHIFT(KeyO),
+		/* p */		SHIFT(KeyP),				/* q */		SHIFT(KeyQ),
+		/* r */		SHIFT(KeyR),				/* s */		SHIFT(KeyS),
+		/* t */		SHIFT(KeyT),				/* u */		SHIFT(KeyU),
+		/* v */		SHIFT(KeyV),				/* w */		SHIFT(KeyW),
+		/* x */		SHIFT(KeyX),				/* y */		SHIFT(KeyY),
+		/* z */		SHIFT(KeyZ),				/* { */		CTRL(KeyUp),
+		/* | */		SHIFT(KeyRight),			/* } */		CTRL(KeyDown),
+		/* ~ */		CTRL(KeyLeft)
+	};
+#undef KEYS
+#undef SHIFT
+#undef X
+
+	if(character > sizeof(key_sequences) / sizeof(*key_sequences)) return nullptr;
+	if(key_sequences[character][0] == NotMapped) return nullptr;
+	return (uint16_t *)key_sequences[character];
+}
diff --git a/Machines/Oric/Typer.cpp b/Machines/Oric/Typer.cpp
index 492068880..bcd1361a9 100644
--- a/Machines/Oric/Typer.cpp
+++ b/Machines/Oric/Typer.cpp
@@ -5,8 +5,6 @@ uint16_t *Oric::Machine::sequence_for_character(Utility::Typer *typer, char char
 #define KEYS(...)	{__VA_ARGS__, TerminateSequence}
 #define SHIFT(...)	{KeyLeftShift, __VA_ARGS__, TerminateSequence}
 #define X			{NotMapped}
-
-	// The following table is arranged in ASCII order
 	static Key key_sequences[][3] = {
 		/* NUL */	X,							/* SOH */	X,
 		/* STX */	X,							/* ETX */	X,
diff --git a/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj b/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj
index e3918bc36..02cee0d91 100644
--- a/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj	
+++ b/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj	
@@ -358,6 +358,8 @@
 		4BC76E6B1C98F43700E6EF73 /* Accelerate.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4BC76E6A1C98F43700E6EF73 /* Accelerate.framework */; };
 		4BC830D11D6E7C690000A26F /* Tape.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4BC830CF1D6E7C690000A26F /* Tape.cpp */; };
 		4BC8A62A1DCE4F2700DAC693 /* Typer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4BC8A6291DCE4F2700DAC693 /* Typer.cpp */; };
+		4BC8A62D1DCE60E000DAC693 /* Typer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4BC8A62B1DCE60E000DAC693 /* Typer.cpp */; };
+		4BC8A62F1DCE63CA00DAC693 /* Typer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4BC8A62E1DCE63CA00DAC693 /* Typer.cpp */; };
 		4BC91B831D1F160E00884B76 /* CommodoreTAP.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4BC91B811D1F160E00884B76 /* CommodoreTAP.cpp */; };
 		4BC9DF451D044FCA00F44158 /* ROMImages in Resources */ = {isa = PBXBuildFile; fileRef = 4BC9DF441D044FCA00F44158 /* ROMImages */; };
 		4BC9DF4F1D04691600F44158 /* 6560.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4BC9DF4D1D04691600F44158 /* 6560.cpp */; };
@@ -833,6 +835,8 @@
 		4BC830CF1D6E7C690000A26F /* Tape.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Tape.cpp; path = ../../StaticAnalyser/Commodore/Tape.cpp; sourceTree = "<group>"; };
 		4BC830D01D6E7C690000A26F /* Tape.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = Tape.hpp; path = ../../StaticAnalyser/Commodore/Tape.hpp; sourceTree = "<group>"; };
 		4BC8A6291DCE4F2700DAC693 /* Typer.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Typer.cpp; path = Oric/Typer.cpp; sourceTree = "<group>"; };
+		4BC8A62B1DCE60E000DAC693 /* Typer.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Typer.cpp; path = Electron/Typer.cpp; sourceTree = "<group>"; };
+		4BC8A62E1DCE63CA00DAC693 /* Typer.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Typer.cpp; sourceTree = "<group>"; };
 		4BC91B811D1F160E00884B76 /* CommodoreTAP.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CommodoreTAP.cpp; sourceTree = "<group>"; };
 		4BC91B821D1F160E00884B76 /* CommodoreTAP.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = CommodoreTAP.hpp; sourceTree = "<group>"; };
 		4BC9DF441D044FCA00F44158 /* ROMImages */ = {isa = PBXFileReference; lastKnownFileType = folder; name = ROMImages; path = ../../../../ROMImages; sourceTree = "<group>"; };
@@ -1022,6 +1026,7 @@
 				4B2E2D9C1C3A070400138695 /* Electron.hpp */,
 				4B30512E1D98ACC600B4FED8 /* Plus3.cpp */,
 				4B30512F1D98ACC600B4FED8 /* Plus3.hpp */,
+				4BC8A62B1DCE60E000DAC693 /* Typer.cpp */,
 			);
 			name = Electron;
 			sourceTree = "<group>";
@@ -1088,6 +1093,7 @@
 			children = (
 				4B4DC81F1D2C2425003C5BF8 /* Vic20.cpp */,
 				4B4DC8201D2C2425003C5BF8 /* Vic20.hpp */,
+				4BC8A62E1DCE63CA00DAC693 /* Typer.cpp */,
 			);
 			path = "Vic-20";
 			sourceTree = "<group>";
@@ -2237,6 +2243,7 @@
 				4BBF99151C8FBA6F0075DAFB /* CRTOpenGL.cpp in Sources */,
 				4B0CCC451C62D0B3001CAC5F /* CRT.cpp in Sources */,
 				4BCF1FA41DADC3DD0039D2E7 /* Oric.cpp in Sources */,
+				4BC8A62D1DCE60E000DAC693 /* Typer.cpp in Sources */,
 				4B643F3F1D77B88000D431D6 /* DocumentController.swift in Sources */,
 				4BA799951D8B656E0045123D /* StaticAnalyser.cpp in Sources */,
 				4BF829601D8F3C87001BAE39 /* CRC.cpp in Sources */,
@@ -2304,6 +2311,7 @@
 				4BCF1FAB1DADD41B0039D2E7 /* StaticAnalyser.cpp in Sources */,
 				4B2A539F1D117D36003C6002 /* CSAudioQueue.m in Sources */,
 				4B37EE821D7345A6006A09A4 /* BinaryDump.cpp in Sources */,
+				4BC8A62F1DCE63CA00DAC693 /* Typer.cpp in Sources */,
 				4BB73EA21B587A5100552FC2 /* AppDelegate.swift in Sources */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;