From edb632af5276c005b639941e322a1b6d82f3021f Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Mon, 9 Oct 2017 22:26:39 -0400 Subject: [PATCH 01/16] Sketches first design for generalising keyboard input. --- Inputs/Keyboard.cpp | 38 ++++++++++++ Inputs/Keyboard.hpp | 60 +++++++++++++++++++ .../Clock Signal.xcodeproj/project.pbxproj | 15 +++++ 3 files changed, 113 insertions(+) create mode 100644 Inputs/Keyboard.cpp create mode 100644 Inputs/Keyboard.hpp diff --git a/Inputs/Keyboard.cpp b/Inputs/Keyboard.cpp new file mode 100644 index 000000000..c479c6a7f --- /dev/null +++ b/Inputs/Keyboard.cpp @@ -0,0 +1,38 @@ +// +// Keyboard.cpp +// Clock Signal +// +// Created by Thomas Harte on 10/9/17. +// Copyright © 2017 Thomas Harte. All rights reserved. +// + +#include "Keyboard.hpp" + +using namespace Inputs; + +Keyboard::Keyboard() {} + +void Keyboard::set_key_pressed(Key key, bool is_pressed) { + size_t key_offset = static_cast(key); + if(key_offset > key_states_.size()) { + key_states_.resize(key_offset, false); + } + key_states_[key_offset] = is_pressed; + + if(delegate_) delegate_->keyboard_did_change_key(this, key, is_pressed); +} + +void Keyboard::reset_all_keys() { + std::fill(key_states_.begin(), key_states_.end(), false); + if(delegate_) delegate_->reset_all_keys(); +} + +void Keyboard::set_delegate(Delegate *delegate) { + delegate_ = delegate; +} + +bool Keyboard::get_key_state(Key key) { + size_t key_offset = static_cast(key); + if(key_offset >= key_states_.size()) return false; + return key_states_[key_offset]; +} diff --git a/Inputs/Keyboard.hpp b/Inputs/Keyboard.hpp new file mode 100644 index 000000000..85b1ba883 --- /dev/null +++ b/Inputs/Keyboard.hpp @@ -0,0 +1,60 @@ +// +// Keyboard.hpp +// Clock Signal +// +// Created by Thomas Harte on 10/9/17. +// Copyright © 2017 Thomas Harte. All rights reserved. +// + +#ifndef Keyboard_hpp +#define Keyboard_hpp + +#include + +namespace Inputs { + +/*! + Provides an intermediate idealised model of a modern-era computer keyboard + (so, heavily indebted to the current Windows and Mac layouts), allowing a host + machine to toggle states, while an interested party either observes or polls. +*/ +class Keyboard { + public: + Keyboard(); + + enum class Key { + Escape, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12, PrintScreen, ScrollLock, Pause, + BackTick, k1, k2, k3, k4, k5, k6, k7, k8, k9, k0, Hyphen, Equals, BackSpace, + Tab, Q, W, E, R, T, Y, U, I, O, P, OpenSquareBracket, CloseSquareBracket, BackSlash, + CapsLock, A, S, D, F, G, H, J, K, L, Semicolon, Quote, Hash, Enter, + LeftShift, Z, X, C, V, B, N, M, Comma, FullStop, ForwardSlash, RightShift, + LeftControl, LeftOption, LeftMeta, Space, RightMeta, RightOption, + Left, Right, Up, Down, + Insert, Home, PageUp, Delete, End, PageDown, + NumLock, KeyPadSlash, KeyPadAsterisk, KeyPadDelete, + KeyPad7, KeyPad8, KeyPad9, KeyPadPlus, + KeyPad4, KeyPad5, KeyPad6, + KeyPad1, KeyPad2, KeyPad3, KeyPadEnter, + KeyPad0, KeyPadDecimalPoint + }; + + // Host interface. + void set_key_pressed(Key key, bool is_pressed); + void reset_all_keys(); + + // Delegate interface. + struct Delegate { + virtual void keyboard_did_change_key(Keyboard *keyboard, Key key, bool is_pressed) = 0; + virtual void reset_all_keys() = 0; + }; + void set_delegate(Delegate *delegate); + bool get_key_state(Key key); + + private: + std::vector key_states_; + Delegate *delegate_ = nullptr; +}; + +} + +#endif /* Keyboard_hpp */ diff --git a/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj b/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj index 704fd7b91..20c740482 100644 --- a/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj +++ b/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj @@ -115,6 +115,7 @@ 4B8378DF1F33675F005CA9E4 /* CharacterMapper.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B8378DD1F33675F005CA9E4 /* CharacterMapper.cpp */; }; 4B8378E21F336920005CA9E4 /* CharacterMapper.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B8378E01F336920005CA9E4 /* CharacterMapper.cpp */; }; 4B8378E51F3378C4005CA9E4 /* CharacterMapper.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B8378E31F3378C4005CA9E4 /* CharacterMapper.cpp */; }; + 4B86E25B1F8C628F006FAA45 /* Keyboard.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B86E2591F8C628F006FAA45 /* Keyboard.cpp */; }; 4B8805F01DCFC99C003085B1 /* Acorn.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B8805EE1DCFC99C003085B1 /* Acorn.cpp */; }; 4B8805F41DCFD22A003085B1 /* Commodore.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B8805F21DCFD22A003085B1 /* Commodore.cpp */; }; 4B8805F71DCFF6C9003085B1 /* Commodore.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B8805F51DCFF6C9003085B1 /* Commodore.cpp */; }; @@ -689,6 +690,8 @@ 4B8378E11F336920005CA9E4 /* CharacterMapper.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = CharacterMapper.hpp; path = Oric/CharacterMapper.hpp; sourceTree = ""; }; 4B8378E31F3378C4005CA9E4 /* CharacterMapper.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CharacterMapper.cpp; sourceTree = ""; }; 4B8378E41F3378C4005CA9E4 /* CharacterMapper.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = CharacterMapper.hpp; sourceTree = ""; }; + 4B86E2591F8C628F006FAA45 /* Keyboard.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Keyboard.cpp; sourceTree = ""; }; + 4B86E25A1F8C628F006FAA45 /* Keyboard.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = Keyboard.hpp; sourceTree = ""; }; 4B8805EE1DCFC99C003085B1 /* Acorn.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Acorn.cpp; path = Parsers/Acorn.cpp; sourceTree = ""; }; 4B8805EF1DCFC99C003085B1 /* Acorn.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = Acorn.hpp; path = Parsers/Acorn.hpp; sourceTree = ""; }; 4B8805F21DCFD22A003085B1 /* Commodore.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Commodore.cpp; path = Parsers/Commodore.cpp; sourceTree = ""; }; @@ -1715,6 +1718,16 @@ name = Implementation; sourceTree = ""; }; + 4B86E2581F8C628F006FAA45 /* Inputs */ = { + isa = PBXGroup; + children = ( + 4B86E2591F8C628F006FAA45 /* Keyboard.cpp */, + 4B86E25A1F8C628F006FAA45 /* Keyboard.hpp */, + ); + name = Inputs; + path = ../../Inputs; + sourceTree = ""; + }; 4B8805F11DCFC9A2003085B1 /* Parsers */ = { isa = PBXGroup; children = ( @@ -2070,6 +2083,7 @@ 4BF660691F281573002CB053 /* ClockReceiver */, 4BC9DF4A1D04691600F44158 /* Components */, 4B3940E81DA83C8700427841 /* Concurrency */, + 4B86E2581F8C628F006FAA45 /* Inputs */, 4BB73EDC1B587CA500552FC2 /* Machines */, 4BB697C81D4B559300248BDF /* NumberTheory */, 4B366DFD1B5C165F0026627B /* Outputs */, @@ -2951,6 +2965,7 @@ 4BC5E4921D7ED365008CF980 /* StaticAnalyser.cpp in Sources */, 4BC830D11D6E7C690000A26F /* Tape.cpp in Sources */, 4B69FB441C4D941400B5F0AA /* TapeUEF.cpp in Sources */, + 4B86E25B1F8C628F006FAA45 /* Keyboard.cpp in Sources */, 4B4518851F75E91A00926311 /* DiskController.cpp in Sources */, 4B8334841F5DA0360097E338 /* Z80Storage.cpp in Sources */, 4BA61EB01D91515900B3C876 /* NSData+StdVector.mm in Sources */, From 78ee46270b1a64a438cb6cdae68b7e276fc457a9 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Thu, 12 Oct 2017 22:25:02 -0400 Subject: [PATCH 02/16] Transfers possession of keyboard mappings from the Mac side over to individual machines. Specifically by establishing an intermediate representation of a useful mix between the American and British IBM and Mac keyboard layouts, and routing through that. --- Inputs/Keyboard.hpp | 11 ++- Machines/AmstradCPC/AmstradCPC.cpp | 6 ++ Machines/AmstradCPC/CharacterMapper.cpp | 6 +- Machines/AmstradCPC/KeyboardMapper.cpp | 76 +++++++++++++++ Machines/AmstradCPC/KeyboardMapper.hpp | 22 +++++ Machines/Commodore/Vic-20/CharacterMapper.cpp | 6 +- Machines/Commodore/Vic-20/KeyboardMapper.cpp | 67 +++++++++++++ Machines/Commodore/Vic-20/KeyboardMapper.hpp | 24 +++++ Machines/Commodore/Vic-20/Vic20.cpp | 6 ++ Machines/Commodore/Vic-20/Vic20.hpp | 2 + Machines/Electron/CharacterMapper.cpp | 8 +- Machines/Electron/Electron.cpp | 6 ++ Machines/Electron/KeyboardMapper.cpp | 57 +++++++++++ Machines/Electron/KeyboardMapper.hpp | 22 +++++ Machines/KeyboardMachine.cpp | 29 ++++++ Machines/KeyboardMachine.hpp | 43 ++++++++- Machines/Oric/CharacterMapper.cpp | 6 +- Machines/Oric/KeyboardMapper.cpp | 53 +++++++++++ Machines/Oric/KeyboardMapper.hpp | 22 +++++ Machines/Oric/Oric.cpp | 12 ++- Machines/Typer.cpp | 6 +- Machines/Typer.hpp | 9 -- Machines/ZX8081/CharacterMapper.cpp | 6 +- Machines/ZX8081/KeyboardMapper.cpp | 35 +++++++ Machines/ZX8081/KeyboardMapper.hpp | 22 +++++ Machines/ZX8081/ZX8081.cpp | 6 ++ .../Clock Signal.xcodeproj/project.pbxproj | 36 ++++++- .../Mac/Clock Signal/Machine/CSMachine.h | 5 + .../Mac/Clock Signal/Machine/CSMachine.mm | 76 +++++++++++++++ .../Machine/Wrappers/CSAmstradCPC.mm | 94 ------------------- .../Machine/Wrappers/CSElectron.mm | 88 ----------------- .../Clock Signal/Machine/Wrappers/CSOric.mm | 93 ------------------ .../Clock Signal/Machine/Wrappers/CSVic20.mm | 30 +----- .../Clock Signal/Machine/Wrappers/CSZX8081.mm | 63 ------------- 34 files changed, 649 insertions(+), 404 deletions(-) create mode 100644 Machines/AmstradCPC/KeyboardMapper.cpp create mode 100644 Machines/AmstradCPC/KeyboardMapper.hpp create mode 100644 Machines/Commodore/Vic-20/KeyboardMapper.cpp create mode 100644 Machines/Commodore/Vic-20/KeyboardMapper.hpp create mode 100644 Machines/Electron/KeyboardMapper.cpp create mode 100644 Machines/Electron/KeyboardMapper.hpp create mode 100644 Machines/KeyboardMachine.cpp create mode 100644 Machines/Oric/KeyboardMapper.cpp create mode 100644 Machines/Oric/KeyboardMapper.hpp create mode 100644 Machines/ZX8081/KeyboardMapper.cpp create mode 100644 Machines/ZX8081/KeyboardMapper.hpp diff --git a/Inputs/Keyboard.hpp b/Inputs/Keyboard.hpp index 85b1ba883..7d480c8c8 100644 --- a/Inputs/Keyboard.hpp +++ b/Inputs/Keyboard.hpp @@ -28,19 +28,20 @@ class Keyboard { Tab, Q, W, E, R, T, Y, U, I, O, P, OpenSquareBracket, CloseSquareBracket, BackSlash, CapsLock, A, S, D, F, G, H, J, K, L, Semicolon, Quote, Hash, Enter, LeftShift, Z, X, C, V, B, N, M, Comma, FullStop, ForwardSlash, RightShift, - LeftControl, LeftOption, LeftMeta, Space, RightMeta, RightOption, + LeftControl, LeftOption, LeftMeta, Space, RightMeta, RightOption, RightControl, Left, Right, Up, Down, Insert, Home, PageUp, Delete, End, PageDown, NumLock, KeyPadSlash, KeyPadAsterisk, KeyPadDelete, KeyPad7, KeyPad8, KeyPad9, KeyPadPlus, - KeyPad4, KeyPad5, KeyPad6, + KeyPad4, KeyPad5, KeyPad6, KeyPadMinus, KeyPad1, KeyPad2, KeyPad3, KeyPadEnter, - KeyPad0, KeyPadDecimalPoint + KeyPad0, KeyPadDecimalPoint, KeyPadEquals, + Help }; // Host interface. - void set_key_pressed(Key key, bool is_pressed); - void reset_all_keys(); + virtual void set_key_pressed(Key key, bool is_pressed); + virtual void reset_all_keys(); // Delegate interface. struct Delegate { diff --git a/Machines/AmstradCPC/AmstradCPC.cpp b/Machines/AmstradCPC/AmstradCPC.cpp index 4c04db4c4..bf19ce094 100644 --- a/Machines/AmstradCPC/AmstradCPC.cpp +++ b/Machines/AmstradCPC/AmstradCPC.cpp @@ -9,6 +9,7 @@ #include "AmstradCPC.hpp" #include "CharacterMapper.hpp" +#include "KeyboardMapper.hpp" #include "../../Processors/Z80/Z80.hpp" @@ -965,6 +966,10 @@ class ConcreteMachine: key_state_.clear_all_keys(); } + KeyboardMapper &get_keyboard_mapper() override { + return keyboard_mapper_; + } + private: inline void write_to_gate_array(uint8_t value) { switch(value >> 6) { @@ -1044,6 +1049,7 @@ class ConcreteMachine: uint8_t *write_pointers_[4]; KeyboardState key_state_; + AmstradCPC::KeyboardMapper keyboard_mapper_; }; } diff --git a/Machines/AmstradCPC/CharacterMapper.cpp b/Machines/AmstradCPC/CharacterMapper.cpp index e1fef2118..1effb650f 100644 --- a/Machines/AmstradCPC/CharacterMapper.cpp +++ b/Machines/AmstradCPC/CharacterMapper.cpp @@ -12,9 +12,9 @@ using namespace AmstradCPC; uint16_t *CharacterMapper::sequence_for_character(char character) { -#define KEYS(...) {__VA_ARGS__, EndSequence} -#define SHIFT(...) {KeyShift, __VA_ARGS__, EndSequence} -#define X {NotMapped} +#define KEYS(...) {__VA_ARGS__, KeyboardMachine::Machine::KeyEndSequence} +#define SHIFT(...) {KeyShift, __VA_ARGS__, KeyboardMachine::Machine::KeyEndSequence} +#define X {KeyboardMachine::Machine::KeyNotMapped} static KeySequence key_sequences[] = { /* NUL */ X, /* SOH */ X, /* STX */ X, /* ETX */ X, diff --git a/Machines/AmstradCPC/KeyboardMapper.cpp b/Machines/AmstradCPC/KeyboardMapper.cpp new file mode 100644 index 000000000..186a4e824 --- /dev/null +++ b/Machines/AmstradCPC/KeyboardMapper.cpp @@ -0,0 +1,76 @@ +// +// KeyboardMapper.cpp +// Clock Signal +// +// Created by Thomas Harte on 10/10/2017. +// Copyright © 2017 Thomas Harte. All rights reserved. +// + +#include "KeyboardMapper.hpp" +#include "AmstradCPC.hpp" + +using namespace AmstradCPC; + +uint16_t KeyboardMapper::mapped_key_for_key(Inputs::Keyboard::Key key) { +#define BIND(source, dest) case Inputs::Keyboard::Key::source: return dest + switch(key) { + default: return KeyCopy; + + BIND(k0, Key0); BIND(k1, Key1); BIND(k2, Key2); BIND(k3, Key3); BIND(k4, Key4); + BIND(k5, Key5); BIND(k6, Key6); BIND(k7, Key7); BIND(k8, Key8); BIND(k9, Key9); + BIND(Q, KeyQ); BIND(W, KeyW); BIND(E, KeyE); BIND(R, KeyR); BIND(T, KeyT); + BIND(Y, KeyY); BIND(U, KeyU); BIND(I, KeyI); BIND(O, KeyO); BIND(P, KeyP); + BIND(A, KeyA); BIND(S, KeyS); BIND(D, KeyD); BIND(F, KeyF); BIND(G, KeyG); + BIND(H, KeyH); BIND(J, KeyJ); BIND(K, KeyK); BIND(L, KeyL); + BIND(Z, KeyZ); BIND(X, KeyX); BIND(C, KeyC); BIND(V, KeyV); + BIND(B, KeyB); BIND(N, KeyN); BIND(M, KeyM); + + BIND(Escape, KeyEscape); + BIND(F1, KeyF1); BIND(F2, KeyF2); BIND(F3, KeyF3); BIND(F4, KeyF4); BIND(F5, KeyF5); + BIND(F6, KeyF6); BIND(F7, KeyF7); BIND(F8, KeyF8); BIND(F9, KeyF9); BIND(F10, KeyF0); + + BIND(F11, KeyRightSquareBracket); + BIND(F12, KeyClear); + + BIND(Hyphen, KeyMinus); BIND(Equals, KeyCaret); BIND(BackSpace, KeyDelete); + BIND(Tab, KeyTab); + + BIND(OpenSquareBracket, KeyAt); + BIND(CloseSquareBracket, KeyLeftSquareBracket); + BIND(BackSlash, KeyBackSlash); + + BIND(CapsLock, KeyCapsLock); + BIND(Semicolon, KeyColon); + BIND(Quote, KeySemicolon); + BIND(Hash, KeyRightSquareBracket); + BIND(Enter, KeyReturn); + + BIND(LeftShift, KeyShift); + BIND(Comma, KeyComma); + BIND(FullStop, KeyFullStop); + BIND(ForwardSlash, KeyForwardSlash); + BIND(RightShift, KeyShift); + + BIND(LeftControl, KeyControl); BIND(LeftOption, KeyControl); BIND(LeftMeta, KeyControl); + BIND(Space, KeySpace); + BIND(RightMeta, KeyControl); BIND(RightOption, KeyControl); BIND(RightControl, KeyControl); + + BIND(Left, KeyLeft); BIND(Right, KeyRight); + BIND(Up, KeyUp); BIND(Down, KeyDown); + + BIND(KeyPad0, KeyF0); + BIND(KeyPad1, KeyF1); BIND(KeyPad2, KeyF2); BIND(KeyPad3, KeyF3); + BIND(KeyPad4, KeyF4); BIND(KeyPad5, KeyF5); BIND(KeyPad6, KeyF6); + BIND(KeyPad7, KeyF7); BIND(KeyPad8, KeyF8); BIND(KeyPad9, KeyF9); + BIND(KeyPadPlus, KeySemicolon); + BIND(KeyPadMinus, KeyMinus); + + BIND(KeyPadEnter, KeyEnter); + BIND(KeyPadDecimalPoint, KeyFullStop); + BIND(KeyPadEquals, KeyMinus); + BIND(KeyPadSlash, KeyForwardSlash); + BIND(KeyPadAsterisk, KeyColon); + BIND(KeyPadDelete, KeyDelete); + } +#undef BIND +} diff --git a/Machines/AmstradCPC/KeyboardMapper.hpp b/Machines/AmstradCPC/KeyboardMapper.hpp new file mode 100644 index 000000000..da848b113 --- /dev/null +++ b/Machines/AmstradCPC/KeyboardMapper.hpp @@ -0,0 +1,22 @@ +// +// KeyboardMapper.hpp +// Clock Signal +// +// Created by Thomas Harte on 10/10/2017. +// Copyright © 2017 Thomas Harte. All rights reserved. +// + +#ifndef Machines_AmstradCPC_KeyboardMapper_hpp +#define Machines_AmstradCPC_KeyboardMapper_hpp + +#include "../KeyboardMachine.hpp" + +namespace AmstradCPC { + +struct KeyboardMapper: public KeyboardMachine::Machine::KeyboardMapper { + uint16_t mapped_key_for_key(Inputs::Keyboard::Key key); +}; + +}; + +#endif /* KeyboardMapper_hpp */ diff --git a/Machines/Commodore/Vic-20/CharacterMapper.cpp b/Machines/Commodore/Vic-20/CharacterMapper.cpp index 35fc4d11a..40c71ac08 100644 --- a/Machines/Commodore/Vic-20/CharacterMapper.cpp +++ b/Machines/Commodore/Vic-20/CharacterMapper.cpp @@ -12,9 +12,9 @@ using namespace Commodore::Vic20; uint16_t *CharacterMapper::sequence_for_character(char character) { -#define KEYS(...) {__VA_ARGS__, EndSequence} -#define SHIFT(...) {KeyLShift, __VA_ARGS__, EndSequence} -#define X {NotMapped} +#define KEYS(...) {__VA_ARGS__, KeyboardMachine::Machine::KeyEndSequence} +#define SHIFT(...) {KeyLShift, __VA_ARGS__, KeyboardMachine::Machine::KeyEndSequence} +#define X {KeyboardMachine::Machine::KeyNotMapped} static KeySequence key_sequences[] = { /* NUL */ X, /* SOH */ X, /* STX */ X, /* ETX */ X, diff --git a/Machines/Commodore/Vic-20/KeyboardMapper.cpp b/Machines/Commodore/Vic-20/KeyboardMapper.cpp new file mode 100644 index 000000000..98e82b589 --- /dev/null +++ b/Machines/Commodore/Vic-20/KeyboardMapper.cpp @@ -0,0 +1,67 @@ +// +// KeyboardMapper.cpp +// Clock Signal +// +// Created by Thomas Harte on 10/10/2017. +// Copyright © 2017 Thomas Harte. All rights reserved. +// + +#include "KeyboardMapper.hpp" +#include "Vic20.hpp" + +using namespace Commodore::Vic20; + +uint16_t KeyboardMapper::mapped_key_for_key(Inputs::Keyboard::Key key) { +#define BIND(source, dest) case Inputs::Keyboard::Key::source: return Commodore::Vic20::dest + switch(key) { + default: break; + + BIND(k0, Key0); BIND(k1, Key1); BIND(k2, Key2); BIND(k3, Key3); BIND(k4, Key4); + BIND(k5, Key5); BIND(k6, Key6); BIND(k7, Key7); BIND(k8, Key8); BIND(k9, Key9); + BIND(Q, KeyQ); BIND(W, KeyW); BIND(E, KeyE); BIND(R, KeyR); BIND(T, KeyT); + BIND(Y, KeyY); BIND(U, KeyU); BIND(I, KeyI); BIND(O, KeyO); BIND(P, KeyP); + BIND(A, KeyA); BIND(S, KeyS); BIND(D, KeyD); BIND(F, KeyF); BIND(G, KeyG); + BIND(H, KeyH); BIND(J, KeyJ); BIND(K, KeyK); BIND(L, KeyL); + BIND(Z, KeyZ); BIND(X, KeyX); BIND(C, KeyC); BIND(V, KeyV); + BIND(B, KeyB); BIND(N, KeyN); BIND(M, KeyM); + + BIND(BackTick, KeyLeft); + BIND(Hyphen, KeyPlus); + BIND(Equals, KeyDash); + BIND(F11, KeyGBP); + BIND(F12, KeyHome); + + BIND(Tab, KeyControl); + BIND(OpenSquareBracket, KeyAt); + BIND(CloseSquareBracket, KeyAsterisk); + + BIND(BackSlash, KeyRestore); + BIND(Hash, KeyUp); + BIND(F10, KeyUp); + + BIND(Semicolon, KeyColon); + BIND(Quote, KeySemicolon); + BIND(F9, KeyEquals); + + BIND(LeftMeta, KeyCBM); + BIND(LeftOption, KeyCBM); + BIND(RightOption, KeyCBM); + BIND(RightMeta, KeyCBM); + + BIND(LeftShift, KeyLShift); + BIND(RightShift, KeyRShift); + + BIND(Comma, KeyComma); + BIND(FullStop, KeyFullStop); + BIND(ForwardSlash, KeySlash); + + BIND(Right, KeyRight); + BIND(Down, KeyDown); + + BIND(Enter, KeyReturn); + BIND(Space, KeySpace); + BIND(BackSpace, KeyDelete); + } +#undef BIND + return KeyboardMachine::Machine::KeyNotMapped; +} diff --git a/Machines/Commodore/Vic-20/KeyboardMapper.hpp b/Machines/Commodore/Vic-20/KeyboardMapper.hpp new file mode 100644 index 000000000..c132c72e2 --- /dev/null +++ b/Machines/Commodore/Vic-20/KeyboardMapper.hpp @@ -0,0 +1,24 @@ +// +// KeyboardMapper.hpp +// Clock Signal +// +// Created by Thomas Harte on 10/10/2017. +// Copyright © 2017 Thomas Harte. All rights reserved. +// + +#ifndef Machines_Commodore_Vic20_KeyboardMapper_hpp +#define Machines_Commodore_Vic20_KeyboardMapper_hpp + +#include "../../KeyboardMachine.hpp" + +namespace Commodore { +namespace Vic20 { + +struct KeyboardMapper: public KeyboardMachine::Machine::KeyboardMapper { + uint16_t mapped_key_for_key(Inputs::Keyboard::Key key); +}; + +} +} + +#endif /* KeyboardMapper_hpp */ diff --git a/Machines/Commodore/Vic-20/Vic20.cpp b/Machines/Commodore/Vic-20/Vic20.cpp index 5a7a83e6d..8baf3ba6f 100644 --- a/Machines/Commodore/Vic-20/Vic20.cpp +++ b/Machines/Commodore/Vic-20/Vic20.cpp @@ -9,6 +9,7 @@ #include "Vic20.hpp" #include "CharacterMapper.hpp" +#include "KeyboardMapper.hpp" #include "../../../Processors/6502/6502.hpp" #include "../../../Components/6560/6560.hpp" @@ -541,6 +542,10 @@ class ConcreteMachine: keyboard_via_.set_control_line_input(MOS::MOS6522::Port::A, MOS::MOS6522::Line::One, !tape->get_input()); } + KeyboardMapper &get_keyboard_mapper() override { + return keyboard_mapper_; + } + private: CPU::MOS6502::Processor m6502_; @@ -570,6 +575,7 @@ class ConcreteMachine: } Region region_; + Commodore::Vic20::KeyboardMapper keyboard_mapper_; std::unique_ptr mos6560_; std::shared_ptr user_port_via_port_handler_; diff --git a/Machines/Commodore/Vic-20/Vic20.hpp b/Machines/Commodore/Vic-20/Vic20.hpp index 0ca7b5a7b..53e94b28f 100644 --- a/Machines/Commodore/Vic-20/Vic20.hpp +++ b/Machines/Commodore/Vic-20/Vic20.hpp @@ -54,6 +54,8 @@ enum Key: uint16_t { KeyI = key(1, 0x10), KeyP = key(1, 0x20), KeyAsterisk = key(1, 0x40), KeyReturn = key(1, 0x80), Key1 = key(0, 0x01), Key3 = key(0, 0x02), Key5 = key(0, 0x04), Key7 = key(0, 0x08), Key9 = key(0, 0x10), KeyPlus = key(0, 0x20), KeyGBP = key(0, 0x40), KeyDelete = key(0, 0x80), + + KeyRestore = 0xfffe #undef key }; diff --git a/Machines/Electron/CharacterMapper.cpp b/Machines/Electron/CharacterMapper.cpp index 91572f29a..d17588ced 100644 --- a/Machines/Electron/CharacterMapper.cpp +++ b/Machines/Electron/CharacterMapper.cpp @@ -12,10 +12,10 @@ using namespace Electron; uint16_t *CharacterMapper::sequence_for_character(char character) { -#define KEYS(...) {__VA_ARGS__, EndSequence} -#define SHIFT(...) {KeyShift, __VA_ARGS__, EndSequence} -#define CTRL(...) {KeyControl, __VA_ARGS__, EndSequence} -#define X {NotMapped} +#define KEYS(...) {__VA_ARGS__, KeyboardMachine::Machine::KeyEndSequence} +#define SHIFT(...) {KeyShift, __VA_ARGS__, KeyboardMachine::Machine::KeyEndSequence} +#define CTRL(...) {KeyControl, __VA_ARGS__, KeyboardMachine::Machine::KeyEndSequence} +#define X {KeyboardMachine::Machine::KeyNotMapped} static KeySequence key_sequences[] = { /* NUL */ X, /* SOH */ X, /* STX */ X, /* ETX */ X, diff --git a/Machines/Electron/Electron.cpp b/Machines/Electron/Electron.cpp index 39e67ca27..2ca236611 100644 --- a/Machines/Electron/Electron.cpp +++ b/Machines/Electron/Electron.cpp @@ -17,6 +17,7 @@ #include "CharacterMapper.hpp" #include "Interrupts.hpp" +#include "KeyboardMapper.hpp" #include "Plus3.hpp" #include "Speaker.hpp" #include "Tape.hpp" @@ -387,6 +388,10 @@ class ConcreteMachine: Utility::TypeRecipient::set_typer_for_string(string, std::move(mapper)); } + KeyboardMapper &get_keyboard_mapper() override { + return keyboard_mapper_; + } + private: inline void update_display() { if(cycles_since_display_update_ > 0) { @@ -442,6 +447,7 @@ class ConcreteMachine: uint8_t interrupt_status_ = Interrupt::PowerOnReset | Interrupt::TransmitDataEmpty | 0x80; uint8_t interrupt_control_ = 0; uint8_t key_states_[14]; + Electron::KeyboardMapper keyboard_mapper_; // Counters related to simultaneous subsystems Cycles cycles_since_display_update_ = 0; diff --git a/Machines/Electron/KeyboardMapper.cpp b/Machines/Electron/KeyboardMapper.cpp new file mode 100644 index 000000000..50ee57b80 --- /dev/null +++ b/Machines/Electron/KeyboardMapper.cpp @@ -0,0 +1,57 @@ +// +// KeyboardMapper.cpp +// Clock Signal +// +// Created by Thomas Harte on 10/10/2017. +// Copyright © 2017 Thomas Harte. All rights reserved. +// + +#include "KeyboardMapper.hpp" +#include "Electron.hpp" + +using namespace Electron; + +uint16_t KeyboardMapper::mapped_key_for_key(Inputs::Keyboard::Key key) { +#define BIND(source, dest) case Inputs::Keyboard::Key::source: return Electron::Key::dest + switch(key) { + default: return KeyCopy; + + BIND(k0, Key0); BIND(k1, Key1); BIND(k2, Key2); BIND(k3, Key3); BIND(k4, Key4); + BIND(k5, Key5); BIND(k6, Key6); BIND(k7, Key7); BIND(k8, Key8); BIND(k9, Key9); + BIND(Q, KeyQ); BIND(W, KeyW); BIND(E, KeyE); BIND(R, KeyR); BIND(T, KeyT); + BIND(Y, KeyY); BIND(U, KeyU); BIND(I, KeyI); BIND(O, KeyO); BIND(P, KeyP); + BIND(A, KeyA); BIND(S, KeyS); BIND(D, KeyD); BIND(F, KeyF); BIND(G, KeyG); + BIND(H, KeyH); BIND(J, KeyJ); BIND(K, KeyK); BIND(L, KeyL); + BIND(Z, KeyZ); BIND(X, KeyX); BIND(C, KeyC); BIND(V, KeyV); + BIND(B, KeyB); BIND(N, KeyN); BIND(M, KeyM); + + BIND(Comma, KeyComma); + BIND(FullStop, KeyFullStop); + BIND(ForwardSlash, KeySlash); + BIND(Semicolon, KeySemiColon); + BIND(Quote, KeyColon); + + BIND(Escape, KeyEscape); + BIND(Equals, KeyBreak); + BIND(F12, KeyBreak); + + BIND(Left, KeyLeft); BIND(Right, KeyRight); BIND(Up, KeyUp); BIND(Down, KeyDown); + + BIND(Tab, KeyFunc); BIND(LeftOption, KeyFunc); BIND(RightOption, KeyFunc); + BIND(LeftMeta, KeyFunc); BIND(RightMeta, KeyFunc); + BIND(CapsLock, KeyControl); BIND(LeftControl, KeyControl); BIND(RightControl, KeyControl); + BIND(LeftShift, KeyShift); BIND(RightShift, KeyShift); + + BIND(Hyphen, KeyMinus); + BIND(Delete, KeyDelete); + BIND(Enter, KeyReturn); BIND(KeyPadEnter, KeyReturn); + + BIND(KeyPad0, Key0); BIND(KeyPad1, Key1); BIND(KeyPad2, Key2); BIND(KeyPad3, Key3); BIND(KeyPad4, Key4); + BIND(KeyPad5, Key5); BIND(KeyPad6, Key6); BIND(KeyPad7, Key7); BIND(KeyPad8, Key8); BIND(KeyPad9, Key9); + + BIND(KeyPadMinus, KeyMinus); BIND(KeyPadPlus, KeyColon); + + BIND(Space, KeySpace); + } +#undef BIND +} diff --git a/Machines/Electron/KeyboardMapper.hpp b/Machines/Electron/KeyboardMapper.hpp new file mode 100644 index 000000000..6b2528a33 --- /dev/null +++ b/Machines/Electron/KeyboardMapper.hpp @@ -0,0 +1,22 @@ +// +// KeyboardMapper.hpp +// Clock Signal +// +// Created by Thomas Harte on 10/10/2017. +// Copyright © 2017 Thomas Harte. All rights reserved. +// + +#ifndef Machines_Electron_KeyboardMapper_hpp +#define Machines_Electron_KeyboardMapper_hpp + +#include "../KeyboardMachine.hpp" + +namespace Electron { + +struct KeyboardMapper: public KeyboardMachine::Machine::KeyboardMapper { + uint16_t mapped_key_for_key(Inputs::Keyboard::Key key); +}; + +}; + +#endif /* KeyboardMapper_hpp */ diff --git a/Machines/KeyboardMachine.cpp b/Machines/KeyboardMachine.cpp new file mode 100644 index 000000000..36299cd13 --- /dev/null +++ b/Machines/KeyboardMachine.cpp @@ -0,0 +1,29 @@ +// +// KeyboardMachine.cpp +// Clock Signal +// +// Created by Thomas Harte on 10/10/2017. +// Copyright © 2017 Thomas Harte. All rights reserved. +// + +#include "KeyboardMachine.hpp" + +using namespace KeyboardMachine; + +Machine::Machine() { + keyboard_.set_delegate(this); +} + +void Machine::keyboard_did_change_key(Inputs::Keyboard *keyboard, Inputs::Keyboard::Key key, bool is_pressed) { + uint16_t mapped_key = get_keyboard_mapper().mapped_key_for_key(key); + if(mapped_key != KeyNotMapped) set_key_state(mapped_key, is_pressed); +} + +void Machine::reset_all_keys() { + // TODO: unify naming. + clear_all_keys(); +} + +Inputs::Keyboard &Machine::get_keyboard() { + return keyboard_; +} diff --git a/Machines/KeyboardMachine.hpp b/Machines/KeyboardMachine.hpp index 6399d6f58..a509002a6 100644 --- a/Machines/KeyboardMachine.hpp +++ b/Machines/KeyboardMachine.hpp @@ -9,20 +9,59 @@ #ifndef KeyboardMachine_h #define KeyboardMachine_h +#include "../Inputs/Keyboard.hpp" + namespace KeyboardMachine { -class Machine { +class Machine: public Inputs::Keyboard::Delegate { public: + Machine(); + /*! Indicates that the key @c key has been either pressed or released, according to the state of @c isPressed. */ - virtual void set_key_state(uint16_t key, bool isPressed) = 0; + virtual void set_key_state(uint16_t key, bool is_pressed) = 0; /*! Instructs that all keys should now be treated as released. */ virtual void clear_all_keys() = 0; + + /*! + Provides a destination for keyboard input. + */ + virtual Inputs::Keyboard &get_keyboard(); + + /*! + A keyboard mapper attempts to provide a physical mapping between host keys and emulated keys. + See the character mapper for logical mapping. + */ + class KeyboardMapper { + public: + virtual uint16_t mapped_key_for_key(Inputs::Keyboard::Key key) = 0; + }; + + /// Terminates a key sequence from the character mapper. + static const uint16_t KeyEndSequence = 0xffff; + + /*! + Indicates that a key is not mapped (for the keyboard mapper) or that a + character cannot be typed (for the character mapper). + */ + static const uint16_t KeyNotMapped = 0xfffe; + + protected: + /*! + Allows individual machines to provide the mapping between host keys + as per Inputs::Keyboard and their native scheme. + */ + virtual KeyboardMapper &get_keyboard_mapper() = 0; + + private: + void keyboard_did_change_key(Inputs::Keyboard *keyboard, Inputs::Keyboard::Key key, bool is_pressed); + void reset_all_keys(); + Inputs::Keyboard keyboard_; }; } diff --git a/Machines/Oric/CharacterMapper.cpp b/Machines/Oric/CharacterMapper.cpp index f8e0e649e..53df8fa35 100644 --- a/Machines/Oric/CharacterMapper.cpp +++ b/Machines/Oric/CharacterMapper.cpp @@ -12,9 +12,9 @@ using namespace Oric; uint16_t *CharacterMapper::sequence_for_character(char character) { -#define KEYS(...) {__VA_ARGS__, EndSequence} -#define SHIFT(...) {KeyLeftShift, __VA_ARGS__, EndSequence} -#define X {NotMapped} +#define KEYS(...) {__VA_ARGS__, KeyboardMachine::Machine::KeyEndSequence} +#define SHIFT(...) {KeyLeftShift, __VA_ARGS__, KeyboardMachine::Machine::KeyEndSequence} +#define X {KeyboardMachine::Machine::KeyNotMapped} static KeySequence key_sequences[] = { /* NUL */ X, /* SOH */ X, /* STX */ X, /* ETX */ X, diff --git a/Machines/Oric/KeyboardMapper.cpp b/Machines/Oric/KeyboardMapper.cpp new file mode 100644 index 000000000..4a8a5a8e7 --- /dev/null +++ b/Machines/Oric/KeyboardMapper.cpp @@ -0,0 +1,53 @@ +// +// KeyboardMapper.cpp +// Clock Signal +// +// Created by Thomas Harte on 10/10/2017. +// Copyright © 2017 Thomas Harte. All rights reserved. +// + +#include "KeyboardMapper.hpp" +#include "Oric.hpp" + +using namespace Oric; + +uint16_t KeyboardMapper::mapped_key_for_key(Inputs::Keyboard::Key key) { +#define BIND(source, dest) case Inputs::Keyboard::Key::source: return Oric::dest + switch(key) { + default: break; + + BIND(k0, Key0); BIND(k1, Key1); BIND(k2, Key2); BIND(k3, Key3); BIND(k4, Key4); + BIND(k5, Key5); BIND(k6, Key6); BIND(k7, Key7); BIND(k8, Key8); BIND(k9, Key9); + BIND(Q, KeyQ); BIND(W, KeyW); BIND(E, KeyE); BIND(R, KeyR); BIND(T, KeyT); + BIND(Y, KeyY); BIND(U, KeyU); BIND(I, KeyI); BIND(O, KeyO); BIND(P, KeyP); + BIND(A, KeyA); BIND(S, KeyS); BIND(D, KeyD); BIND(F, KeyF); BIND(G, KeyG); + BIND(H, KeyH); BIND(J, KeyJ); BIND(K, KeyK); BIND(L, KeyL); + BIND(Z, KeyZ); BIND(X, KeyX); BIND(C, KeyC); BIND(V, KeyV); + BIND(B, KeyB); BIND(N, KeyN); BIND(M, KeyM); + + BIND(Left, KeyLeft); BIND(Right, KeyRight); BIND(Up, KeyUp); BIND(Down, KeyDown); + + BIND(Hyphen, KeyMinus); BIND(Equals, KeyEquals); BIND(BackSlash, KeyBackSlash); + BIND(OpenSquareBracket, KeyOpenSquare); BIND(CloseSquareBracket, KeyCloseSquare); + + BIND(BackSpace, KeyDelete); BIND(Delete, KeyDelete); + + BIND(Semicolon, KeySemiColon); BIND(Quote, KeyQuote); + BIND(Comma, KeyComma); BIND(FullStop, KeyFullStop); BIND(ForwardSlash, KeyForwardSlash); + + BIND(Escape, KeyEscape); BIND(Tab, KeyEscape); + BIND(CapsLock, KeyControl); BIND(LeftControl, KeyControl); BIND(RightControl, KeyControl); + BIND(LeftOption, KeyFunction); + BIND(RightOption, KeyFunction); + BIND(LeftMeta, KeyFunction); + BIND(RightMeta, KeyFunction); + BIND(LeftShift, KeyLeftShift); + BIND(RightShift, KeyRightShift); + + BIND(Space, KeySpace); + BIND(Enter, KeyReturn); + } +#undef BIND + + return KeyboardMachine::Machine::KeyNotMapped; +} diff --git a/Machines/Oric/KeyboardMapper.hpp b/Machines/Oric/KeyboardMapper.hpp new file mode 100644 index 000000000..2a61bdf61 --- /dev/null +++ b/Machines/Oric/KeyboardMapper.hpp @@ -0,0 +1,22 @@ +// +// KeyboardMapper.hpp +// Clock Signal +// +// Created by Thomas Harte on 10/10/2017. +// Copyright © 2017 Thomas Harte. All rights reserved. +// + +#ifndef Machines_Oric_KeyboardMapper_hpp +#define Machines_Oric_KeyboardMapper_hpp + +#include "../KeyboardMachine.hpp" + +namespace Oric { + +struct KeyboardMapper: public KeyboardMachine::Machine::KeyboardMapper { + uint16_t mapped_key_for_key(Inputs::Keyboard::Key key); +}; + +}; + +#endif /* KeyboardMapper_hpp */ diff --git a/Machines/Oric/Oric.cpp b/Machines/Oric/Oric.cpp index e863a2b03..9f6f717f9 100644 --- a/Machines/Oric/Oric.cpp +++ b/Machines/Oric/Oric.cpp @@ -8,9 +8,10 @@ #include "Oric.hpp" -#include "Video.hpp" -#include "Microdisc.hpp" #include "CharacterMapper.hpp" +#include "KeyboardMapper.hpp" +#include "Microdisc.hpp" +#include "Video.hpp" #include "../MemoryFuzzer.hpp" #include "../Typer.hpp" @@ -405,6 +406,10 @@ class ConcreteMachine: set_interrupt_line(); } + KeyboardMapper &get_keyboard_mapper() override { + return keyboard_mapper_; + } + private: CPU::MOS6502::Processor m6502_; @@ -425,6 +430,9 @@ class ConcreteMachine: std::unique_ptr video_output_; std::shared_ptr ay8910_; + // Inputs + Oric::KeyboardMapper keyboard_mapper_; + // The tape TapePlayer tape_player_; bool use_fast_tape_hack_ = false; diff --git a/Machines/Typer.cpp b/Machines/Typer.cpp index 4a19ddc7b..678c64ea7 100644 --- a/Machines/Typer.cpp +++ b/Machines/Typer.cpp @@ -44,14 +44,14 @@ void Typer::run_for(const HalfCycles duration) { bool Typer::try_type_next_character() { uint16_t *sequence = character_mapper_->sequence_for_character(string_[string_pointer_]); - if(!sequence || sequence[0] == CharacterMapper::NotMapped) { + if(!sequence || sequence[0] == KeyboardMachine::Machine::KeyNotMapped) { return false; } if(!phase_) delegate_->clear_all_keys(); else { delegate_->set_key_state(sequence[phase_ - 1], true); - return sequence[phase_] != CharacterMapper::EndSequence; + return sequence[phase_] != KeyboardMachine::Machine::KeyEndSequence; } return true; @@ -85,6 +85,6 @@ Typer::~Typer() { uint16_t *CharacterMapper::table_lookup_sequence_for_character(KeySequence *sequences, size_t length, char character) { size_t ucharacter = static_cast((unsigned char)character); if(ucharacter > (length / sizeof(KeySequence))) return nullptr; - if(sequences[ucharacter][0] == NotMapped) return nullptr; + if(sequences[ucharacter][0] == KeyboardMachine::Machine::KeyNotMapped) return nullptr; return sequences[ucharacter]; } diff --git a/Machines/Typer.hpp b/Machines/Typer.hpp index 7e85ef4b7..2c165a489 100644 --- a/Machines/Typer.hpp +++ b/Machines/Typer.hpp @@ -24,15 +24,6 @@ class CharacterMapper { /// @returns The EndSequence-terminated sequence of keys that would cause @c character to be typed. virtual uint16_t *sequence_for_character(char character) = 0; - /// Terminates a key sequence. - static const uint16_t EndSequence = 0xffff; - - /*! - If returned as the first entry in a key sequence, indicates that the requested character - cannot be mapped. - */ - static const uint16_t NotMapped = 0xfffe; - protected: typedef uint16_t KeySequence[16]; diff --git a/Machines/ZX8081/CharacterMapper.cpp b/Machines/ZX8081/CharacterMapper.cpp index 07f1cf874..af4f41f60 100644 --- a/Machines/ZX8081/CharacterMapper.cpp +++ b/Machines/ZX8081/CharacterMapper.cpp @@ -14,9 +14,9 @@ using namespace ZX8081; CharacterMapper::CharacterMapper(bool is_zx81) : is_zx81_(is_zx81) {} uint16_t *CharacterMapper::sequence_for_character(char character) { -#define KEYS(...) {__VA_ARGS__, EndSequence} -#define SHIFT(...) {KeyShift, __VA_ARGS__, EndSequence} -#define X {NotMapped} +#define KEYS(...) {__VA_ARGS__, KeyboardMachine::Machine::KeyEndSequence} +#define SHIFT(...) {KeyShift, __VA_ARGS__, KeyboardMachine::Machine::KeyEndSequence} +#define X {KeyboardMachine::Machine::KeyNotMapped} static KeySequence zx81_key_sequences[] = { /* NUL */ X, /* SOH */ X, /* STX */ X, /* ETX */ X, diff --git a/Machines/ZX8081/KeyboardMapper.cpp b/Machines/ZX8081/KeyboardMapper.cpp new file mode 100644 index 000000000..1280f2e92 --- /dev/null +++ b/Machines/ZX8081/KeyboardMapper.cpp @@ -0,0 +1,35 @@ +// +// KeyboardMapper.cpp +// Clock Signal +// +// Created by Thomas Harte on 10/10/2017. +// Copyright © 2017 Thomas Harte. All rights reserved. +// + +#include "KeyboardMapper.hpp" +#include "ZX8081.hpp" + +using namespace ZX8081; + +uint16_t KeyboardMapper::mapped_key_for_key(Inputs::Keyboard::Key key) { +#define BIND(source, dest) case Inputs::Keyboard::Key::source: return ZX8081::dest + switch(key) { + default: break; + + BIND(k0, Key0); BIND(k1, Key1); BIND(k2, Key2); BIND(k3, Key3); BIND(k4, Key4); + BIND(k5, Key5); BIND(k6, Key6); BIND(k7, Key7); BIND(k8, Key8); BIND(k9, Key9); + BIND(Q, KeyQ); BIND(W, KeyW); BIND(E, KeyE); BIND(R, KeyR); BIND(T, KeyT); + BIND(Y, KeyY); BIND(U, KeyU); BIND(I, KeyI); BIND(O, KeyO); BIND(P, KeyP); + BIND(A, KeyA); BIND(S, KeyS); BIND(D, KeyD); BIND(F, KeyF); BIND(G, KeyG); + BIND(H, KeyH); BIND(J, KeyJ); BIND(K, KeyK); BIND(L, KeyL); + BIND(Z, KeyZ); BIND(X, KeyX); BIND(C, KeyC); BIND(V, KeyV); + BIND(B, KeyB); BIND(N, KeyN); BIND(M, KeyM); + + BIND(LeftShift, KeyShift); BIND(RightShift, KeyShift); + BIND(FullStop, KeyDot); + BIND(Enter, KeyEnter); + BIND(Space, KeySpace); + } +#undef BIND + return KeyboardMachine::Machine::KeyNotMapped; +} diff --git a/Machines/ZX8081/KeyboardMapper.hpp b/Machines/ZX8081/KeyboardMapper.hpp new file mode 100644 index 000000000..5129fa305 --- /dev/null +++ b/Machines/ZX8081/KeyboardMapper.hpp @@ -0,0 +1,22 @@ +// +// KeyboardMapper.hpp +// Clock Signal +// +// Created by Thomas Harte on 10/10/2017. +// Copyright © 2017 Thomas Harte. All rights reserved. +// + +#ifndef Machines_ZX8081_KeyboardMapper_hpp +#define Machines_ZX8081_KeyboardMapper_hpp + +#include "../KeyboardMachine.hpp" + +namespace ZX8081 { + +struct KeyboardMapper: public KeyboardMachine::Machine::KeyboardMapper { + uint16_t mapped_key_for_key(Inputs::Keyboard::Key key); +}; + +}; + +#endif /* KeyboardMapper_hpp */ diff --git a/Machines/ZX8081/ZX8081.cpp b/Machines/ZX8081/ZX8081.cpp index d39cc8e7f..94a435b53 100644 --- a/Machines/ZX8081/ZX8081.cpp +++ b/Machines/ZX8081/ZX8081.cpp @@ -18,6 +18,7 @@ #include "../Typer.hpp" #include "CharacterMapper.hpp" +#include "KeyboardMapper.hpp" #include "Video.hpp" #include @@ -331,6 +332,10 @@ template class ConcreteMachine: HalfCycles get_typer_delay() override final { return Cycles(7000000); } HalfCycles get_typer_frequency() override final { return Cycles(390000); } + KeyboardMapper &get_keyboard_mapper() override { + return keyboard_mapper_; + } + private: CPU::Z80::Processor z80_; @@ -350,6 +355,7 @@ template class ConcreteMachine: int line_counter_; uint8_t key_states_[8]; + ZX8081::KeyboardMapper keyboard_mapper_; HalfClockReceiver tape_player_; Storage::Tape::ZX8081::Parser parser_; diff --git a/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj b/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj index 20c740482..b5f6f2549 100644 --- a/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj +++ b/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj @@ -81,6 +81,12 @@ 4B4DC82B1D2C27A4003C5BF8 /* SerialBus.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B4DC8291D2C27A4003C5BF8 /* SerialBus.cpp */; }; 4B5073071DDD3B9400C48FBD /* ArrayBuilder.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B5073051DDD3B9400C48FBD /* ArrayBuilder.cpp */; }; 4B50730A1DDFCFDF00C48FBD /* ArrayBuilderTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 4B5073091DDFCFDF00C48FBD /* ArrayBuilderTests.mm */; }; + 4B54C0BC1F8D8E790050900F /* KeyboardMachine.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B54C0BB1F8D8E790050900F /* KeyboardMachine.cpp */; }; + 4B54C0BF1F8D8F450050900F /* KeyboardMapper.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B54C0BD1F8D8F450050900F /* KeyboardMapper.cpp */; }; + 4B54C0C21F8D91CD0050900F /* KeyboardMapper.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B54C0C11F8D91CD0050900F /* KeyboardMapper.cpp */; }; + 4B54C0C51F8D91D90050900F /* KeyboardMapper.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B54C0C41F8D91D90050900F /* KeyboardMapper.cpp */; }; + 4B54C0C81F8D91E50050900F /* KeyboardMapper.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B54C0C61F8D91E50050900F /* KeyboardMapper.cpp */; }; + 4B54C0CB1F8D92590050900F /* KeyboardMapper.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B54C0CA1F8D92580050900F /* KeyboardMapper.cpp */; }; 4B55CE5D1C3B7D6F0093A61B /* CSOpenGLView.m in Sources */ = {isa = PBXBuildFile; fileRef = 4B55CE5C1C3B7D6F0093A61B /* CSOpenGLView.m */; }; 4B55CE5F1C3B7D960093A61B /* MachineDocument.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B55CE5E1C3B7D960093A61B /* MachineDocument.swift */; }; 4B58601E1F806AB200AEE2E3 /* MFMSectorDump.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B58601C1F806AB200AEE2E3 /* MFMSectorDump.cpp */; }; @@ -629,6 +635,17 @@ 4B5073051DDD3B9400C48FBD /* ArrayBuilder.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ArrayBuilder.cpp; sourceTree = ""; }; 4B5073061DDD3B9400C48FBD /* ArrayBuilder.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = ArrayBuilder.hpp; sourceTree = ""; }; 4B5073091DDFCFDF00C48FBD /* ArrayBuilderTests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = ArrayBuilderTests.mm; sourceTree = ""; }; + 4B54C0BB1F8D8E790050900F /* KeyboardMachine.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = KeyboardMachine.cpp; sourceTree = ""; }; + 4B54C0BD1F8D8F450050900F /* KeyboardMapper.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = KeyboardMapper.cpp; path = Oric/KeyboardMapper.cpp; sourceTree = ""; }; + 4B54C0BE1F8D8F450050900F /* KeyboardMapper.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = KeyboardMapper.hpp; path = Oric/KeyboardMapper.hpp; sourceTree = ""; }; + 4B54C0C01F8D91CD0050900F /* KeyboardMapper.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = KeyboardMapper.hpp; path = AmstradCPC/KeyboardMapper.hpp; sourceTree = ""; }; + 4B54C0C11F8D91CD0050900F /* KeyboardMapper.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = KeyboardMapper.cpp; path = AmstradCPC/KeyboardMapper.cpp; sourceTree = ""; }; + 4B54C0C31F8D91D90050900F /* KeyboardMapper.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = KeyboardMapper.hpp; sourceTree = ""; }; + 4B54C0C41F8D91D90050900F /* KeyboardMapper.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = KeyboardMapper.cpp; sourceTree = ""; }; + 4B54C0C61F8D91E50050900F /* KeyboardMapper.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = KeyboardMapper.cpp; path = Electron/KeyboardMapper.cpp; sourceTree = ""; }; + 4B54C0C71F8D91E50050900F /* KeyboardMapper.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = KeyboardMapper.hpp; path = Electron/KeyboardMapper.hpp; sourceTree = ""; }; + 4B54C0C91F8D92580050900F /* KeyboardMapper.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = KeyboardMapper.hpp; path = ZX8081/KeyboardMapper.hpp; sourceTree = ""; }; + 4B54C0CA1F8D92580050900F /* KeyboardMapper.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = KeyboardMapper.cpp; path = ZX8081/KeyboardMapper.cpp; sourceTree = ""; }; 4B55CE5B1C3B7D6F0093A61B /* CSOpenGLView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CSOpenGLView.h; sourceTree = ""; }; 4B55CE5C1C3B7D6F0093A61B /* CSOpenGLView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CSOpenGLView.m; sourceTree = ""; }; 4B55CE5E1C3B7D960093A61B /* MachineDocument.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MachineDocument.swift; sourceTree = ""; }; @@ -1207,9 +1224,11 @@ isa = PBXGroup; children = ( 4B8378DD1F33675F005CA9E4 /* CharacterMapper.cpp */, + 4B54C0CA1F8D92580050900F /* KeyboardMapper.cpp */, 4BD3A3091EE755C800B5B501 /* Video.cpp */, 4B1497901EE4B5A800CE2596 /* ZX8081.cpp */, 4B8378DE1F33675F005CA9E4 /* CharacterMapper.hpp */, + 4B54C0C91F8D92580050900F /* KeyboardMapper.hpp */, 4BD3A30A1EE755C800B5B501 /* Video.hpp */, 4B1497911EE4B5A800CE2596 /* ZX8081.hpp */, ); @@ -1319,6 +1338,7 @@ children = ( 4B8378DA1F336631005CA9E4 /* CharacterMapper.cpp */, 4B2E2D9B1C3A070400138695 /* Electron.cpp */, + 4B54C0C61F8D91E50050900F /* KeyboardMapper.cpp */, 4B30512E1D98ACC600B4FED8 /* Plus3.cpp */, 4BEA52611DF339D7007E74F2 /* Speaker.cpp */, 4BEA525D1DF33323007E74F2 /* Tape.cpp */, @@ -1326,6 +1346,7 @@ 4B8378DB1F336631005CA9E4 /* CharacterMapper.hpp */, 4B2E2D9C1C3A070400138695 /* Electron.hpp */, 4BEA52601DF3343A007E74F2 /* Interrupts.hpp */, + 4B54C0C71F8D91E50050900F /* KeyboardMapper.hpp */, 4B30512F1D98ACC600B4FED8 /* Plus3.hpp */, 4BEA52621DF339D7007E74F2 /* Speaker.hpp */, 4BEA525F1DF333D8007E74F2 /* Tape.hpp */, @@ -1379,9 +1400,11 @@ isa = PBXGroup; children = ( 4B38F3461F2EC11D00D9235D /* AmstradCPC.cpp */, - 4B38F3471F2EC11D00D9235D /* AmstradCPC.hpp */, 4BACC5AF1F3DFF7C0037C015 /* CharacterMapper.cpp */, + 4B54C0C11F8D91CD0050900F /* KeyboardMapper.cpp */, + 4B38F3471F2EC11D00D9235D /* AmstradCPC.hpp */, 4BACC5B01F3DFF7C0037C015 /* CharacterMapper.hpp */, + 4B54C0C01F8D91CD0050900F /* KeyboardMapper.hpp */, ); name = AmstradCPC; sourceTree = ""; @@ -1525,8 +1548,10 @@ isa = PBXGroup; children = ( 4B8378E31F3378C4005CA9E4 /* CharacterMapper.cpp */, + 4B54C0C41F8D91D90050900F /* KeyboardMapper.cpp */, 4B4DC81F1D2C2425003C5BF8 /* Vic20.cpp */, 4B8378E41F3378C4005CA9E4 /* CharacterMapper.hpp */, + 4B54C0C31F8D91D90050900F /* KeyboardMapper.hpp */, 4B4DC8201D2C2425003C5BF8 /* Vic20.hpp */, ); path = "Vic-20"; @@ -2173,6 +2198,7 @@ 4BB73EDC1B587CA500552FC2 /* Machines */ = { isa = PBXGroup; children = ( + 4B54C0BB1F8D8E790050900F /* KeyboardMachine.cpp */, 4B2A33281DB8544D002876E3 /* MemoryFuzzer.cpp */, 4B1E85731D170228001EF87D /* Typer.cpp */, 4BA9C3CF1D8164A9002DDB61 /* ConfigurationTarget.hpp */, @@ -2316,10 +2342,12 @@ isa = PBXGroup; children = ( 4B8378E01F336920005CA9E4 /* CharacterMapper.cpp */, + 4B54C0BD1F8D8F450050900F /* KeyboardMapper.cpp */, 4B5FADBE1DE3BF2B00AEC565 /* Microdisc.cpp */, 4BCF1FA21DADC3DD0039D2E7 /* Oric.cpp */, 4B2BFDB01DAEF5FF001A68B8 /* Video.cpp */, 4B8378E11F336920005CA9E4 /* CharacterMapper.hpp */, + 4B54C0BE1F8D8F450050900F /* KeyboardMapper.hpp */, 4B5FADBF1DE3BF2B00AEC565 /* Microdisc.hpp */, 4BCF1FA31DADC3DD0039D2E7 /* Oric.hpp */, 4B2BFDB11DAEF5FF001A68B8 /* Video.hpp */, @@ -2926,12 +2954,14 @@ 4B4518A11F75FD1C00926311 /* D64.cpp in Sources */, 4B1558C01F844ECD006E9A97 /* BitReverse.cpp in Sources */, 4BCF1FA41DADC3DD0039D2E7 /* Oric.cpp in Sources */, + 4B54C0CB1F8D92590050900F /* KeyboardMapper.cpp in Sources */, 4BEA525E1DF33323007E74F2 /* Tape.cpp in Sources */, 4B8334951F5E25B60097E338 /* C1540.cpp in Sources */, 4B1497921EE4B5A800CE2596 /* ZX8081.cpp in Sources */, 4B643F3F1D77B88000D431D6 /* DocumentController.swift in Sources */, 4B4518861F75E91A00926311 /* MFMDiskController.cpp in Sources */, 4BA799951D8B656E0045123D /* StaticAnalyser.cpp in Sources */, + 4B54C0BF1F8D8F450050900F /* KeyboardMapper.cpp in Sources */, 4B3FE75E1F3CF68B00448EE4 /* CPM.cpp in Sources */, 4B2BFDB21DAEF5FF001A68B8 /* Video.cpp in Sources */, 4B4DC82B1D2C27A4003C5BF8 /* SerialBus.cpp in Sources */, @@ -2964,6 +2994,7 @@ 4BEA52631DF339D7007E74F2 /* Speaker.cpp in Sources */, 4BC5E4921D7ED365008CF980 /* StaticAnalyser.cpp in Sources */, 4BC830D11D6E7C690000A26F /* Tape.cpp in Sources */, + 4B54C0C51F8D91D90050900F /* KeyboardMapper.cpp in Sources */, 4B69FB441C4D941400B5F0AA /* TapeUEF.cpp in Sources */, 4B86E25B1F8C628F006FAA45 /* Keyboard.cpp in Sources */, 4B4518851F75E91A00926311 /* DiskController.cpp in Sources */, @@ -2994,6 +3025,7 @@ 4B8FE2291DA1EDDF0090D3CE /* ElectronOptionsPanel.swift in Sources */, 4B55CE5D1C3B7D6F0093A61B /* CSOpenGLView.m in Sources */, 4BB697CB1D4B6D3E00248BDF /* TimedEventLoop.cpp in Sources */, + 4B54C0C21F8D91CD0050900F /* KeyboardMapper.cpp in Sources */, 4BBC951E1F368D83008F4C34 /* i8272.cpp in Sources */, 4BF1354C1D6D2C300054B2EA /* StaticAnalyser.cpp in Sources */, 4B4A76301DB1A3FA007AAE2E /* AY38910.cpp in Sources */, @@ -3024,6 +3056,7 @@ 4BEE0A6F1D72496600532C7B /* Cartridge.cpp in Sources */, 4B8805FB1DCFF807003085B1 /* Oric.cpp in Sources */, 4B5FADC01DE3BF2B00AEC565 /* Microdisc.cpp in Sources */, + 4B54C0C81F8D91E50050900F /* KeyboardMapper.cpp in Sources */, 4BEE0A701D72496600532C7B /* PRG.cpp in Sources */, 4B8334861F5DA3780097E338 /* 6502Storage.cpp in Sources */, 4B8FE2271DA1DE2D0090D3CE /* NSBundle+DataResource.m in Sources */, @@ -3034,6 +3067,7 @@ 4B2A539F1D117D36003C6002 /* CSAudioQueue.m in Sources */, 4B37EE821D7345A6006A09A4 /* BinaryDump.cpp in Sources */, 4B8334821F5D9FF70097E338 /* PartialMachineCycle.cpp in Sources */, + 4B54C0BC1F8D8E790050900F /* KeyboardMachine.cpp in Sources */, 4BB73EA21B587A5100552FC2 /* AppDelegate.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; diff --git a/OSBindings/Mac/Clock Signal/Machine/CSMachine.h b/OSBindings/Mac/Clock Signal/Machine/CSMachine.h index 8eaf2113e..0804bb987 100644 --- a/OSBindings/Mac/Clock Signal/Machine/CSMachine.h +++ b/OSBindings/Mac/Clock Signal/Machine/CSMachine.h @@ -46,4 +46,9 @@ - (void)paste:(NSString *)string; +// This is an informal implementation of the CSKeyboardMachine protocol; specific machines +// can decide whether they opt in as keyboard machines. +- (void)setKey:(uint16_t)key isPressed:(BOOL)isPressed; +- (void)clearAllKeys; + @end diff --git a/OSBindings/Mac/Clock Signal/Machine/CSMachine.mm b/OSBindings/Mac/Clock Signal/Machine/CSMachine.mm index a0d816ed6..763567a8b 100644 --- a/OSBindings/Mac/Clock Signal/Machine/CSMachine.mm +++ b/OSBindings/Mac/Clock Signal/Machine/CSMachine.mm @@ -10,6 +10,8 @@ #import "CSMachine+Subclassing.h" #import "CSMachine+Target.h" +#import "CSKeyboardMachine.h" + #include "Typer.hpp" #include "ConfigurationTarget.hpp" @@ -183,4 +185,78 @@ struct MachineDelegate: CRTMachine::Machine::Delegate, public LockProtectedDeleg } } +- (void)setKey:(uint16_t)key isPressed:(BOOL)isPressed { + auto keyboard_machine = dynamic_cast(_machine); + if(!keyboard_machine) return; + + @synchronized(self) { + Inputs::Keyboard &keyboard = keyboard_machine->get_keyboard(); + + // Connect the Carbon-era Mac keyboard scancodes to Clock Signal's 'universal' enumeration in order + // to pass into the platform-neutral realm. +#define BIND(source, dest) case source: keyboard.set_key_pressed(Inputs::Keyboard::Key::dest, isPressed); break + switch(key) { + BIND(VK_ANSI_0, k0); BIND(VK_ANSI_1, k1); BIND(VK_ANSI_2, k2); BIND(VK_ANSI_3, k3); BIND(VK_ANSI_4, k4); + BIND(VK_ANSI_5, k5); BIND(VK_ANSI_6, k6); BIND(VK_ANSI_7, k7); BIND(VK_ANSI_8, k8); BIND(VK_ANSI_9, k9); + + BIND(VK_ANSI_Q, Q); BIND(VK_ANSI_W, W); BIND(VK_ANSI_E, E); BIND(VK_ANSI_R, R); BIND(VK_ANSI_T, T); + BIND(VK_ANSI_Y, Y); BIND(VK_ANSI_U, U); BIND(VK_ANSI_I, I); BIND(VK_ANSI_O, O); BIND(VK_ANSI_P, P); + + BIND(VK_ANSI_A, A); BIND(VK_ANSI_S, S); BIND(VK_ANSI_D, D); BIND(VK_ANSI_F, F); BIND(VK_ANSI_G, G); + BIND(VK_ANSI_H, H); BIND(VK_ANSI_J, J); BIND(VK_ANSI_K, K); BIND(VK_ANSI_L, L); + + BIND(VK_ANSI_Z, Z); BIND(VK_ANSI_X, X); BIND(VK_ANSI_C, C); BIND(VK_ANSI_V, V); + BIND(VK_ANSI_B, B); BIND(VK_ANSI_N, N); BIND(VK_ANSI_M, M); + + BIND(VK_F1, F1); BIND(VK_F2, F2); BIND(VK_F3, F3); BIND(VK_F4, F4); + BIND(VK_F5, F5); BIND(VK_F6, F6); BIND(VK_F7, F7); BIND(VK_F8, F8); + BIND(VK_F9, F9); BIND(VK_F10, F10); BIND(VK_F11, F11); BIND(VK_F12, F12); + + BIND(VK_ANSI_Keypad0, KeyPad0); BIND(VK_ANSI_Keypad1, KeyPad1); BIND(VK_ANSI_Keypad2, KeyPad2); + BIND(VK_ANSI_Keypad3, KeyPad3); BIND(VK_ANSI_Keypad4, KeyPad4); BIND(VK_ANSI_Keypad5, KeyPad5); + BIND(VK_ANSI_Keypad6, KeyPad6); BIND(VK_ANSI_Keypad7, KeyPad7); BIND(VK_ANSI_Keypad8, KeyPad8); + BIND(VK_ANSI_Keypad9, KeyPad9); + + BIND(VK_ANSI_Equal, Equals); BIND(VK_ANSI_Minus, Hyphen); + BIND(VK_ANSI_RightBracket, CloseSquareBracket); BIND(VK_ANSI_LeftBracket, OpenSquareBracket); + BIND(VK_ANSI_Quote, Quote); BIND(VK_ANSI_Grave, BackTick); + + BIND(VK_ANSI_Semicolon, Semicolon); + BIND(VK_ANSI_Backslash, BackSlash); BIND(VK_ANSI_Slash, ForwardSlash); + BIND(VK_ANSI_Comma, Comma); BIND(VK_ANSI_Period, FullStop); + + BIND(VK_ANSI_KeypadDecimal, KeyPadDecimalPoint); BIND(VK_ANSI_KeypadEquals, KeyPadEquals); + BIND(VK_ANSI_KeypadMultiply, KeyPadAsterisk); BIND(VK_ANSI_KeypadDivide, KeyPadSlash); + BIND(VK_ANSI_KeypadPlus, KeyPadPlus); BIND(VK_ANSI_KeypadMinus, KeyPadMinus); + BIND(VK_ANSI_KeypadClear, KeyPadDelete); BIND(VK_ANSI_KeypadEnter, KeyPadEnter); + + BIND(VK_Return, Enter); BIND(VK_Tab, Tab); + BIND(VK_Space, Space); BIND(VK_Delete, BackSpace); + BIND(VK_Control, LeftControl); BIND(VK_Option, LeftOption); + BIND(VK_Command, LeftMeta); BIND(VK_Shift, LeftShift); + BIND(VK_RightControl, RightControl); BIND(VK_RightOption, RightOption); + BIND(VK_Escape, Escape); BIND(VK_CapsLock, CapsLock); + BIND(VK_Home, Home); BIND(VK_End, End); + BIND(VK_PageUp, PageUp); BIND(VK_PageDown, PageDown); + + BIND(VK_RightShift, RightShift); + BIND(VK_Help, Help); + BIND(VK_ForwardDelete, Delete); + + BIND(VK_LeftArrow, Left); BIND(VK_RightArrow, Right); + BIND(VK_DownArrow, Down); BIND(VK_UpArrow, Up); + } +#undef BIND + } +} + +- (void)clearAllKeys { + auto keyboard_machine = dynamic_cast(_machine); + if(!keyboard_machine) return; + + @synchronized(self) { + keyboard_machine->get_keyboard().reset_all_keys(); + } +} + @end diff --git a/OSBindings/Mac/Clock Signal/Machine/Wrappers/CSAmstradCPC.mm b/OSBindings/Mac/Clock Signal/Machine/Wrappers/CSAmstradCPC.mm index d3aa3eb47..f129bdecb 100644 --- a/OSBindings/Mac/Clock Signal/Machine/Wrappers/CSAmstradCPC.mm +++ b/OSBindings/Mac/Clock Signal/Machine/Wrappers/CSAmstradCPC.mm @@ -55,98 +55,4 @@ - (NSString *)userDefaultsPrefix { return @"amstradCPC"; } -#pragma mark - Keyboard Mapping - -- (void)clearAllKeys { - @synchronized(self) { - _amstradCPC->clear_all_keys(); - } -} - -- (void)setKey:(uint16_t)key isPressed:(BOOL)isPressed { - @synchronized(self) { - switch(key) { - case VK_ANSI_0: _amstradCPC->set_key_state(AmstradCPC::Key::Key0, isPressed); break; - case VK_ANSI_1: _amstradCPC->set_key_state(AmstradCPC::Key::Key1, isPressed); break; - case VK_ANSI_2: _amstradCPC->set_key_state(AmstradCPC::Key::Key2, isPressed); break; - case VK_ANSI_3: _amstradCPC->set_key_state(AmstradCPC::Key::Key3, isPressed); break; - case VK_ANSI_4: _amstradCPC->set_key_state(AmstradCPC::Key::Key4, isPressed); break; - case VK_ANSI_5: _amstradCPC->set_key_state(AmstradCPC::Key::Key5, isPressed); break; - case VK_ANSI_6: _amstradCPC->set_key_state(AmstradCPC::Key::Key6, isPressed); break; - case VK_ANSI_7: _amstradCPC->set_key_state(AmstradCPC::Key::Key7, isPressed); break; - case VK_ANSI_8: _amstradCPC->set_key_state(AmstradCPC::Key::Key8, isPressed); break; - case VK_ANSI_9: _amstradCPC->set_key_state(AmstradCPC::Key::Key9, isPressed); break; - - case VK_ANSI_Q: _amstradCPC->set_key_state(AmstradCPC::Key::KeyQ, isPressed); break; - case VK_ANSI_W: _amstradCPC->set_key_state(AmstradCPC::Key::KeyW, isPressed); break; - case VK_ANSI_E: _amstradCPC->set_key_state(AmstradCPC::Key::KeyE, isPressed); break; - case VK_ANSI_R: _amstradCPC->set_key_state(AmstradCPC::Key::KeyR, isPressed); break; - case VK_ANSI_T: _amstradCPC->set_key_state(AmstradCPC::Key::KeyT, isPressed); break; - case VK_ANSI_Y: _amstradCPC->set_key_state(AmstradCPC::Key::KeyY, isPressed); break; - case VK_ANSI_U: _amstradCPC->set_key_state(AmstradCPC::Key::KeyU, isPressed); break; - case VK_ANSI_I: _amstradCPC->set_key_state(AmstradCPC::Key::KeyI, isPressed); break; - case VK_ANSI_O: _amstradCPC->set_key_state(AmstradCPC::Key::KeyO, isPressed); break; - case VK_ANSI_P: _amstradCPC->set_key_state(AmstradCPC::Key::KeyP, isPressed); break; - case VK_ANSI_A: _amstradCPC->set_key_state(AmstradCPC::Key::KeyA, isPressed); break; - case VK_ANSI_S: _amstradCPC->set_key_state(AmstradCPC::Key::KeyS, isPressed); break; - case VK_ANSI_D: _amstradCPC->set_key_state(AmstradCPC::Key::KeyD, isPressed); break; - case VK_ANSI_F: _amstradCPC->set_key_state(AmstradCPC::Key::KeyF, isPressed); break; - case VK_ANSI_G: _amstradCPC->set_key_state(AmstradCPC::Key::KeyG, isPressed); break; - case VK_ANSI_H: _amstradCPC->set_key_state(AmstradCPC::Key::KeyH, isPressed); break; - case VK_ANSI_J: _amstradCPC->set_key_state(AmstradCPC::Key::KeyJ, isPressed); break; - case VK_ANSI_K: _amstradCPC->set_key_state(AmstradCPC::Key::KeyK, isPressed); break; - case VK_ANSI_L: _amstradCPC->set_key_state(AmstradCPC::Key::KeyL, isPressed); break; - case VK_ANSI_Z: _amstradCPC->set_key_state(AmstradCPC::Key::KeyZ, isPressed); break; - case VK_ANSI_X: _amstradCPC->set_key_state(AmstradCPC::Key::KeyX, isPressed); break; - case VK_ANSI_C: _amstradCPC->set_key_state(AmstradCPC::Key::KeyC, isPressed); break; - case VK_ANSI_V: _amstradCPC->set_key_state(AmstradCPC::Key::KeyV, isPressed); break; - case VK_ANSI_B: _amstradCPC->set_key_state(AmstradCPC::Key::KeyB, isPressed); break; - case VK_ANSI_N: _amstradCPC->set_key_state(AmstradCPC::Key::KeyN, isPressed); break; - case VK_ANSI_M: _amstradCPC->set_key_state(AmstradCPC::Key::KeyM, isPressed); break; - - case VK_Space: _amstradCPC->set_key_state(AmstradCPC::Key::KeySpace, isPressed); break; - case VK_ANSI_Grave: _amstradCPC->set_key_state(AmstradCPC::Key::KeyCopy, isPressed); break; - case VK_Return: _amstradCPC->set_key_state(AmstradCPC::Key::KeyReturn, isPressed); break; - case VK_ANSI_Minus: _amstradCPC->set_key_state(AmstradCPC::Key::KeyMinus, isPressed); break; - - case VK_RightArrow: _amstradCPC->set_key_state(AmstradCPC::Key::KeyRight, isPressed); break; - case VK_LeftArrow: _amstradCPC->set_key_state(AmstradCPC::Key::KeyLeft, isPressed); break; - case VK_DownArrow: _amstradCPC->set_key_state(AmstradCPC::Key::KeyDown, isPressed); break; - case VK_UpArrow: _amstradCPC->set_key_state(AmstradCPC::Key::KeyUp, isPressed); break; - - case VK_Delete: _amstradCPC->set_key_state(AmstradCPC::Key::KeyDelete, isPressed); break; - case VK_Escape: _amstradCPC->set_key_state(AmstradCPC::Key::KeyEscape, isPressed); break; - - case VK_ANSI_Comma: _amstradCPC->set_key_state(AmstradCPC::Key::KeyComma, isPressed); break; - case VK_ANSI_Period: _amstradCPC->set_key_state(AmstradCPC::Key::KeyFullStop, isPressed); break; - - case VK_ANSI_Semicolon: - _amstradCPC->set_key_state(AmstradCPC::Key::KeySemicolon, isPressed); break; - case VK_ANSI_Quote: _amstradCPC->set_key_state(AmstradCPC::Key::KeyColon, isPressed); break; - - case VK_ANSI_Slash: _amstradCPC->set_key_state(AmstradCPC::Key::KeyForwardSlash, isPressed); break; - case VK_ANSI_Backslash: _amstradCPC->set_key_state(AmstradCPC::Key::KeyBackSlash, isPressed); break; - - case VK_Shift: _amstradCPC->set_key_state(AmstradCPC::Key::KeyShift, isPressed); break; - case VK_Control: _amstradCPC->set_key_state(AmstradCPC::Key::KeyControl, isPressed); break; - - case VK_F1: _amstradCPC->set_key_state(AmstradCPC::Key::KeyF1, isPressed); break; - case VK_F2: _amstradCPC->set_key_state(AmstradCPC::Key::KeyF2, isPressed); break; - case VK_F3: _amstradCPC->set_key_state(AmstradCPC::Key::KeyF3, isPressed); break; - case VK_F4: _amstradCPC->set_key_state(AmstradCPC::Key::KeyF4, isPressed); break; - case VK_F5: _amstradCPC->set_key_state(AmstradCPC::Key::KeyF5, isPressed); break; - case VK_F6: _amstradCPC->set_key_state(AmstradCPC::Key::KeyF6, isPressed); break; - case VK_F7: _amstradCPC->set_key_state(AmstradCPC::Key::KeyF7, isPressed); break; - case VK_F8: _amstradCPC->set_key_state(AmstradCPC::Key::KeyF8, isPressed); break; - case VK_F9: _amstradCPC->set_key_state(AmstradCPC::Key::KeyF9, isPressed); break; - case VK_F10: _amstradCPC->set_key_state(AmstradCPC::Key::KeyF0, isPressed); break; - case VK_F12: _amstradCPC->set_key_state(AmstradCPC::Key::KeyFDot, isPressed); break; - - default: -// printf("%02x\n", key); - break; - } - } -} - @end diff --git a/OSBindings/Mac/Clock Signal/Machine/Wrappers/CSElectron.mm b/OSBindings/Mac/Clock Signal/Machine/Wrappers/CSElectron.mm index 496f87fef..8a9611ed3 100644 --- a/OSBindings/Mac/Clock Signal/Machine/Wrappers/CSElectron.mm +++ b/OSBindings/Mac/Clock Signal/Machine/Wrappers/CSElectron.mm @@ -57,94 +57,6 @@ } } -#pragma mark - Keyboard Mapping - -- (void)clearAllKeys { - @synchronized(self) { - _electron->clear_all_keys(); - } -} - -- (void)setKey:(uint16_t)key isPressed:(BOOL)isPressed { - @synchronized(self) { - switch(key) - { - case VK_ANSI_0: _electron->set_key_state(Electron::Key::Key0, isPressed); break; - case VK_ANSI_1: _electron->set_key_state(Electron::Key::Key1, isPressed); break; - case VK_ANSI_2: _electron->set_key_state(Electron::Key::Key2, isPressed); break; - case VK_ANSI_3: _electron->set_key_state(Electron::Key::Key3, isPressed); break; - case VK_ANSI_4: _electron->set_key_state(Electron::Key::Key4, isPressed); break; - case VK_ANSI_5: _electron->set_key_state(Electron::Key::Key5, isPressed); break; - case VK_ANSI_6: _electron->set_key_state(Electron::Key::Key6, isPressed); break; - case VK_ANSI_7: _electron->set_key_state(Electron::Key::Key7, isPressed); break; - case VK_ANSI_8: _electron->set_key_state(Electron::Key::Key8, isPressed); break; - case VK_ANSI_9: _electron->set_key_state(Electron::Key::Key9, isPressed); break; - - case VK_ANSI_Q: _electron->set_key_state(Electron::Key::KeyQ, isPressed); break; - case VK_ANSI_W: _electron->set_key_state(Electron::Key::KeyW, isPressed); break; - case VK_ANSI_E: _electron->set_key_state(Electron::Key::KeyE, isPressed); break; - case VK_ANSI_R: _electron->set_key_state(Electron::Key::KeyR, isPressed); break; - case VK_ANSI_T: _electron->set_key_state(Electron::Key::KeyT, isPressed); break; - case VK_ANSI_Y: _electron->set_key_state(Electron::Key::KeyY, isPressed); break; - case VK_ANSI_U: _electron->set_key_state(Electron::Key::KeyU, isPressed); break; - case VK_ANSI_I: _electron->set_key_state(Electron::Key::KeyI, isPressed); break; - case VK_ANSI_O: _electron->set_key_state(Electron::Key::KeyO, isPressed); break; - case VK_ANSI_P: _electron->set_key_state(Electron::Key::KeyP, isPressed); break; - case VK_ANSI_A: _electron->set_key_state(Electron::Key::KeyA, isPressed); break; - case VK_ANSI_S: _electron->set_key_state(Electron::Key::KeyS, isPressed); break; - case VK_ANSI_D: _electron->set_key_state(Electron::Key::KeyD, isPressed); break; - case VK_ANSI_F: _electron->set_key_state(Electron::Key::KeyF, isPressed); break; - case VK_ANSI_G: _electron->set_key_state(Electron::Key::KeyG, isPressed); break; - case VK_ANSI_H: _electron->set_key_state(Electron::Key::KeyH, isPressed); break; - case VK_ANSI_J: _electron->set_key_state(Electron::Key::KeyJ, isPressed); break; - case VK_ANSI_K: _electron->set_key_state(Electron::Key::KeyK, isPressed); break; - case VK_ANSI_L: _electron->set_key_state(Electron::Key::KeyL, isPressed); break; - case VK_ANSI_Z: _electron->set_key_state(Electron::Key::KeyZ, isPressed); break; - case VK_ANSI_X: _electron->set_key_state(Electron::Key::KeyX, isPressed); break; - case VK_ANSI_C: _electron->set_key_state(Electron::Key::KeyC, isPressed); break; - case VK_ANSI_V: _electron->set_key_state(Electron::Key::KeyV, isPressed); break; - case VK_ANSI_B: _electron->set_key_state(Electron::Key::KeyB, isPressed); break; - case VK_ANSI_N: _electron->set_key_state(Electron::Key::KeyN, isPressed); break; - case VK_ANSI_M: _electron->set_key_state(Electron::Key::KeyM, isPressed); break; - - case VK_Space: _electron->set_key_state(Electron::Key::KeySpace, isPressed); break; - case VK_ANSI_Grave: - case VK_ANSI_Backslash: - _electron->set_key_state(Electron::Key::KeyCopy, isPressed); break; - case VK_Return: _electron->set_key_state(Electron::Key::KeyReturn, isPressed); break; - case VK_ANSI_Minus: _electron->set_key_state(Electron::Key::KeyMinus, isPressed); break; - - case VK_RightArrow: _electron->set_key_state(Electron::Key::KeyRight, isPressed); break; - case VK_LeftArrow: _electron->set_key_state(Electron::Key::KeyLeft, isPressed); break; - case VK_DownArrow: _electron->set_key_state(Electron::Key::KeyDown, isPressed); break; - case VK_UpArrow: _electron->set_key_state(Electron::Key::KeyUp, isPressed); break; - - case VK_Delete: _electron->set_key_state(Electron::Key::KeyDelete, isPressed); break; - case VK_Escape: _electron->set_key_state(Electron::Key::KeyEscape, isPressed); break; - - case VK_ANSI_Comma: _electron->set_key_state(Electron::Key::KeyComma, isPressed); break; - case VK_ANSI_Period: _electron->set_key_state(Electron::Key::KeyFullStop, isPressed); break; - - case VK_ANSI_Semicolon: - _electron->set_key_state(Electron::Key::KeySemiColon, isPressed); break; - case VK_ANSI_Quote: _electron->set_key_state(Electron::Key::KeyColon, isPressed); break; - - case VK_ANSI_Slash: _electron->set_key_state(Electron::Key::KeySlash, isPressed); break; - - case VK_Shift: _electron->set_key_state(Electron::Key::KeyShift, isPressed); break; - case VK_Control: _electron->set_key_state(Electron::Key::KeyControl, isPressed); break; - case VK_Command: - case VK_Option: _electron->set_key_state(Electron::Key::KeyFunc, isPressed); break; - - case VK_F12: _electron->set_key_state(Electron::Key::KeyBreak, isPressed); break; - - default: -// printf("%02x\n", key); - break; - } - } -} - - (NSString *)userDefaultsPrefix { return @"electron"; } #pragma mark - Options diff --git a/OSBindings/Mac/Clock Signal/Machine/Wrappers/CSOric.mm b/OSBindings/Mac/Clock Signal/Machine/Wrappers/CSOric.mm index 672be644d..2e9a5daf0 100644 --- a/OSBindings/Mac/Clock Signal/Machine/Wrappers/CSOric.mm +++ b/OSBindings/Mac/Clock Signal/Machine/Wrappers/CSOric.mm @@ -43,99 +43,6 @@ return [[NSBundle mainBundle] dataForResource:name withExtension:@"rom" subdirectory:@"ROMImages/Oric"]; } -#pragma mark - CSKeyboardMachine - -- (void)setKey:(uint16_t)key isPressed:(BOOL)isPressed { - @synchronized(self) { - switch(key) { - case VK_ANSI_0: _oric->set_key_state(Oric::Key::Key0, isPressed); break; - case VK_ANSI_1: _oric->set_key_state(Oric::Key::Key1, isPressed); break; - case VK_ANSI_2: _oric->set_key_state(Oric::Key::Key2, isPressed); break; - case VK_ANSI_3: _oric->set_key_state(Oric::Key::Key3, isPressed); break; - case VK_ANSI_4: _oric->set_key_state(Oric::Key::Key4, isPressed); break; - case VK_ANSI_5: _oric->set_key_state(Oric::Key::Key5, isPressed); break; - case VK_ANSI_6: _oric->set_key_state(Oric::Key::Key6, isPressed); break; - case VK_ANSI_7: _oric->set_key_state(Oric::Key::Key7, isPressed); break; - case VK_ANSI_8: _oric->set_key_state(Oric::Key::Key8, isPressed); break; - case VK_ANSI_9: _oric->set_key_state(Oric::Key::Key9, isPressed); break; - - case VK_ANSI_Q: _oric->set_key_state(Oric::Key::KeyQ, isPressed); break; - case VK_ANSI_W: _oric->set_key_state(Oric::Key::KeyW, isPressed); break; - case VK_ANSI_E: _oric->set_key_state(Oric::Key::KeyE, isPressed); break; - case VK_ANSI_R: _oric->set_key_state(Oric::Key::KeyR, isPressed); break; - case VK_ANSI_T: _oric->set_key_state(Oric::Key::KeyT, isPressed); break; - case VK_ANSI_Y: _oric->set_key_state(Oric::Key::KeyY, isPressed); break; - case VK_ANSI_U: _oric->set_key_state(Oric::Key::KeyU, isPressed); break; - case VK_ANSI_I: _oric->set_key_state(Oric::Key::KeyI, isPressed); break; - case VK_ANSI_O: _oric->set_key_state(Oric::Key::KeyO, isPressed); break; - case VK_ANSI_P: _oric->set_key_state(Oric::Key::KeyP, isPressed); break; - case VK_ANSI_A: _oric->set_key_state(Oric::Key::KeyA, isPressed); break; - case VK_ANSI_S: _oric->set_key_state(Oric::Key::KeyS, isPressed); break; - case VK_ANSI_D: _oric->set_key_state(Oric::Key::KeyD, isPressed); break; - case VK_ANSI_F: _oric->set_key_state(Oric::Key::KeyF, isPressed); break; - case VK_ANSI_G: _oric->set_key_state(Oric::Key::KeyG, isPressed); break; - case VK_ANSI_H: _oric->set_key_state(Oric::Key::KeyH, isPressed); break; - case VK_ANSI_J: _oric->set_key_state(Oric::Key::KeyJ, isPressed); break; - case VK_ANSI_K: _oric->set_key_state(Oric::Key::KeyK, isPressed); break; - case VK_ANSI_L: _oric->set_key_state(Oric::Key::KeyL, isPressed); break; - case VK_ANSI_Z: _oric->set_key_state(Oric::Key::KeyZ, isPressed); break; - case VK_ANSI_X: _oric->set_key_state(Oric::Key::KeyX, isPressed); break; - case VK_ANSI_C: _oric->set_key_state(Oric::Key::KeyC, isPressed); break; - case VK_ANSI_V: _oric->set_key_state(Oric::Key::KeyV, isPressed); break; - case VK_ANSI_B: _oric->set_key_state(Oric::Key::KeyB, isPressed); break; - case VK_ANSI_N: _oric->set_key_state(Oric::Key::KeyN, isPressed); break; - case VK_ANSI_M: _oric->set_key_state(Oric::Key::KeyM, isPressed); break; - - case VK_Space: _oric->set_key_state(Oric::Key::KeySpace, isPressed); break; - case VK_Return: _oric->set_key_state(Oric::Key::KeyReturn, isPressed); break; - case VK_ANSI_Minus: _oric->set_key_state(Oric::Key::KeyMinus, isPressed); break; - case VK_ANSI_Equal: _oric->set_key_state(Oric::Key::KeyEquals, isPressed); break; - case VK_ANSI_Backslash: - _oric->set_key_state(Oric::Key::KeyBackSlash, isPressed); break; - case VK_ANSI_Slash: _oric->set_key_state(Oric::Key::KeyForwardSlash, isPressed); break; - - case VK_ANSI_LeftBracket: - _oric->set_key_state(Oric::Key::KeyOpenSquare, isPressed); break; - case VK_ANSI_RightBracket: - _oric->set_key_state(Oric::Key::KeyCloseSquare, isPressed); break; - case VK_ANSI_Quote: _oric->set_key_state(Oric::Key::KeyQuote, isPressed); break; - - case VK_RightArrow: _oric->set_key_state(Oric::Key::KeyRight, isPressed); break; - case VK_LeftArrow: _oric->set_key_state(Oric::Key::KeyLeft, isPressed); break; - case VK_DownArrow: _oric->set_key_state(Oric::Key::KeyDown, isPressed); break; - case VK_UpArrow: _oric->set_key_state(Oric::Key::KeyUp, isPressed); break; - - case VK_Delete: _oric->set_key_state(Oric::Key::KeyDelete, isPressed); break; - case VK_Escape: _oric->set_key_state(Oric::Key::KeyEscape, isPressed); break; - - case VK_ANSI_Comma: _oric->set_key_state(Oric::Key::KeyComma, isPressed); break; - case VK_ANSI_Period: _oric->set_key_state(Oric::Key::KeyFullStop, isPressed); break; - - case VK_ANSI_Semicolon: _oric->set_key_state(Oric::Key::KeySemiColon, isPressed); break; - - case VK_Shift: - _oric->set_key_state(Oric::Key::KeyLeftShift, isPressed); - _oric->set_key_state(Oric::Key::KeyRightShift, isPressed); - break; - case VK_RightShift: _oric->set_key_state(Oric::Key::KeyRightShift, isPressed); break; - case VK_Control: _oric->set_key_state(Oric::Key::KeyControl, isPressed); break; - - case VK_ANSI_Grave: - case VK_F12: _oric->set_key_state(Oric::Key::KeyNMI, isPressed); break; - - default: - printf("%02x\n", key); - break; - } - } -} - -- (void)clearAllKeys { - @synchronized(self) { - _oric->clear_all_keys(); - } -} - #pragma mark - Options - (void)setUseFastLoadingHack:(BOOL)useFastLoadingHack { diff --git a/OSBindings/Mac/Clock Signal/Machine/Wrappers/CSVic20.mm b/OSBindings/Mac/Clock Signal/Machine/Wrappers/CSVic20.mm index 4740c3e64..6a23f93e9 100644 --- a/OSBindings/Mac/Clock Signal/Machine/Wrappers/CSVic20.mm +++ b/OSBindings/Mac/Clock Signal/Machine/Wrappers/CSVic20.mm @@ -68,28 +68,8 @@ using namespace Commodore::Vic20; #pragma mark - Keyboard map -- (void)setKey:(uint16_t)key isPressed:(BOOL)isPressed { +/*- (void)setKey:(uint16_t)key isPressed:(BOOL)isPressed { static NSDictionary *vicKeysByKeys = @{ - @(VK_ANSI_1): @(Key::Key1), @(VK_ANSI_2): @(Key::Key2), - @(VK_ANSI_3): @(Key::Key3), @(VK_ANSI_4): @(Key::Key4), - @(VK_ANSI_5): @(Key::Key5), @(VK_ANSI_6): @(Key::Key6), - @(VK_ANSI_7): @(Key::Key7), @(VK_ANSI_8): @(Key::Key8), - @(VK_ANSI_9): @(Key::Key9), @(VK_ANSI_0): @(Key::Key0), - - @(VK_ANSI_Q): @(Key::KeyQ), @(VK_ANSI_W): @(Key::KeyW), - @(VK_ANSI_E): @(Key::KeyE), @(VK_ANSI_R): @(Key::KeyR), - @(VK_ANSI_T): @(Key::KeyT), @(VK_ANSI_Y): @(Key::KeyY), - @(VK_ANSI_U): @(Key::KeyU), @(VK_ANSI_I): @(Key::KeyI), - @(VK_ANSI_O): @(Key::KeyO), @(VK_ANSI_P): @(Key::KeyP), - @(VK_ANSI_A): @(Key::KeyA), @(VK_ANSI_S): @(Key::KeyS), - @(VK_ANSI_D): @(Key::KeyD), @(VK_ANSI_F): @(Key::KeyF), - @(VK_ANSI_G): @(Key::KeyG), @(VK_ANSI_H): @(Key::KeyH), - @(VK_ANSI_J): @(Key::KeyJ), @(VK_ANSI_K): @(Key::KeyK), - @(VK_ANSI_L): @(Key::KeyL), @(VK_ANSI_Z): @(Key::KeyZ), - @(VK_ANSI_X): @(Key::KeyX), @(VK_ANSI_C): @(Key::KeyC), - @(VK_ANSI_V): @(Key::KeyV), @(VK_ANSI_B): @(Key::KeyB), - @(VK_ANSI_N): @(Key::KeyN), @(VK_ANSI_M): @(Key::KeyM), - @(VK_Space): @(Key::KeySpace), @(VK_Return): @(Key::KeyReturn), @(VK_Delete): @(Key::KeyDelete), @@ -156,13 +136,7 @@ using namespace Commodore::Vic20; } } } -} - -- (void)clearAllKeys { - @synchronized(self) { - _vic20->clear_all_keys(); - } -} +}*/ #pragma mark - Public configuration options diff --git a/OSBindings/Mac/Clock Signal/Machine/Wrappers/CSZX8081.mm b/OSBindings/Mac/Clock Signal/Machine/Wrappers/CSZX8081.mm index 2315d69d2..fb5d07578 100644 --- a/OSBindings/Mac/Clock Signal/Machine/Wrappers/CSZX8081.mm +++ b/OSBindings/Mac/Clock Signal/Machine/Wrappers/CSZX8081.mm @@ -34,69 +34,6 @@ return [[NSBundle mainBundle] dataForResource:name withExtension:@"rom" subdirectory:@"ROMImages/ZX8081"]; } -#pragma mark - Keyboard Mapping - -- (void)clearAllKeys { - @synchronized(self) { - _zx8081->clear_all_keys(); - } -} - -- (void)setKey:(uint16_t)key isPressed:(BOOL)isPressed { - @synchronized(self) { - switch(key) { - case VK_ANSI_0: _zx8081->set_key_state(ZX8081::Key::Key0, isPressed); break; - case VK_ANSI_1: _zx8081->set_key_state(ZX8081::Key::Key1, isPressed); break; - case VK_ANSI_2: _zx8081->set_key_state(ZX8081::Key::Key2, isPressed); break; - case VK_ANSI_3: _zx8081->set_key_state(ZX8081::Key::Key3, isPressed); break; - case VK_ANSI_4: _zx8081->set_key_state(ZX8081::Key::Key4, isPressed); break; - case VK_ANSI_5: _zx8081->set_key_state(ZX8081::Key::Key5, isPressed); break; - case VK_ANSI_6: _zx8081->set_key_state(ZX8081::Key::Key6, isPressed); break; - case VK_ANSI_7: _zx8081->set_key_state(ZX8081::Key::Key7, isPressed); break; - case VK_ANSI_8: _zx8081->set_key_state(ZX8081::Key::Key8, isPressed); break; - case VK_ANSI_9: _zx8081->set_key_state(ZX8081::Key::Key9, isPressed); break; - - case VK_ANSI_Q: _zx8081->set_key_state(ZX8081::Key::KeyQ, isPressed); break; - case VK_ANSI_W: _zx8081->set_key_state(ZX8081::Key::KeyW, isPressed); break; - case VK_ANSI_E: _zx8081->set_key_state(ZX8081::Key::KeyE, isPressed); break; - case VK_ANSI_R: _zx8081->set_key_state(ZX8081::Key::KeyR, isPressed); break; - case VK_ANSI_T: _zx8081->set_key_state(ZX8081::Key::KeyT, isPressed); break; - case VK_ANSI_Y: _zx8081->set_key_state(ZX8081::Key::KeyY, isPressed); break; - case VK_ANSI_U: _zx8081->set_key_state(ZX8081::Key::KeyU, isPressed); break; - case VK_ANSI_I: _zx8081->set_key_state(ZX8081::Key::KeyI, isPressed); break; - case VK_ANSI_O: _zx8081->set_key_state(ZX8081::Key::KeyO, isPressed); break; - case VK_ANSI_P: _zx8081->set_key_state(ZX8081::Key::KeyP, isPressed); break; - - case VK_ANSI_A: _zx8081->set_key_state(ZX8081::Key::KeyA, isPressed); break; - case VK_ANSI_S: _zx8081->set_key_state(ZX8081::Key::KeyS, isPressed); break; - case VK_ANSI_D: _zx8081->set_key_state(ZX8081::Key::KeyD, isPressed); break; - case VK_ANSI_F: _zx8081->set_key_state(ZX8081::Key::KeyF, isPressed); break; - case VK_ANSI_G: _zx8081->set_key_state(ZX8081::Key::KeyG, isPressed); break; - case VK_ANSI_H: _zx8081->set_key_state(ZX8081::Key::KeyH, isPressed); break; - case VK_ANSI_J: _zx8081->set_key_state(ZX8081::Key::KeyJ, isPressed); break; - case VK_ANSI_K: _zx8081->set_key_state(ZX8081::Key::KeyK, isPressed); break; - case VK_ANSI_L: _zx8081->set_key_state(ZX8081::Key::KeyL, isPressed); break; - - case VK_ANSI_Z: _zx8081->set_key_state(ZX8081::Key::KeyZ, isPressed); break; - case VK_ANSI_X: _zx8081->set_key_state(ZX8081::Key::KeyX, isPressed); break; - case VK_ANSI_C: _zx8081->set_key_state(ZX8081::Key::KeyC, isPressed); break; - case VK_ANSI_V: _zx8081->set_key_state(ZX8081::Key::KeyV, isPressed); break; - case VK_ANSI_B: _zx8081->set_key_state(ZX8081::Key::KeyB, isPressed); break; - case VK_ANSI_N: _zx8081->set_key_state(ZX8081::Key::KeyN, isPressed); break; - case VK_ANSI_M: _zx8081->set_key_state(ZX8081::Key::KeyM, isPressed); break; - - case VK_Shift: - case VK_RightShift: - _zx8081->set_key_state(ZX8081::Key::KeyShift, isPressed); break; - break; - - case VK_ANSI_Period:_zx8081->set_key_state(ZX8081::Key::KeyDot, isPressed); break; - case VK_Return: _zx8081->set_key_state(ZX8081::Key::KeyEnter, isPressed); break; - case VK_Space: _zx8081->set_key_state(ZX8081::Key::KeySpace, isPressed); break; - } - } -} - - (NSString *)userDefaultsPrefix { return @"zx8081"; } #pragma mark - Options From 4f289ab10bed498de206858e43f7bace50f349b9 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Thu, 12 Oct 2017 22:33:00 -0400 Subject: [PATCH 03/16] Corrects some deficiencies in Vic-20 keyboard mapping. ... albeit without yet being clear on the wiring behind restore. --- Machines/Commodore/Vic-20/KeyboardMapper.cpp | 6 ++++++ Machines/Commodore/Vic-20/Vic20.cpp | 12 ++++++++---- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/Machines/Commodore/Vic-20/KeyboardMapper.cpp b/Machines/Commodore/Vic-20/KeyboardMapper.cpp index 98e82b589..013da837d 100644 --- a/Machines/Commodore/Vic-20/KeyboardMapper.cpp +++ b/Machines/Commodore/Vic-20/KeyboardMapper.cpp @@ -61,6 +61,12 @@ uint16_t KeyboardMapper::mapped_key_for_key(Inputs::Keyboard::Key key) { BIND(Enter, KeyReturn); BIND(Space, KeySpace); BIND(BackSpace, KeyDelete); + + BIND(Escape, KeyRunStop); + BIND(F1, KeyF1); + BIND(F3, KeyF3); + BIND(F5, KeyF5); + BIND(F7, KeyF7); } #undef BIND return KeyboardMachine::Machine::KeyNotMapped; diff --git a/Machines/Commodore/Vic-20/Vic20.cpp b/Machines/Commodore/Vic-20/Vic20.cpp index 8baf3ba6f..3ac582610 100644 --- a/Machines/Commodore/Vic-20/Vic20.cpp +++ b/Machines/Commodore/Vic-20/Vic20.cpp @@ -111,10 +111,14 @@ class KeyboardVIA: public MOS::MOS6522::IRQDelegatePortHandler { /// Sets whether @c key @c is_pressed. void set_key_state(uint16_t key, bool is_pressed) { - if(is_pressed) - columns_[key & 7] &= ~(key >> 3); - else - columns_[key & 7] |= (key >> 3); + if(key == KeyRestore) { + // TODO: how is restore wired? + } else { + if(is_pressed) + columns_[key & 7] &= ~(key >> 3); + else + columns_[key & 7] |= (key >> 3); + } } /// Sets all keys as unpressed. From 3a05ce36dec1376ed7d781a3026c19f7034e9742 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Sat, 14 Oct 2017 22:07:11 -0400 Subject: [PATCH 04/16] Adds a reference to the calling keyboard in `reset_all_keys`. --- Inputs/Keyboard.cpp | 2 +- Inputs/Keyboard.hpp | 4 ++-- Machines/KeyboardMachine.cpp | 2 +- Machines/KeyboardMachine.hpp | 4 ++-- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Inputs/Keyboard.cpp b/Inputs/Keyboard.cpp index c479c6a7f..6acfec9bc 100644 --- a/Inputs/Keyboard.cpp +++ b/Inputs/Keyboard.cpp @@ -24,7 +24,7 @@ void Keyboard::set_key_pressed(Key key, bool is_pressed) { void Keyboard::reset_all_keys() { std::fill(key_states_.begin(), key_states_.end(), false); - if(delegate_) delegate_->reset_all_keys(); + if(delegate_) delegate_->reset_all_keys(this); } void Keyboard::set_delegate(Delegate *delegate) { diff --git a/Inputs/Keyboard.hpp b/Inputs/Keyboard.hpp index 7d480c8c8..0506be2b0 100644 --- a/Inputs/Keyboard.hpp +++ b/Inputs/Keyboard.hpp @@ -46,11 +46,11 @@ class Keyboard { // Delegate interface. struct Delegate { virtual void keyboard_did_change_key(Keyboard *keyboard, Key key, bool is_pressed) = 0; - virtual void reset_all_keys() = 0; + virtual void reset_all_keys(Keyboard *keyboard) = 0; }; void set_delegate(Delegate *delegate); bool get_key_state(Key key); - + private: std::vector key_states_; Delegate *delegate_ = nullptr; diff --git a/Machines/KeyboardMachine.cpp b/Machines/KeyboardMachine.cpp index 36299cd13..c6562bee4 100644 --- a/Machines/KeyboardMachine.cpp +++ b/Machines/KeyboardMachine.cpp @@ -19,7 +19,7 @@ void Machine::keyboard_did_change_key(Inputs::Keyboard *keyboard, Inputs::Keyboa if(mapped_key != KeyNotMapped) set_key_state(mapped_key, is_pressed); } -void Machine::reset_all_keys() { +void Machine::reset_all_keys(Inputs::Keyboard *keyboard) { // TODO: unify naming. clear_all_keys(); } diff --git a/Machines/KeyboardMachine.hpp b/Machines/KeyboardMachine.hpp index a509002a6..0074a3ee2 100644 --- a/Machines/KeyboardMachine.hpp +++ b/Machines/KeyboardMachine.hpp @@ -59,8 +59,8 @@ class Machine: public Inputs::Keyboard::Delegate { virtual KeyboardMapper &get_keyboard_mapper() = 0; private: - void keyboard_did_change_key(Inputs::Keyboard *keyboard, Inputs::Keyboard::Key key, bool is_pressed); - void reset_all_keys(); + void keyboard_did_change_key(Inputs::Keyboard *keyboard, Inputs::Keyboard::Key key, bool is_pressed) override; + void reset_all_keys(Inputs::Keyboard *keyboard) override; Inputs::Keyboard keyboard_; }; From ee179aa7bd0f98dfe804d01c20bbadb8a620fb11 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Sat, 14 Oct 2017 22:36:31 -0400 Subject: [PATCH 05/16] Introduces a joystick analogue to the shared keyboard interface, and implements it for the Vic-20. --- Inputs/Joystick.cpp | 9 +++ Inputs/Joystick.hpp | 35 +++++++++ Machines/Commodore/Vic-20/Vic20.cpp | 49 ++++++++++++- Machines/Commodore/Vic-20/Vic20.hpp | 16 ++--- Machines/JoystickMachine.hpp | 24 +++++++ .../Clock Signal.xcodeproj/project.pbxproj | 8 +++ .../Clock Signal/Machine/Wrappers/CSVic20.mm | 72 ++----------------- 7 files changed, 132 insertions(+), 81 deletions(-) create mode 100644 Inputs/Joystick.cpp create mode 100644 Inputs/Joystick.hpp create mode 100644 Machines/JoystickMachine.hpp diff --git a/Inputs/Joystick.cpp b/Inputs/Joystick.cpp new file mode 100644 index 000000000..df0104423 --- /dev/null +++ b/Inputs/Joystick.cpp @@ -0,0 +1,9 @@ +// +// Joystick.cpp +// Clock Signal +// +// Created by Thomas Harte on 14/10/2017. +// Copyright © 2017 Thomas Harte. All rights reserved. +// + +#include "Joystick.hpp" diff --git a/Inputs/Joystick.hpp b/Inputs/Joystick.hpp new file mode 100644 index 000000000..4b2223075 --- /dev/null +++ b/Inputs/Joystick.hpp @@ -0,0 +1,35 @@ +// +// Joystick.hpp +// Clock Signal +// +// Created by Thomas Harte on 14/10/2017. +// Copyright © 2017 Thomas Harte. All rights reserved. +// + +#ifndef Joystick_hpp +#define Joystick_hpp + +#include + +namespace Inputs { + +/*! + Provides an intermediate idealised model of a simple joystick, allowing a host + machine to toggle states, while an interested party either observes or polls. +*/ +class Joystick { + public: + virtual ~Joystick() {} + + enum class DigitalInput { + Up, Down, Left, Right, Fire + }; + + // Host interface. + virtual void set_digital_input(DigitalInput digital_input, bool is_active) = 0; + virtual void reset_all_inputs() = 0; +}; + +} + +#endif /* Joystick_hpp */ diff --git a/Machines/Commodore/Vic-20/Vic20.cpp b/Machines/Commodore/Vic-20/Vic20.cpp index 3ac582610..a4d76525a 100644 --- a/Machines/Commodore/Vic-20/Vic20.cpp +++ b/Machines/Commodore/Vic-20/Vic20.cpp @@ -30,6 +30,14 @@ namespace Commodore { namespace Vic20 { +enum JoystickInput { + Up = 0x04, + Down = 0x08, + Left = 0x10, + Right = 0x80, + Fire = 0x20 +}; + /*! Models the user-port VIA, which is the Vic's connection point for controlling its tape recorder — sensing the presence or absence of a tape and controlling the tape motor — and reading the current @@ -214,6 +222,38 @@ class Vic6560: public MOS::MOS6560 { uint8_t *colour_memory; // Colour memory must be contiguous. }; +/*! + Interfaces a joystick to the two VIAs. +*/ +class Joystick: public Inputs::Joystick { + public: + Joystick(UserPortVIA &user_port_via_port_handler, KeyboardVIA &keyboard_via_port_handler) : + user_port_via_port_handler_(user_port_via_port_handler), + keyboard_via_port_handler_(keyboard_via_port_handler) {} + + void set_digital_input(DigitalInput digital_input, bool is_active) override { + JoystickInput mapped_input; + switch (digital_input) { + default: return; + case DigitalInput::Up: mapped_input = Up; break; + case DigitalInput::Down: mapped_input = Down; break; + case DigitalInput::Left: mapped_input = Left; break; + case DigitalInput::Right: mapped_input = Right; break; + case DigitalInput::Fire: mapped_input = Fire; break; + } + + user_port_via_port_handler_.set_joystick_state(mapped_input, is_active); + keyboard_via_port_handler_.set_joystick_state(mapped_input, is_active); + } + + void reset_all_inputs() override { + } + + private: + UserPortVIA &user_port_via_port_handler_; + KeyboardVIA &keyboard_via_port_handler_; +}; + class ConcreteMachine: public CPU::MOS6502::BusHandler, public MOS::MOS6522::IRQDelegatePortHandler::Delegate, @@ -253,6 +293,9 @@ class ConcreteMachine: // set the NTSC clock rate set_region(NTSC); + + // install a joystick + joysticks_.push_back(new Joystick(*user_port_via_port_handler_, *keyboard_via_port_handler_)); } ~ConcreteMachine() { @@ -340,9 +383,8 @@ class ConcreteMachine: keyboard_via_port_handler_->clear_all_keys(); } - void set_joystick_state(JoystickInput input, bool isPressed) override final { - user_port_via_port_handler_->set_joystick_state(input, isPressed); - keyboard_via_port_handler_->set_joystick_state(input, isPressed); + std::vector &get_joysticks() override { + return joysticks_; } void set_memory_size(MemorySize size) override final { @@ -580,6 +622,7 @@ class ConcreteMachine: Region region_; Commodore::Vic20::KeyboardMapper keyboard_mapper_; + std::vector joysticks_; std::unique_ptr mos6560_; std::shared_ptr user_port_via_port_handler_; diff --git a/Machines/Commodore/Vic-20/Vic20.hpp b/Machines/Commodore/Vic-20/Vic20.hpp index 53e94b28f..829c207f6 100644 --- a/Machines/Commodore/Vic-20/Vic20.hpp +++ b/Machines/Commodore/Vic-20/Vic20.hpp @@ -11,6 +11,8 @@ #include "../../ConfigurationTarget.hpp" #include "../../CRTMachine.hpp" +#include "../../KeyboardMachine.hpp" +#include "../../JoystickMachine.hpp" #include "../../Typer.hpp" #include @@ -59,18 +61,11 @@ enum Key: uint16_t { #undef key }; -enum JoystickInput { - Up = 0x04, - Down = 0x08, - Left = 0x10, - Right = 0x80, - Fire = 0x20 -}; - class Machine: public CRTMachine::Machine, public ConfigurationTarget::Machine, - public KeyboardMachine::Machine { + public KeyboardMachine::Machine, + public JoystickMachine::Machine { public: virtual ~Machine(); @@ -81,9 +76,6 @@ class Machine: virtual void set_rom(ROMSlot slot, size_t length, const uint8_t *data) = 0; // TODO: take a std::vector to collapse length and data. - /// Sets the state of joystick input @c input. - virtual void set_joystick_state(JoystickInput input, bool isPressed) = 0; - /// Sets the memory size of this Vic-20. virtual void set_memory_size(MemorySize size) = 0; diff --git a/Machines/JoystickMachine.hpp b/Machines/JoystickMachine.hpp new file mode 100644 index 000000000..bc7c4a783 --- /dev/null +++ b/Machines/JoystickMachine.hpp @@ -0,0 +1,24 @@ +// +// JoystickMachine.hpp +// Clock Signal +// +// Created by Thomas Harte on 14/10/2017. +// Copyright © 2017 Thomas Harte. All rights reserved. +// + +#ifndef JoystickMachine_hpp +#define JoystickMachine_hpp + +#include "../Inputs/Joystick.hpp" +#include + +namespace JoystickMachine { + +class Machine { + public: + virtual std::vector &get_joysticks() = 0; +}; + +} + +#endif /* JoystickMachine_hpp */ diff --git a/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj b/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj index b5f6f2549..db6b35038 100644 --- a/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj +++ b/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj @@ -100,6 +100,7 @@ 4B69FB441C4D941400B5F0AA /* TapeUEF.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B69FB421C4D941400B5F0AA /* TapeUEF.cpp */; }; 4B69FB461C4D950F00B5F0AA /* libz.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = 4B69FB451C4D950F00B5F0AA /* libz.tbd */; }; 4B6A4C991F58F09E00E3F787 /* 6502Base.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B6A4C951F58F09E00E3F787 /* 6502Base.cpp */; }; + 4B70412B1F92C2A700735E45 /* Joystick.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B7041291F92C2A700735E45 /* Joystick.cpp */; }; 4B7136861F78724F008B8ED9 /* Encoder.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B7136841F78724F008B8ED9 /* Encoder.cpp */; }; 4B7136891F78725F008B8ED9 /* Shifter.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B7136871F78725F008B8ED9 /* Shifter.cpp */; }; 4B71368E1F788112008B8ED9 /* Parser.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B71368C1F788112008B8ED9 /* Parser.cpp */; }; @@ -672,6 +673,9 @@ 4B6A4C911F58F09E00E3F787 /* 6502AllRAM.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = 6502AllRAM.cpp; sourceTree = ""; }; 4B6A4C921F58F09E00E3F787 /* 6502AllRAM.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = 6502AllRAM.hpp; sourceTree = ""; }; 4B6A4C951F58F09E00E3F787 /* 6502Base.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = 6502Base.cpp; sourceTree = ""; }; + 4B7041271F92C26900735E45 /* JoystickMachine.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = JoystickMachine.hpp; sourceTree = ""; }; + 4B7041291F92C2A700735E45 /* Joystick.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = Joystick.cpp; sourceTree = ""; }; + 4B70412A1F92C2A700735E45 /* Joystick.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = Joystick.hpp; sourceTree = ""; }; 4B7136841F78724F008B8ED9 /* Encoder.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Encoder.cpp; sourceTree = ""; }; 4B7136851F78724F008B8ED9 /* Encoder.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = Encoder.hpp; sourceTree = ""; }; 4B7136871F78725F008B8ED9 /* Shifter.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = Shifter.cpp; sourceTree = ""; }; @@ -1748,6 +1752,8 @@ children = ( 4B86E2591F8C628F006FAA45 /* Keyboard.cpp */, 4B86E25A1F8C628F006FAA45 /* Keyboard.hpp */, + 4B7041291F92C2A700735E45 /* Joystick.cpp */, + 4B70412A1F92C2A700735E45 /* Joystick.hpp */, ); name = Inputs; path = ../../Inputs; @@ -2203,6 +2209,7 @@ 4B1E85731D170228001EF87D /* Typer.cpp */, 4BA9C3CF1D8164A9002DDB61 /* ConfigurationTarget.hpp */, 4B046DC31CFE651500E9E45E /* CRTMachine.hpp */, + 4B7041271F92C26900735E45 /* JoystickMachine.hpp */, 4B8E4ECD1DCE483D003716C3 /* KeyboardMachine.hpp */, 4B2A33291DB8544D002876E3 /* MemoryFuzzer.hpp */, 4B1E85741D170228001EF87D /* Typer.hpp */, @@ -2995,6 +3002,7 @@ 4BC5E4921D7ED365008CF980 /* StaticAnalyser.cpp in Sources */, 4BC830D11D6E7C690000A26F /* Tape.cpp in Sources */, 4B54C0C51F8D91D90050900F /* KeyboardMapper.cpp in Sources */, + 4B70412B1F92C2A700735E45 /* Joystick.cpp in Sources */, 4B69FB441C4D941400B5F0AA /* TapeUEF.cpp in Sources */, 4B86E25B1F8C628F006FAA45 /* Keyboard.cpp in Sources */, 4B4518851F75E91A00926311 /* DiskController.cpp in Sources */, diff --git a/OSBindings/Mac/Clock Signal/Machine/Wrappers/CSVic20.mm b/OSBindings/Mac/Clock Signal/Machine/Wrappers/CSVic20.mm index 6a23f93e9..fbfbbe20c 100644 --- a/OSBindings/Mac/Clock Signal/Machine/Wrappers/CSVic20.mm +++ b/OSBindings/Mac/Clock Signal/Machine/Wrappers/CSVic20.mm @@ -69,73 +69,13 @@ using namespace Commodore::Vic20; #pragma mark - Keyboard map /*- (void)setKey:(uint16_t)key isPressed:(BOOL)isPressed { - static NSDictionary *vicKeysByKeys = @{ - @(VK_Space): @(Key::KeySpace), - @(VK_Return): @(Key::KeyReturn), - @(VK_Delete): @(Key::KeyDelete), - @(VK_ANSI_Comma): @(Key::KeyComma), - @(VK_ANSI_Period): @(Key::KeyFullStop), - @(VK_ANSI_Minus): @(Key::KeyDash), - @(VK_ANSI_Equal): @(Key::KeyEquals), - @(VK_ANSI_Semicolon): @(Key::KeyColon), - @(VK_ANSI_Quote): @(Key::KeySemicolon), - @(VK_ANSI_Slash): @(Key::KeySlash), - @(VK_Option): @(Key::KeyCBM), - @(VK_Control): @(Key::KeyControl), - - @(VK_F1): @(Key::KeyF1), @(VK_F3): @(Key::KeyF3), - @(VK_F5): @(Key::KeyF5), @(VK_F7): @(Key::KeyF7), - - @(VK_ANSI_Grave): @(Key::KeyLeft), - @(VK_Tab): @(Key::KeyRunStop), - @(VK_ANSI_LeftBracket): @(Key::KeyAt), - @(VK_ANSI_RightBracket): @(Key::KeyAsterisk), - @(VK_ANSI_Backslash): @(Key::KeyUp), - - @(VK_RightArrow): @(Key::KeyRight), - @(VK_DownArrow): @(Key::KeyDown), - }; - - // Not yet mapped: - // KeyHome - // KeyPlus - // KeyGBP - - if(key == VK_Tab && isPressed) { - _joystickMode ^= YES; - } - - @synchronized(self) { - if(_joystickMode) { - switch(key) { - case VK_UpArrow: _vic20->set_joystick_state(JoystickInput::Up, isPressed); break; - case VK_DownArrow: _vic20->set_joystick_state(JoystickInput::Down, isPressed); break; - case VK_LeftArrow: _vic20->set_joystick_state(JoystickInput::Left, isPressed); break; - case VK_RightArrow: _vic20->set_joystick_state(JoystickInput::Right, isPressed); break; - case VK_ANSI_A: _vic20->set_joystick_state(JoystickInput::Fire, isPressed); break; - } - } else { - switch(key) { - default: { - NSNumber *targetKey = vicKeysByKeys[@(key)]; - if(targetKey) - { - _vic20->set_key_state((Key)targetKey.integerValue, isPressed); - } - else - { - NSLog(@"Unmapped: %02x", key); - } - } break; - - case VK_Shift: - // Yuck - _vic20->set_key_state(Key::KeyLShift, isPressed); - _vic20->set_key_state(Key::KeyRShift, isPressed); - break; - } + switch(key) { + case VK_UpArrow: _vic20->set_joystick_state(JoystickInput::Up, isPressed); break; + case VK_DownArrow: _vic20->set_joystick_state(JoystickInput::Down, isPressed); break; + case VK_LeftArrow: _vic20->set_joystick_state(JoystickInput::Left, isPressed); break; + case VK_RightArrow: _vic20->set_joystick_state(JoystickInput::Right, isPressed); break; + case VK_ANSI_A: _vic20->set_joystick_state(JoystickInput::Fire, isPressed); break; } - } }*/ #pragma mark - Public configuration options From 7aaf27389c3cac2beef153e60f80e7cf5f78aa56 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Sun, 15 Oct 2017 20:44:59 -0400 Subject: [PATCH 06/16] Commutes the Atari 2600 to the JoystickMachine interface. --- Inputs/Joystick.hpp | 8 +- Machines/Atari2600/Atari2600.cpp | 73 +++++++++++-------- Machines/Atari2600/Atari2600.hpp | 7 +- .../Machine/Wrappers/CSAtari2600.mm | 28 +++---- 4 files changed, 67 insertions(+), 49 deletions(-) diff --git a/Inputs/Joystick.hpp b/Inputs/Joystick.hpp index 4b2223075..036d936a6 100644 --- a/Inputs/Joystick.hpp +++ b/Inputs/Joystick.hpp @@ -27,7 +27,13 @@ class Joystick { // Host interface. virtual void set_digital_input(DigitalInput digital_input, bool is_active) = 0; - virtual void reset_all_inputs() = 0; + virtual void reset_all_inputs() { + set_digital_input(DigitalInput::Up, false); + set_digital_input(DigitalInput::Down, false); + set_digital_input(DigitalInput::Left, false); + set_digital_input(DigitalInput::Right, false); + set_digital_input(DigitalInput::Fire, false); + } }; } diff --git a/Machines/Atari2600/Atari2600.cpp b/Machines/Atari2600/Atari2600.cpp index 85f867854..c68e4661a 100644 --- a/Machines/Atari2600/Atari2600.cpp +++ b/Machines/Atari2600/Atari2600.cpp @@ -30,6 +30,33 @@ namespace { namespace Atari2600 { +class Joystick: public Inputs::Joystick { + public: + Joystick(Bus *bus, size_t shift, size_t fire_tia_input) : + bus_(bus), shift_(shift), fire_tia_input_(fire_tia_input) {} + + void set_digital_input(DigitalInput digital_input, bool is_active) { + switch(digital_input) { + case DigitalInput::Up: bus_->mos6532_.update_port_input(0, 0x10 >> shift_, is_active); break; + case DigitalInput::Down: bus_->mos6532_.update_port_input(0, 0x20 >> shift_, is_active); break; + case DigitalInput::Left: bus_->mos6532_.update_port_input(0, 0x40 >> shift_, is_active); break; + case DigitalInput::Right: bus_->mos6532_.update_port_input(0, 0x80 >> shift_, is_active); break; + + // TODO: latching + case DigitalInput::Fire: + if(is_active) + bus_->tia_input_value_[fire_tia_input_] &= ~0x80; + else + bus_->tia_input_value_[fire_tia_input_] |= 0x80; + break; + } + } + + private: + size_t shift_, fire_tia_input_; + Bus *bus_; +}; + class ConcreteMachine: public Machine, public Outputs::CRT::Delegate { @@ -44,7 +71,7 @@ class ConcreteMachine: close_output(); } - void configure_as_target(const StaticAnalyser::Target &target) { + void configure_as_target(const StaticAnalyser::Target &target) override { const std::vector &rom = target.media.cartridges.front()->get_segments().front().data; switch(target.atari.paging_model) { case StaticAnalyser::Atari2600PagingModel::ActivisionStack: bus_.reset(new Cartridge::Cartridge(rom)); break; @@ -79,34 +106,20 @@ class ConcreteMachine: } break; } + + joysticks_.push_back(new Joystick(bus_.get(), 0, 0)); + joysticks_.push_back(new Joystick(bus_.get(), 4, 1)); } - bool insert_media(const StaticAnalyser::Media &media) { + bool insert_media(const StaticAnalyser::Media &media) override { return false; } - void set_digital_input(Atari2600DigitalInput input, bool state) { - switch (input) { - case Atari2600DigitalInputJoy1Up: bus_->mos6532_.update_port_input(0, 0x10, state); break; - case Atari2600DigitalInputJoy1Down: bus_->mos6532_.update_port_input(0, 0x20, state); break; - case Atari2600DigitalInputJoy1Left: bus_->mos6532_.update_port_input(0, 0x40, state); break; - case Atari2600DigitalInputJoy1Right: bus_->mos6532_.update_port_input(0, 0x80, state); break; - - case Atari2600DigitalInputJoy2Up: bus_->mos6532_.update_port_input(0, 0x01, state); break; - case Atari2600DigitalInputJoy2Down: bus_->mos6532_.update_port_input(0, 0x02, state); break; - case Atari2600DigitalInputJoy2Left: bus_->mos6532_.update_port_input(0, 0x04, state); break; - case Atari2600DigitalInputJoy2Right: bus_->mos6532_.update_port_input(0, 0x08, state); break; - - // TODO: latching - case Atari2600DigitalInputJoy1Fire: if(state) bus_->tia_input_value_[0] &= ~0x80; else bus_->tia_input_value_[0] |= 0x80; break; - case Atari2600DigitalInputJoy2Fire: if(state) bus_->tia_input_value_[1] &= ~0x80; else bus_->tia_input_value_[1] |= 0x80; break; - - default: break; - } + std::vector &get_joysticks() override { + return joysticks_; } - - void set_switch_is_enabled(Atari2600Switch input, bool state) { + void set_switch_is_enabled(Atari2600Switch input, bool state) override { switch(input) { case Atari2600SwitchReset: bus_->mos6532_.update_port_input(1, 0x01, state); break; case Atari2600SwitchSelect: bus_->mos6532_.update_port_input(1, 0x02, state); break; @@ -116,36 +129,36 @@ class ConcreteMachine: } } - void set_reset_switch(bool state) { + void set_reset_switch(bool state) override { bus_->set_reset_line(state); } // to satisfy CRTMachine::Machine - void setup_output(float aspect_ratio) { + void setup_output(float aspect_ratio) override { bus_->tia_.reset(new TIA); bus_->speaker_.reset(new Speaker); bus_->speaker_->set_input_rate((float)(get_clock_rate() / (double)CPUTicksPerAudioTick)); bus_->tia_->get_crt()->set_delegate(this); } - void close_output() { + void close_output() override { bus_.reset(); } - std::shared_ptr get_crt() { + std::shared_ptr get_crt() override { return bus_->tia_->get_crt(); } - std::shared_ptr get_speaker() { + std::shared_ptr get_speaker() override { return bus_->speaker_; } - void run_for(const Cycles cycles) { + void run_for(const Cycles cycles) override { bus_->run_for(cycles); } // to satisfy Outputs::CRT::Delegate - void crt_did_end_batch_of_frames(Outputs::CRT::CRT *crt, unsigned int number_of_frames, unsigned int number_of_unexpected_vertical_syncs) { + void crt_did_end_batch_of_frames(Outputs::CRT::CRT *crt, unsigned int number_of_frames, unsigned int number_of_unexpected_vertical_syncs) override { const size_t number_of_frame_records = sizeof(frame_records_) / sizeof(frame_records_[0]); frame_records_[frame_record_pointer_ % number_of_frame_records].number_of_frames = number_of_frames; frame_records_[frame_record_pointer_ % number_of_frame_records].number_of_unexpected_vertical_syncs = number_of_unexpected_vertical_syncs; @@ -182,7 +195,6 @@ class ConcreteMachine: } } - private: // the bus std::unique_ptr bus_; @@ -196,6 +208,7 @@ class ConcreteMachine: } frame_records_[4]; unsigned int frame_record_pointer_; bool is_ntsc_; + std::vector joysticks_; }; } diff --git a/Machines/Atari2600/Atari2600.hpp b/Machines/Atari2600/Atari2600.hpp index 860773d23..c4c2d5282 100644 --- a/Machines/Atari2600/Atari2600.hpp +++ b/Machines/Atari2600/Atari2600.hpp @@ -11,6 +11,7 @@ #include "../ConfigurationTarget.hpp" #include "../CRTMachine.hpp" +#include "../JoystickMachine.hpp" #include "Atari2600Inputs.h" @@ -21,16 +22,14 @@ namespace Atari2600 { */ class Machine: public CRTMachine::Machine, - public ConfigurationTarget::Machine { + public ConfigurationTarget::Machine, + public JoystickMachine::Machine { public: virtual ~Machine(); /// Creates and returns an Atari 2600 on the heap. static Machine *Atari2600(); - /// Sets @c input to @c state. - virtual void set_digital_input(Atari2600DigitalInput input, bool state) = 0; - /// Sets the switch @c input to @c state. virtual void set_switch_is_enabled(Atari2600Switch input, bool state) = 0; diff --git a/OSBindings/Mac/Clock Signal/Machine/Wrappers/CSAtari2600.mm b/OSBindings/Mac/Clock Signal/Machine/Wrappers/CSAtari2600.mm index 327233c08..cad5044b2 100644 --- a/OSBindings/Mac/Clock Signal/Machine/Wrappers/CSAtari2600.mm +++ b/OSBindings/Mac/Clock Signal/Machine/Wrappers/CSAtari2600.mm @@ -25,23 +25,23 @@ } - (void)setDirection:(CSJoystickDirection)direction onPad:(NSUInteger)pad isPressed:(BOOL)isPressed { - Atari2600DigitalInput input; - switch(direction) - { - case CSJoystickDirectionUp: input = pad ? Atari2600DigitalInputJoy2Up : Atari2600DigitalInputJoy1Up; break; - case CSJoystickDirectionDown: input = pad ? Atari2600DigitalInputJoy2Down : Atari2600DigitalInputJoy1Down; break; - case CSJoystickDirectionLeft: input = pad ? Atari2600DigitalInputJoy2Left : Atari2600DigitalInputJoy1Left; break; - case CSJoystickDirectionRight: input = pad ? Atari2600DigitalInputJoy2Right : Atari2600DigitalInputJoy1Right; break; - } - @synchronized(self) { - _atari2600->set_digital_input(input, isPressed ? true : false); - } +// Atari2600DigitalInput input; +// switch(direction) +// { +// case CSJoystickDirectionUp: input = pad ? Atari2600DigitalInputJoy2Up : Atari2600DigitalInputJoy1Up; break; +// case CSJoystickDirectionDown: input = pad ? Atari2600DigitalInputJoy2Down : Atari2600DigitalInputJoy1Down; break; +// case CSJoystickDirectionLeft: input = pad ? Atari2600DigitalInputJoy2Left : Atari2600DigitalInputJoy1Left; break; +// case CSJoystickDirectionRight: input = pad ? Atari2600DigitalInputJoy2Right : Atari2600DigitalInputJoy1Right; break; +// } +// @synchronized(self) { +// _atari2600->set_digital_input(input, isPressed ? true : false); +// } } - (void)setButtonAtIndex:(NSUInteger)button onPad:(NSUInteger)pad isPressed:(BOOL)isPressed { - @synchronized(self) { - _atari2600->set_digital_input(pad ? Atari2600DigitalInputJoy2Fire : Atari2600DigitalInputJoy1Fire, isPressed ? true : false); - } +// @synchronized(self) { +// _atari2600->set_digital_input(pad ? Atari2600DigitalInputJoy2Fire : Atari2600DigitalInputJoy1Fire, isPressed ? true : false); +// } } - (void)setResetLineEnabled:(BOOL)enabled { From 18798c98864d1e543897dea79c538bb1c403b4e7 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Sun, 15 Oct 2017 20:49:47 -0400 Subject: [PATCH 07/16] Corrects joystick memory leaks. --- Machines/Atari2600/Atari2600.cpp | 8 ++++---- Machines/Commodore/Vic-20/Vic20.cpp | 6 +++--- Machines/JoystickMachine.hpp | 2 +- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/Machines/Atari2600/Atari2600.cpp b/Machines/Atari2600/Atari2600.cpp index c68e4661a..92bc5c9e1 100644 --- a/Machines/Atari2600/Atari2600.cpp +++ b/Machines/Atari2600/Atari2600.cpp @@ -107,15 +107,15 @@ class ConcreteMachine: break; } - joysticks_.push_back(new Joystick(bus_.get(), 0, 0)); - joysticks_.push_back(new Joystick(bus_.get(), 4, 1)); + joysticks_.emplace_back(new Joystick(bus_.get(), 0, 0)); + joysticks_.emplace_back(new Joystick(bus_.get(), 4, 1)); } bool insert_media(const StaticAnalyser::Media &media) override { return false; } - std::vector &get_joysticks() override { + std::vector> &get_joysticks() override { return joysticks_; } @@ -208,7 +208,7 @@ class ConcreteMachine: } frame_records_[4]; unsigned int frame_record_pointer_; bool is_ntsc_; - std::vector joysticks_; + std::vector> joysticks_; }; } diff --git a/Machines/Commodore/Vic-20/Vic20.cpp b/Machines/Commodore/Vic-20/Vic20.cpp index a4d76525a..2f6261140 100644 --- a/Machines/Commodore/Vic-20/Vic20.cpp +++ b/Machines/Commodore/Vic-20/Vic20.cpp @@ -295,7 +295,7 @@ class ConcreteMachine: set_region(NTSC); // install a joystick - joysticks_.push_back(new Joystick(*user_port_via_port_handler_, *keyboard_via_port_handler_)); + joysticks_.emplace_back(new Joystick(*user_port_via_port_handler_, *keyboard_via_port_handler_)); } ~ConcreteMachine() { @@ -383,7 +383,7 @@ class ConcreteMachine: keyboard_via_port_handler_->clear_all_keys(); } - std::vector &get_joysticks() override { + std::vector> &get_joysticks() override { return joysticks_; } @@ -622,7 +622,7 @@ class ConcreteMachine: Region region_; Commodore::Vic20::KeyboardMapper keyboard_mapper_; - std::vector joysticks_; + std::vector> joysticks_; std::unique_ptr mos6560_; std::shared_ptr user_port_via_port_handler_; diff --git a/Machines/JoystickMachine.hpp b/Machines/JoystickMachine.hpp index bc7c4a783..3fe3e05d6 100644 --- a/Machines/JoystickMachine.hpp +++ b/Machines/JoystickMachine.hpp @@ -16,7 +16,7 @@ namespace JoystickMachine { class Machine { public: - virtual std::vector &get_joysticks() = 0; + virtual std::vector> &get_joysticks() = 0; }; } From 542ec4312ff31a12eea16728e2f55c8e5ee71117 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Sun, 15 Oct 2017 21:25:56 -0400 Subject: [PATCH 08/16] Switched the Objective-C code to using dynamic_cast alone to decide whether to post keyboard or joystick events. --- .../ClockSignal-Bridging-Header.h | 3 +- .../Documents/MachineDocument.swift | 40 +----- .../Clock Signal/Machine/CSJoystickMachine.h | 22 --- .../Clock Signal/Machine/CSKeyboardMachine.h | 16 --- .../Mac/Clock Signal/Machine/CSMachine.h | 8 +- .../Mac/Clock Signal/Machine/CSMachine.mm | 133 +++++++++++------- .../Machine/Wrappers/CSAmstradCPC.h | 3 +- .../Machine/Wrappers/CSAtari2600.h | 3 +- .../Machine/Wrappers/CSAtari2600.mm | 20 --- .../Machine/Wrappers/CSElectron.h | 3 +- .../Clock Signal/Machine/Wrappers/CSOric.h | 3 +- .../Clock Signal/Machine/Wrappers/CSVic20.h | 3 +- .../Clock Signal/Machine/Wrappers/CSZX8081.h | 3 +- 13 files changed, 99 insertions(+), 161 deletions(-) delete mode 100644 OSBindings/Mac/Clock Signal/Machine/CSJoystickMachine.h delete mode 100644 OSBindings/Mac/Clock Signal/Machine/CSKeyboardMachine.h diff --git a/OSBindings/Mac/Clock Signal/ClockSignal-Bridging-Header.h b/OSBindings/Mac/Clock Signal/ClockSignal-Bridging-Header.h index e3c78f382..b05c01f4f 100644 --- a/OSBindings/Mac/Clock Signal/ClockSignal-Bridging-Header.h +++ b/OSBindings/Mac/Clock Signal/ClockSignal-Bridging-Header.h @@ -3,7 +3,6 @@ // #import "CSMachine.h" -#import "CSKeyboardMachine.h" #import "CSFastLoading.h" #import "CSAtari2600.h" @@ -17,3 +16,5 @@ #import "CSOpenGLView.h" #import "CSAudioQueue.h" #import "CSBestEffortUpdater.h" + +#include "KeyCodes.h" diff --git a/OSBindings/Mac/Clock Signal/Documents/MachineDocument.swift b/OSBindings/Mac/Clock Signal/Documents/MachineDocument.swift index ece8b63c4..1a367787e 100644 --- a/OSBindings/Mac/Clock Signal/Documents/MachineDocument.swift +++ b/OSBindings/Mac/Clock Signal/Documents/MachineDocument.swift @@ -187,48 +187,22 @@ class MachineDocument: } // MARK: Input management - fileprivate func withKeyboardMachine(_ action: (CSKeyboardMachine) -> ()) { - if let keyboardMachine = self.machine as? CSKeyboardMachine { - action(keyboardMachine) - } - } - - fileprivate func withJoystickMachine(_ action: (CSJoystickMachine) -> ()) { - if let joystickMachine = self.machine as? CSJoystickMachine { - action(joystickMachine) - } - } - - fileprivate func sendJoystickEvent(_ machine: CSJoystickMachine, keyCode: UInt16, isPressed: Bool) { - switch keyCode { - case 123: machine.setDirection(.left, onPad: 0, isPressed: isPressed) - case 126: machine.setDirection(.up, onPad: 0, isPressed: isPressed) - case 124: machine.setDirection(.right, onPad: 0, isPressed: isPressed) - case 125: machine.setDirection(.down, onPad: 0, isPressed: isPressed) - default: machine.setButtonAt(0, onPad: 0, isPressed: isPressed) - } - } - func windowDidResignKey(_ notification: Notification) { - self.withKeyboardMachine { $0.clearAllKeys() } + self.machine.clearAllKeys() } func keyDown(_ event: NSEvent) { - self.withKeyboardMachine { $0.setKey(event.keyCode, isPressed: true) } - self.withJoystickMachine { sendJoystickEvent($0, keyCode: event.keyCode, isPressed: true) } + self.machine.setKey(event.keyCode, isPressed: true) } func keyUp(_ event: NSEvent) { - self.withKeyboardMachine { $0.setKey(event.keyCode, isPressed: false) } - self.withJoystickMachine { sendJoystickEvent($0, keyCode: event.keyCode, isPressed: false) } + self.machine.setKey(event.keyCode, isPressed: false) } func flagsChanged(_ newModifiers: NSEvent) { - self.withKeyboardMachine { - $0.setKey(VK_Shift, isPressed: newModifiers.modifierFlags.contains(.shift)) - $0.setKey(VK_Control, isPressed: newModifiers.modifierFlags.contains(.control)) - $0.setKey(VK_Command, isPressed: newModifiers.modifierFlags.contains(.command)) - $0.setKey(VK_Option, isPressed: newModifiers.modifierFlags.contains(.option)) - } + self.machine.setKey(VK_Shift, isPressed: newModifiers.modifierFlags.contains(.shift)) + self.machine.setKey(VK_Control, isPressed: newModifiers.modifierFlags.contains(.control)) + self.machine.setKey(VK_Command, isPressed: newModifiers.modifierFlags.contains(.command)) + self.machine.setKey(VK_Option, isPressed: newModifiers.modifierFlags.contains(.option)) } } diff --git a/OSBindings/Mac/Clock Signal/Machine/CSJoystickMachine.h b/OSBindings/Mac/Clock Signal/Machine/CSJoystickMachine.h deleted file mode 100644 index ed1cc5e67..000000000 --- a/OSBindings/Mac/Clock Signal/Machine/CSJoystickMachine.h +++ /dev/null @@ -1,22 +0,0 @@ -// -// CSJoystickMachine.h -// Clock Signal -// -// Created by Thomas Harte on 03/10/2016. -// Copyright © 2016 Thomas Harte. All rights reserved. -// - -typedef NS_ENUM(NSInteger, CSJoystickDirection) -{ - CSJoystickDirectionUp, - CSJoystickDirectionDown, - CSJoystickDirectionLeft, - CSJoystickDirectionRight -}; - -@protocol CSJoystickMachine - -- (void)setButtonAtIndex:(NSUInteger)button onPad:(NSUInteger)pad isPressed:(BOOL)isPressed; -- (void)setDirection:(CSJoystickDirection)direction onPad:(NSUInteger)pad isPressed:(BOOL)isPressed; - -@end diff --git a/OSBindings/Mac/Clock Signal/Machine/CSKeyboardMachine.h b/OSBindings/Mac/Clock Signal/Machine/CSKeyboardMachine.h deleted file mode 100644 index 34f3dea0f..000000000 --- a/OSBindings/Mac/Clock Signal/Machine/CSKeyboardMachine.h +++ /dev/null @@ -1,16 +0,0 @@ -// -// CSKeyboardMachine.h -// Clock Signal -// -// Created by Thomas Harte on 05/06/2016. -// Copyright © 2016 Thomas Harte. All rights reserved. -// - -#import "KeyCodes.h" - -@protocol CSKeyboardMachine - -- (void)setKey:(uint16_t)key isPressed:(BOOL)isPressed; -- (void)clearAllKeys; - -@end diff --git a/OSBindings/Mac/Clock Signal/Machine/CSMachine.h b/OSBindings/Mac/Clock Signal/Machine/CSMachine.h index 0804bb987..1b6f805c2 100644 --- a/OSBindings/Mac/Clock Signal/Machine/CSMachine.h +++ b/OSBindings/Mac/Clock Signal/Machine/CSMachine.h @@ -35,6 +35,9 @@ - (void)setView:(CSOpenGLView *)view aspectRatio:(float)aspectRatio; - (void)drawViewForPixelSize:(CGSize)pixelSize onlyIfDirty:(BOOL)onlyIfDirty; +- (void)setKey:(uint16_t)key isPressed:(BOOL)isPressed; +- (void)clearAllKeys; + @property (nonatomic, strong) CSAudioQueue *audioQueue; @property (nonatomic, readonly) CSOpenGLView *view; @property (nonatomic, weak) id delegate; @@ -46,9 +49,4 @@ - (void)paste:(NSString *)string; -// This is an informal implementation of the CSKeyboardMachine protocol; specific machines -// can decide whether they opt in as keyboard machines. -- (void)setKey:(uint16_t)key isPressed:(BOOL)isPressed; -- (void)clearAllKeys; - @end diff --git a/OSBindings/Mac/Clock Signal/Machine/CSMachine.mm b/OSBindings/Mac/Clock Signal/Machine/CSMachine.mm index 763567a8b..6c7746ac0 100644 --- a/OSBindings/Mac/Clock Signal/Machine/CSMachine.mm +++ b/OSBindings/Mac/Clock Signal/Machine/CSMachine.mm @@ -10,10 +10,11 @@ #import "CSMachine+Subclassing.h" #import "CSMachine+Target.h" -#import "CSKeyboardMachine.h" - +#include "KeyCodes.h" #include "Typer.hpp" #include "ConfigurationTarget.hpp" +#include "JoystickMachine.hpp" +#include "KeyboardMachine.hpp" @interface CSMachine() - (void)speaker:(Outputs::Speaker *)speaker didCompleteSamples:(const int16_t *)samples length:(int)length; @@ -187,75 +188,103 @@ struct MachineDelegate: CRTMachine::Machine::Delegate, public LockProtectedDeleg - (void)setKey:(uint16_t)key isPressed:(BOOL)isPressed { auto keyboard_machine = dynamic_cast(_machine); - if(!keyboard_machine) return; + if(keyboard_machine) { + @synchronized(self) { + Inputs::Keyboard &keyboard = keyboard_machine->get_keyboard(); - @synchronized(self) { - Inputs::Keyboard &keyboard = keyboard_machine->get_keyboard(); - - // Connect the Carbon-era Mac keyboard scancodes to Clock Signal's 'universal' enumeration in order - // to pass into the platform-neutral realm. + // Connect the Carbon-era Mac keyboard scancodes to Clock Signal's 'universal' enumeration in order + // to pass into the platform-neutral realm. #define BIND(source, dest) case source: keyboard.set_key_pressed(Inputs::Keyboard::Key::dest, isPressed); break - switch(key) { - BIND(VK_ANSI_0, k0); BIND(VK_ANSI_1, k1); BIND(VK_ANSI_2, k2); BIND(VK_ANSI_3, k3); BIND(VK_ANSI_4, k4); - BIND(VK_ANSI_5, k5); BIND(VK_ANSI_6, k6); BIND(VK_ANSI_7, k7); BIND(VK_ANSI_8, k8); BIND(VK_ANSI_9, k9); + switch(key) { + BIND(VK_ANSI_0, k0); BIND(VK_ANSI_1, k1); BIND(VK_ANSI_2, k2); BIND(VK_ANSI_3, k3); BIND(VK_ANSI_4, k4); + BIND(VK_ANSI_5, k5); BIND(VK_ANSI_6, k6); BIND(VK_ANSI_7, k7); BIND(VK_ANSI_8, k8); BIND(VK_ANSI_9, k9); - BIND(VK_ANSI_Q, Q); BIND(VK_ANSI_W, W); BIND(VK_ANSI_E, E); BIND(VK_ANSI_R, R); BIND(VK_ANSI_T, T); - BIND(VK_ANSI_Y, Y); BIND(VK_ANSI_U, U); BIND(VK_ANSI_I, I); BIND(VK_ANSI_O, O); BIND(VK_ANSI_P, P); + BIND(VK_ANSI_Q, Q); BIND(VK_ANSI_W, W); BIND(VK_ANSI_E, E); BIND(VK_ANSI_R, R); BIND(VK_ANSI_T, T); + BIND(VK_ANSI_Y, Y); BIND(VK_ANSI_U, U); BIND(VK_ANSI_I, I); BIND(VK_ANSI_O, O); BIND(VK_ANSI_P, P); - BIND(VK_ANSI_A, A); BIND(VK_ANSI_S, S); BIND(VK_ANSI_D, D); BIND(VK_ANSI_F, F); BIND(VK_ANSI_G, G); - BIND(VK_ANSI_H, H); BIND(VK_ANSI_J, J); BIND(VK_ANSI_K, K); BIND(VK_ANSI_L, L); + BIND(VK_ANSI_A, A); BIND(VK_ANSI_S, S); BIND(VK_ANSI_D, D); BIND(VK_ANSI_F, F); BIND(VK_ANSI_G, G); + BIND(VK_ANSI_H, H); BIND(VK_ANSI_J, J); BIND(VK_ANSI_K, K); BIND(VK_ANSI_L, L); - BIND(VK_ANSI_Z, Z); BIND(VK_ANSI_X, X); BIND(VK_ANSI_C, C); BIND(VK_ANSI_V, V); - BIND(VK_ANSI_B, B); BIND(VK_ANSI_N, N); BIND(VK_ANSI_M, M); + BIND(VK_ANSI_Z, Z); BIND(VK_ANSI_X, X); BIND(VK_ANSI_C, C); BIND(VK_ANSI_V, V); + BIND(VK_ANSI_B, B); BIND(VK_ANSI_N, N); BIND(VK_ANSI_M, M); - BIND(VK_F1, F1); BIND(VK_F2, F2); BIND(VK_F3, F3); BIND(VK_F4, F4); - BIND(VK_F5, F5); BIND(VK_F6, F6); BIND(VK_F7, F7); BIND(VK_F8, F8); - BIND(VK_F9, F9); BIND(VK_F10, F10); BIND(VK_F11, F11); BIND(VK_F12, F12); + BIND(VK_F1, F1); BIND(VK_F2, F2); BIND(VK_F3, F3); BIND(VK_F4, F4); + BIND(VK_F5, F5); BIND(VK_F6, F6); BIND(VK_F7, F7); BIND(VK_F8, F8); + BIND(VK_F9, F9); BIND(VK_F10, F10); BIND(VK_F11, F11); BIND(VK_F12, F12); - BIND(VK_ANSI_Keypad0, KeyPad0); BIND(VK_ANSI_Keypad1, KeyPad1); BIND(VK_ANSI_Keypad2, KeyPad2); - BIND(VK_ANSI_Keypad3, KeyPad3); BIND(VK_ANSI_Keypad4, KeyPad4); BIND(VK_ANSI_Keypad5, KeyPad5); - BIND(VK_ANSI_Keypad6, KeyPad6); BIND(VK_ANSI_Keypad7, KeyPad7); BIND(VK_ANSI_Keypad8, KeyPad8); - BIND(VK_ANSI_Keypad9, KeyPad9); + BIND(VK_ANSI_Keypad0, KeyPad0); BIND(VK_ANSI_Keypad1, KeyPad1); BIND(VK_ANSI_Keypad2, KeyPad2); + BIND(VK_ANSI_Keypad3, KeyPad3); BIND(VK_ANSI_Keypad4, KeyPad4); BIND(VK_ANSI_Keypad5, KeyPad5); + BIND(VK_ANSI_Keypad6, KeyPad6); BIND(VK_ANSI_Keypad7, KeyPad7); BIND(VK_ANSI_Keypad8, KeyPad8); + BIND(VK_ANSI_Keypad9, KeyPad9); - BIND(VK_ANSI_Equal, Equals); BIND(VK_ANSI_Minus, Hyphen); - BIND(VK_ANSI_RightBracket, CloseSquareBracket); BIND(VK_ANSI_LeftBracket, OpenSquareBracket); - BIND(VK_ANSI_Quote, Quote); BIND(VK_ANSI_Grave, BackTick); + BIND(VK_ANSI_Equal, Equals); BIND(VK_ANSI_Minus, Hyphen); + BIND(VK_ANSI_RightBracket, CloseSquareBracket); BIND(VK_ANSI_LeftBracket, OpenSquareBracket); + BIND(VK_ANSI_Quote, Quote); BIND(VK_ANSI_Grave, BackTick); - BIND(VK_ANSI_Semicolon, Semicolon); - BIND(VK_ANSI_Backslash, BackSlash); BIND(VK_ANSI_Slash, ForwardSlash); - BIND(VK_ANSI_Comma, Comma); BIND(VK_ANSI_Period, FullStop); + BIND(VK_ANSI_Semicolon, Semicolon); + BIND(VK_ANSI_Backslash, BackSlash); BIND(VK_ANSI_Slash, ForwardSlash); + BIND(VK_ANSI_Comma, Comma); BIND(VK_ANSI_Period, FullStop); - BIND(VK_ANSI_KeypadDecimal, KeyPadDecimalPoint); BIND(VK_ANSI_KeypadEquals, KeyPadEquals); - BIND(VK_ANSI_KeypadMultiply, KeyPadAsterisk); BIND(VK_ANSI_KeypadDivide, KeyPadSlash); - BIND(VK_ANSI_KeypadPlus, KeyPadPlus); BIND(VK_ANSI_KeypadMinus, KeyPadMinus); - BIND(VK_ANSI_KeypadClear, KeyPadDelete); BIND(VK_ANSI_KeypadEnter, KeyPadEnter); - - BIND(VK_Return, Enter); BIND(VK_Tab, Tab); - BIND(VK_Space, Space); BIND(VK_Delete, BackSpace); - BIND(VK_Control, LeftControl); BIND(VK_Option, LeftOption); - BIND(VK_Command, LeftMeta); BIND(VK_Shift, LeftShift); - BIND(VK_RightControl, RightControl); BIND(VK_RightOption, RightOption); - BIND(VK_Escape, Escape); BIND(VK_CapsLock, CapsLock); - BIND(VK_Home, Home); BIND(VK_End, End); - BIND(VK_PageUp, PageUp); BIND(VK_PageDown, PageDown); + BIND(VK_ANSI_KeypadDecimal, KeyPadDecimalPoint); BIND(VK_ANSI_KeypadEquals, KeyPadEquals); + BIND(VK_ANSI_KeypadMultiply, KeyPadAsterisk); BIND(VK_ANSI_KeypadDivide, KeyPadSlash); + BIND(VK_ANSI_KeypadPlus, KeyPadPlus); BIND(VK_ANSI_KeypadMinus, KeyPadMinus); + BIND(VK_ANSI_KeypadClear, KeyPadDelete); BIND(VK_ANSI_KeypadEnter, KeyPadEnter); + + BIND(VK_Return, Enter); BIND(VK_Tab, Tab); + BIND(VK_Space, Space); BIND(VK_Delete, BackSpace); + BIND(VK_Control, LeftControl); BIND(VK_Option, LeftOption); + BIND(VK_Command, LeftMeta); BIND(VK_Shift, LeftShift); + BIND(VK_RightControl, RightControl); BIND(VK_RightOption, RightOption); + BIND(VK_Escape, Escape); BIND(VK_CapsLock, CapsLock); + BIND(VK_Home, Home); BIND(VK_End, End); + BIND(VK_PageUp, PageUp); BIND(VK_PageDown, PageDown); - BIND(VK_RightShift, RightShift); - BIND(VK_Help, Help); - BIND(VK_ForwardDelete, Delete); + BIND(VK_RightShift, RightShift); + BIND(VK_Help, Help); + BIND(VK_ForwardDelete, Delete); - BIND(VK_LeftArrow, Left); BIND(VK_RightArrow, Right); - BIND(VK_DownArrow, Down); BIND(VK_UpArrow, Up); - } + BIND(VK_LeftArrow, Left); BIND(VK_RightArrow, Right); + BIND(VK_DownArrow, Down); BIND(VK_UpArrow, Up); + } #undef BIND + } + return; + } + + auto joystick_machine = dynamic_cast(_machine); + if(joystick_machine) { + @synchronized(self) { + std::vector> &joysticks = joystick_machine->get_joysticks(); + if(!joysticks.empty()) { + switch(key) { + case VK_LeftArrow: joysticks[0]->set_digital_input(Inputs::Joystick::DigitalInput::Left, isPressed); break; + case VK_RightArrow: joysticks[0]->set_digital_input(Inputs::Joystick::DigitalInput::Right, isPressed); break; + case VK_UpArrow: joysticks[0]->set_digital_input(Inputs::Joystick::DigitalInput::Up, isPressed); break; + case VK_DownArrow: joysticks[0]->set_digital_input(Inputs::Joystick::DigitalInput::Down, isPressed); break; + default: + joysticks[0]->set_digital_input(Inputs::Joystick::DigitalInput::Fire, isPressed); break; + break; + } + } + } } } - (void)clearAllKeys { auto keyboard_machine = dynamic_cast(_machine); - if(!keyboard_machine) return; + if(keyboard_machine) { + @synchronized(self) { + keyboard_machine->get_keyboard().reset_all_keys(); + } + } - @synchronized(self) { - keyboard_machine->get_keyboard().reset_all_keys(); + auto joystick_machine = dynamic_cast(_machine); + if(joystick_machine) { + @synchronized(self) { + for(auto &joystick : joystick_machine->get_joysticks()) { + joystick->reset_all_inputs(); + } + } } } diff --git a/OSBindings/Mac/Clock Signal/Machine/Wrappers/CSAmstradCPC.h b/OSBindings/Mac/Clock Signal/Machine/Wrappers/CSAmstradCPC.h index a10e1de80..df34baaf4 100644 --- a/OSBindings/Mac/Clock Signal/Machine/Wrappers/CSAmstradCPC.h +++ b/OSBindings/Mac/Clock Signal/Machine/Wrappers/CSAmstradCPC.h @@ -7,9 +7,8 @@ // #import "CSMachine.h" -#import "CSKeyboardMachine.h" -@interface CSAmstradCPC : CSMachine +@interface CSAmstradCPC : CSMachine - (instancetype)init; diff --git a/OSBindings/Mac/Clock Signal/Machine/Wrappers/CSAtari2600.h b/OSBindings/Mac/Clock Signal/Machine/Wrappers/CSAtari2600.h index 8661ff646..c06a072f7 100644 --- a/OSBindings/Mac/Clock Signal/Machine/Wrappers/CSAtari2600.h +++ b/OSBindings/Mac/Clock Signal/Machine/Wrappers/CSAtari2600.h @@ -8,9 +8,8 @@ #include "CSMachine.h" #include "Atari2600Inputs.h" -#import "CSJoystickMachine.h" -@interface CSAtari2600 : CSMachine +@interface CSAtari2600 : CSMachine - (instancetype)init; diff --git a/OSBindings/Mac/Clock Signal/Machine/Wrappers/CSAtari2600.mm b/OSBindings/Mac/Clock Signal/Machine/Wrappers/CSAtari2600.mm index cad5044b2..25490fc53 100644 --- a/OSBindings/Mac/Clock Signal/Machine/Wrappers/CSAtari2600.mm +++ b/OSBindings/Mac/Clock Signal/Machine/Wrappers/CSAtari2600.mm @@ -24,26 +24,6 @@ return self; } -- (void)setDirection:(CSJoystickDirection)direction onPad:(NSUInteger)pad isPressed:(BOOL)isPressed { -// Atari2600DigitalInput input; -// switch(direction) -// { -// case CSJoystickDirectionUp: input = pad ? Atari2600DigitalInputJoy2Up : Atari2600DigitalInputJoy1Up; break; -// case CSJoystickDirectionDown: input = pad ? Atari2600DigitalInputJoy2Down : Atari2600DigitalInputJoy1Down; break; -// case CSJoystickDirectionLeft: input = pad ? Atari2600DigitalInputJoy2Left : Atari2600DigitalInputJoy1Left; break; -// case CSJoystickDirectionRight: input = pad ? Atari2600DigitalInputJoy2Right : Atari2600DigitalInputJoy1Right; break; -// } -// @synchronized(self) { -// _atari2600->set_digital_input(input, isPressed ? true : false); -// } -} - -- (void)setButtonAtIndex:(NSUInteger)button onPad:(NSUInteger)pad isPressed:(BOOL)isPressed { -// @synchronized(self) { -// _atari2600->set_digital_input(pad ? Atari2600DigitalInputJoy2Fire : Atari2600DigitalInputJoy1Fire, isPressed ? true : false); -// } -} - - (void)setResetLineEnabled:(BOOL)enabled { @synchronized(self) { _atari2600->set_reset_switch(enabled ? true : false); diff --git a/OSBindings/Mac/Clock Signal/Machine/Wrappers/CSElectron.h b/OSBindings/Mac/Clock Signal/Machine/Wrappers/CSElectron.h index be83f2fdb..863142ee5 100644 --- a/OSBindings/Mac/Clock Signal/Machine/Wrappers/CSElectron.h +++ b/OSBindings/Mac/Clock Signal/Machine/Wrappers/CSElectron.h @@ -7,10 +7,9 @@ // #import "CSMachine.h" -#import "CSKeyboardMachine.h" #import "CSFastLoading.h" -@interface CSElectron : CSMachine +@interface CSElectron : CSMachine - (instancetype)init; diff --git a/OSBindings/Mac/Clock Signal/Machine/Wrappers/CSOric.h b/OSBindings/Mac/Clock Signal/Machine/Wrappers/CSOric.h index f6a6d683e..11c231d68 100644 --- a/OSBindings/Mac/Clock Signal/Machine/Wrappers/CSOric.h +++ b/OSBindings/Mac/Clock Signal/Machine/Wrappers/CSOric.h @@ -7,10 +7,9 @@ // #import "CSMachine.h" -#import "CSKeyboardMachine.h" #import "CSFastLoading.h" -@interface CSOric : CSMachine +@interface CSOric : CSMachine - (instancetype)init; diff --git a/OSBindings/Mac/Clock Signal/Machine/Wrappers/CSVic20.h b/OSBindings/Mac/Clock Signal/Machine/Wrappers/CSVic20.h index b2b2022fc..8a4af6136 100644 --- a/OSBindings/Mac/Clock Signal/Machine/Wrappers/CSVic20.h +++ b/OSBindings/Mac/Clock Signal/Machine/Wrappers/CSVic20.h @@ -7,7 +7,6 @@ // #import "CSMachine.h" -#import "CSKeyboardMachine.h" #import "CSFastLoading.h" typedef NS_ENUM(NSInteger, CSVic20Country) @@ -26,7 +25,7 @@ typedef NS_ENUM(NSInteger, CSVic20MemorySize) CSVic20MemorySize32Kb, }; -@interface CSVic20 : CSMachine +@interface CSVic20 : CSMachine - (instancetype)init; diff --git a/OSBindings/Mac/Clock Signal/Machine/Wrappers/CSZX8081.h b/OSBindings/Mac/Clock Signal/Machine/Wrappers/CSZX8081.h index 3478e8c18..42737acde 100644 --- a/OSBindings/Mac/Clock Signal/Machine/Wrappers/CSZX8081.h +++ b/OSBindings/Mac/Clock Signal/Machine/Wrappers/CSZX8081.h @@ -7,10 +7,9 @@ // #import "CSMachine.h" -#import "CSKeyboardMachine.h" #import "CSFastLoading.h" -@interface CSZX8081 : CSMachine +@interface CSZX8081 : CSMachine @property (nonatomic, assign) BOOL useFastLoadingHack; From 3f4d90d775a96ceabcf50a92713c33f0f3f2979b Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Tue, 17 Oct 2017 20:49:12 -0400 Subject: [PATCH 09/16] Corrects buffer overwrites resulting from failure to treat a number of records of 0x80 as a special case. --- Storage/Disk/Parsers/CPM.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/Storage/Disk/Parsers/CPM.cpp b/Storage/Disk/Parsers/CPM.cpp index 75c638ce2..2931bf3bc 100644 --- a/Storage/Disk/Parsers/CPM.cpp +++ b/Storage/Disk/Parsers/CPM.cpp @@ -88,7 +88,7 @@ std::unique_ptr Storage::Disk::CPM::GetCatalogue( std::unique_ptr result(new Catalogue); bool has_long_allocation_units = (parameters.tracks * parameters.sectors_per_track * (int)sector_size / parameters.block_size) >= 256; - size_t bytes_per_catalogue_entry = (has_long_allocation_units ? 16 : 8) * (size_t)parameters.block_size; + size_t bytes_per_catalogue_entry = (has_long_allocation_units ? 8 : 16) * (size_t)parameters.block_size; int sectors_per_block = parameters.block_size / (int)sector_size; int records_per_sector = (int)sector_size / 128; @@ -117,7 +117,8 @@ std::unique_ptr Storage::Disk::CPM::GetCatalogue( // Accumulate all data. while(entry <= final_entry) { int record = 0; - for(size_t block = 0; block < (has_long_allocation_units ? 8 : 16) && record < entry->number_of_records; block++) { + int number_of_records = (entry->number_of_records != 0x80) ? entry->number_of_records : (has_long_allocation_units ? 8 : 16); + for(size_t block = 0; block < (has_long_allocation_units ? 8 : 16) && record < number_of_records; block++) { int block_number; if(has_long_allocation_units) { block_number = catalogue[entry->catalogue_index + 16 + (block << 1)] + (catalogue[entry->catalogue_index + 16 + (block << 1) + 1] << 8); @@ -133,7 +134,7 @@ std::unique_ptr Storage::Disk::CPM::GetCatalogue( sector = first_sector % parameters.sectors_per_track; track = first_sector / parameters.sectors_per_track; - for(int s = 0; s < sectors_per_block && record < entry->number_of_records; s++) { + for(int s = 0; s < sectors_per_block && record < number_of_records; s++) { Storage::Encodings::MFM::Sector *sector_contents = parser.get_sector(0, static_cast(track), static_cast(parameters.first_sector + sector)); if(!sector_contents) break; sector++; From 0c2dd6232807a3f374e20b6eb0fbc7ef906b065b Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Tue, 17 Oct 2017 20:50:46 -0400 Subject: [PATCH 10/16] Various undefined behaviour fixes. Primarily around uninitialised variables, but also with an attempted use of a negative pointer. --- Machines/AmstradCPC/AmstradCPC.cpp | 30 ++++++++---------------- Outputs/CRT/Internals/ArrayBuilder.cpp | 4 +--- Outputs/CRT/Internals/ArrayBuilder.hpp | 12 +++++----- Outputs/CRT/Internals/TextureBuilder.cpp | 10 ++++---- 4 files changed, 22 insertions(+), 34 deletions(-) diff --git a/Machines/AmstradCPC/AmstradCPC.cpp b/Machines/AmstradCPC/AmstradCPC.cpp index bf19ce094..c1d612367 100644 --- a/Machines/AmstradCPC/AmstradCPC.cpp +++ b/Machines/AmstradCPC/AmstradCPC.cpp @@ -156,18 +156,8 @@ class AYDeferrer { class CRTCBusHandler { public: CRTCBusHandler(uint8_t *ram, InterruptTimer &interrupt_timer) : - cycles_(0), - was_enabled_(false), - was_sync_(false), - pixel_data_(nullptr), - pixel_pointer_(nullptr), - was_hsync_(false), ram_(ram), - interrupt_timer_(interrupt_timer), - pixel_divider_(1), - mode_(2), - next_mode_(2), - cycles_into_hsync_(0) { + interrupt_timer_(interrupt_timer) { establish_palette_hits(); build_mode_table(); } @@ -501,19 +491,19 @@ class CRTCBusHandler { return mapping[colour]; } - unsigned int cycles_; + unsigned int cycles_ = 0; - bool was_enabled_, was_sync_, was_hsync_, was_vsync_; - int cycles_into_hsync_; + bool was_enabled_ = false, was_sync_ = false, was_hsync_ = false, was_vsync_ = false; + int cycles_into_hsync_ = 0; std::shared_ptr crt_; - uint8_t *pixel_data_, *pixel_pointer_; + uint8_t *pixel_data_ = nullptr, *pixel_pointer_ = nullptr; - uint8_t *ram_; + uint8_t *ram_ = nullptr; - int next_mode_, mode_; + int next_mode_ = 2, mode_ = 2; - unsigned int pixel_divider_; + unsigned int pixel_divider_ = 1; uint16_t mode0_output_[256]; uint32_t mode1_output_[256]; uint64_t mode2_output_[256]; @@ -523,9 +513,9 @@ class CRTCBusHandler { std::vector mode1_palette_hits_[4]; std::vector mode3_palette_hits_[4]; - int pen_; + int pen_ = 0; uint8_t palette_[16]; - uint8_t border_; + uint8_t border_ = 0; InterruptTimer &interrupt_timer_; }; diff --git a/Outputs/CRT/Internals/ArrayBuilder.cpp b/Outputs/CRT/Internals/ArrayBuilder.cpp index 26216834c..1f09602f5 100644 --- a/Outputs/CRT/Internals/ArrayBuilder.cpp +++ b/Outputs/CRT/Internals/ArrayBuilder.cpp @@ -67,9 +67,7 @@ ArrayBuilder::Submission ArrayBuilder::submit() { } ArrayBuilder::Buffer::Buffer(size_t size, std::function submission_function) : - is_full(false), - submission_function_(submission_function), - allocated_data(0), flushed_data(0), submitted_data(0) { + submission_function_(submission_function) { if(!submission_function_) { glGenBuffers(1, &buffer); glBindBuffer(GL_ARRAY_BUFFER, buffer); diff --git a/Outputs/CRT/Internals/ArrayBuilder.hpp b/Outputs/CRT/Internals/ArrayBuilder.hpp index 1c02e5e68..adaf384ae 100644 --- a/Outputs/CRT/Internals/ArrayBuilder.hpp +++ b/Outputs/CRT/Internals/ArrayBuilder.hpp @@ -82,17 +82,17 @@ class ArrayBuilder { void reset(); private: - bool is_full; - GLuint buffer; + bool is_full = false; + GLuint buffer = 0; std::function submission_function_; std::vector data; - size_t allocated_data; - size_t flushed_data; - size_t submitted_data; + size_t allocated_data = 0; + size_t flushed_data = 0; + size_t submitted_data = 0; } output_, input_; uint8_t *get_storage(size_t size, Buffer &buffer); - bool is_full_; + bool is_full_ = false; }; } diff --git a/Outputs/CRT/Internals/TextureBuilder.cpp b/Outputs/CRT/Internals/TextureBuilder.cpp index 7fa46d955..945b440b1 100644 --- a/Outputs/CRT/Internals/TextureBuilder.cpp +++ b/Outputs/CRT/Internals/TextureBuilder.cpp @@ -99,13 +99,13 @@ void TextureBuilder::reduce_previous_allocation_to(size_t actual_length) { // against rounding errors when this run is drawn. // TODO: allow somebody else to specify the rule for generating a left-padding value and // a right-padding value. - uint8_t *start_pointer = pointer_to_location(write_area_.x, write_area_.y); - memcpy( &start_pointer[-bytes_per_pixel_], - start_pointer, + uint8_t *start_pointer = pointer_to_location(write_area_.x, write_area_.y) - bytes_per_pixel_; + memcpy( start_pointer, + &start_pointer[bytes_per_pixel_], bytes_per_pixel_); - memcpy( &start_pointer[actual_length * bytes_per_pixel_], - &start_pointer[(actual_length - 1) * bytes_per_pixel_], + memcpy( &start_pointer[(actual_length + 1) * bytes_per_pixel_], + &start_pointer[actual_length * bytes_per_pixel_], bytes_per_pixel_); } From 92d9805f0951dbb755c33f1533a646dbfcf2e52f Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Tue, 17 Oct 2017 20:51:40 -0400 Subject: [PATCH 11/16] Removes dead Objective-C protocol references. --- OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj | 4 ---- 1 file changed, 4 deletions(-) diff --git a/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj b/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj index db6b35038..38aef314d 100644 --- a/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj +++ b/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj @@ -528,7 +528,6 @@ 4B2A332E1DB86869002876E3 /* OricOptionsPanel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OricOptionsPanel.swift; sourceTree = ""; }; 4B2A53901D117D36003C6002 /* CSAudioQueue.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CSAudioQueue.h; sourceTree = ""; }; 4B2A53911D117D36003C6002 /* CSAudioQueue.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CSAudioQueue.m; sourceTree = ""; }; - 4B2A53931D117D36003C6002 /* CSKeyboardMachine.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CSKeyboardMachine.h; sourceTree = ""; }; 4B2A53941D117D36003C6002 /* CSMachine+Subclassing.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "CSMachine+Subclassing.h"; sourceTree = ""; }; 4B2A53951D117D36003C6002 /* CSMachine.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CSMachine.h; sourceTree = ""; }; 4B2A53961D117D36003C6002 /* CSMachine.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = CSMachine.mm; sourceTree = ""; }; @@ -741,7 +740,6 @@ 4B96F7201D75119A0058BB2D /* Tape.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Tape.cpp; path = ../../StaticAnalyser/Acorn/Tape.cpp; sourceTree = ""; }; 4B96F7211D75119A0058BB2D /* Tape.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = Tape.hpp; path = ../../StaticAnalyser/Acorn/Tape.hpp; sourceTree = ""; }; 4B9CCDA01DA279CA0098B625 /* Vic20OptionsPanel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Vic20OptionsPanel.swift; sourceTree = ""; }; - 4B9CCDA21DA27C3F0098B625 /* CSJoystickMachine.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CSJoystickMachine.h; sourceTree = ""; }; 4BA0F68C1EEA0E8400E9489E /* ZX8081.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ZX8081.cpp; path = Data/ZX8081.cpp; sourceTree = ""; }; 4BA0F68D1EEA0E8400E9489E /* ZX8081.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = ZX8081.hpp; path = Data/ZX8081.hpp; sourceTree = ""; }; 4BA22B051D8817CE0008C640 /* Disk.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Disk.cpp; path = ../../StaticAnalyser/Commodore/Disk.cpp; sourceTree = ""; }; @@ -1283,8 +1281,6 @@ isa = PBXGroup; children = ( 4BBC34241D2208B100FFC9DF /* CSFastLoading.h */, - 4B9CCDA21DA27C3F0098B625 /* CSJoystickMachine.h */, - 4B2A53931D117D36003C6002 /* CSKeyboardMachine.h */, 4B2A53951D117D36003C6002 /* CSMachine.h */, 4B2A53941D117D36003C6002 /* CSMachine+Subclassing.h */, 4B643F3C1D77AE5C00D431D6 /* CSMachine+Target.h */, From 5c141af734b60d01cc7af6a330a429f1f924d4b7 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Tue, 17 Oct 2017 22:40:32 -0400 Subject: [PATCH 12/16] Prevents undefined behaviour from the CPC's timer. --- Machines/AmstradCPC/AmstradCPC.cpp | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/Machines/AmstradCPC/AmstradCPC.cpp b/Machines/AmstradCPC/AmstradCPC.cpp index 317eaead5..5d4052f8d 100644 --- a/Machines/AmstradCPC/AmstradCPC.cpp +++ b/Machines/AmstradCPC/AmstradCPC.cpp @@ -36,8 +36,6 @@ namespace AmstradCPC { */ class InterruptTimer { public: - InterruptTimer() : timer_(0), interrupt_request_(false) {} - /*! Indicates that a new hsync pulse has been recognised. This should be supplied on the falling edge of the CRTC HSYNC signal, which is the @@ -94,10 +92,10 @@ class InterruptTimer { } private: - int reset_counter_; - bool interrupt_request_; - bool last_interrupt_request_; - int timer_; + int reset_counter_ = 0; + bool interrupt_request_ = false; + bool last_interrupt_request_ = false; + int timer_ = 0; }; /*! From 185a6992791319c4b5a12977fc07e0861e881b3f Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Thu, 19 Oct 2017 22:01:24 -0400 Subject: [PATCH 13/16] Fixes off-by-one keyboard state accumulation error. --- Inputs/Keyboard.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Inputs/Keyboard.cpp b/Inputs/Keyboard.cpp index 6acfec9bc..b424ccbb9 100644 --- a/Inputs/Keyboard.cpp +++ b/Inputs/Keyboard.cpp @@ -14,8 +14,8 @@ Keyboard::Keyboard() {} void Keyboard::set_key_pressed(Key key, bool is_pressed) { size_t key_offset = static_cast(key); - if(key_offset > key_states_.size()) { - key_states_.resize(key_offset, false); + if(key_offset >= key_states_.size()) { + key_states_.resize(key_offset+1, false); } key_states_[key_offset] = is_pressed; From b5b6219cb7602b1d1a542df99ff8e7f5280a4479 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Thu, 19 Oct 2017 22:02:00 -0400 Subject: [PATCH 14/16] Slightly simplifies TextureBuilder arithmetic. --- Outputs/CRT/Internals/TextureBuilder.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Outputs/CRT/Internals/TextureBuilder.cpp b/Outputs/CRT/Internals/TextureBuilder.cpp index 9e5d5003f..101c81a33 100644 --- a/Outputs/CRT/Internals/TextureBuilder.cpp +++ b/Outputs/CRT/Internals/TextureBuilder.cpp @@ -72,7 +72,7 @@ uint8_t *TextureBuilder::allocate_write_area(size_t required_length, size_t requ size_t alignment_offset = (required_alignment - ((write_areas_start_x_ + 1) % required_alignment)) % required_alignment; if(write_areas_start_x_ + required_length + 2 + alignment_offset > InputBufferBuilderWidth) { write_areas_start_x_ = 0; - alignment_offset = (required_alignment - 1) % required_alignment; + alignment_offset = required_alignment - 1; write_areas_start_y_ = (write_areas_start_y_ + 1) % InputBufferBuilderHeight; if(write_areas_start_y_ == first_unsubmitted_y_) { From c2f6799f0ceb0f0e80267d8d048c667b63f21852 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Thu, 19 Oct 2017 22:02:34 -0400 Subject: [PATCH 15/16] Implements Vic-20 restore key. --- Machines/Commodore/Vic-20/Vic20.cpp | 19 +++++++++---------- Machines/Commodore/Vic-20/Vic20.hpp | 2 +- 2 files changed, 10 insertions(+), 11 deletions(-) diff --git a/Machines/Commodore/Vic-20/Vic20.cpp b/Machines/Commodore/Vic-20/Vic20.cpp index 2f6261140..0549514ec 100644 --- a/Machines/Commodore/Vic-20/Vic20.cpp +++ b/Machines/Commodore/Vic-20/Vic20.cpp @@ -119,14 +119,10 @@ class KeyboardVIA: public MOS::MOS6522::IRQDelegatePortHandler { /// Sets whether @c key @c is_pressed. void set_key_state(uint16_t key, bool is_pressed) { - if(key == KeyRestore) { - // TODO: how is restore wired? - } else { - if(is_pressed) - columns_[key & 7] &= ~(key >> 3); - else - columns_[key & 7] |= (key >> 3); - } + if(is_pressed) + columns_[key & 7] &= ~(key >> 3); + else + columns_[key & 7] |= (key >> 3); } /// Sets all keys as unpressed. @@ -375,8 +371,11 @@ class ConcreteMachine: return !media.tapes.empty() || (!media.disks.empty() && c1540_ != nullptr) || !media.cartridges.empty(); } - void set_key_state(uint16_t key, bool isPressed) override final { - keyboard_via_port_handler_->set_key_state(key, isPressed); + void set_key_state(uint16_t key, bool is_pressed) override final { + if(key != KeyRestore) + keyboard_via_port_handler_->set_key_state(key, is_pressed); + else + user_port_via_.set_control_line_input(MOS::MOS6522::Port::A, MOS::MOS6522::Line::One, !is_pressed); } void clear_all_keys() override final { diff --git a/Machines/Commodore/Vic-20/Vic20.hpp b/Machines/Commodore/Vic-20/Vic20.hpp index 829c207f6..10bc09365 100644 --- a/Machines/Commodore/Vic-20/Vic20.hpp +++ b/Machines/Commodore/Vic-20/Vic20.hpp @@ -57,7 +57,7 @@ enum Key: uint16_t { Key1 = key(0, 0x01), Key3 = key(0, 0x02), Key5 = key(0, 0x04), Key7 = key(0, 0x08), Key9 = key(0, 0x10), KeyPlus = key(0, 0x20), KeyGBP = key(0, 0x40), KeyDelete = key(0, 0x80), - KeyRestore = 0xfffe + KeyRestore = 0xfffd #undef key }; From 1825af0dd3aafec85cd2df467e835fa48b40fbf1 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Thu, 19 Oct 2017 22:15:21 -0400 Subject: [PATCH 16/16] Eliminates dead code in the Vic-20 and Inputs::Joystick. --- Inputs/Joystick.cpp | 9 --------- Machines/Commodore/Vic-20/Vic20.cpp | 3 --- 2 files changed, 12 deletions(-) delete mode 100644 Inputs/Joystick.cpp diff --git a/Inputs/Joystick.cpp b/Inputs/Joystick.cpp deleted file mode 100644 index df0104423..000000000 --- a/Inputs/Joystick.cpp +++ /dev/null @@ -1,9 +0,0 @@ -// -// Joystick.cpp -// Clock Signal -// -// Created by Thomas Harte on 14/10/2017. -// Copyright © 2017 Thomas Harte. All rights reserved. -// - -#include "Joystick.hpp" diff --git a/Machines/Commodore/Vic-20/Vic20.cpp b/Machines/Commodore/Vic-20/Vic20.cpp index 0549514ec..56fd12270 100644 --- a/Machines/Commodore/Vic-20/Vic20.cpp +++ b/Machines/Commodore/Vic-20/Vic20.cpp @@ -242,9 +242,6 @@ class Joystick: public Inputs::Joystick { keyboard_via_port_handler_.set_joystick_state(mapped_input, is_active); } - void reset_all_inputs() override { - } - private: UserPortVIA &user_port_via_port_handler_; KeyboardVIA &keyboard_via_port_handler_;