From e93dbdb4636e2adf88d1e16eca689c510c284345 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Mon, 11 Jan 2016 19:48:31 -0500 Subject: [PATCH] Implemented keyboard input. --- Machines/Electron/Electron.cpp | 20 +++ Machines/Electron/Electron.hpp | 76 ++++++++- .../Clock Signal.xcodeproj/project.pbxproj | 2 + .../Documents/ElectronDocument.swift | 16 +- .../Mac/Clock Signal/Wrappers/CSElectron.h | 3 + .../Mac/Clock Signal/Wrappers/CSElectron.mm | 74 +++++++++ .../Mac/Clock Signal/Wrappers/CSMachine.mm | 14 -- .../Mac/Clock Signal/Wrappers/KeyCodes.h | 146 ++++++++++++++++++ 8 files changed, 333 insertions(+), 18 deletions(-) create mode 100644 OSBindings/Mac/Clock Signal/Wrappers/KeyCodes.h diff --git a/Machines/Electron/Electron.cpp b/Machines/Electron/Electron.cpp index 58d0aaa7b..4c2fb0b14 100644 --- a/Machines/Electron/Electron.cpp +++ b/Machines/Electron/Electron.cpp @@ -22,6 +22,7 @@ Machine::Machine() : _frameCycles(0), _outputPosition(0) { + memset(_keyStates, 0, sizeof(_keyStates)); _crt = new Outputs::CRT(crt_cycles_per_line, 312, 1, 1); _interruptStatus = 0x02; setup6502(); @@ -151,6 +152,10 @@ unsigned int Machine::perform_bus_operation(CPU6502::BusOperation operation, uin case ROMSlotKeyboard: case ROMSlotKeyboard+1: *value = 0xf0; + for(int address_line = 0; address_line < 14; address_line++) + { + if(!(address&(1 << address_line))) *value |= _keyStates[address_line]; + } break; default: *value = 0xff; @@ -318,3 +323,18 @@ const char *Machine::get_signal_decoder() "return vec4( step(mod(texValue, 8.0/256.0), 4.0/256.0), step(mod(texValue, 4.0/256.0), 2.0/256.0), step(mod(texValue, 2.0/256.0), 1.0/256.0), 1.0);\n" "}"; } + +void Machine::set_key_state(Key key, bool isPressed) +{ + if(key == KeyBreak) + { + set_reset_line(isPressed); + } + else + { + if(isPressed) + _keyStates[key >> 4] |= key&0xf; + else + _keyStates[key >> 4] &= ~(key&0xf); + } +} diff --git a/Machines/Electron/Electron.hpp b/Machines/Electron/Electron.hpp index 52acfaadc..ac9b64b65 100644 --- a/Machines/Electron/Electron.hpp +++ b/Machines/Electron/Electron.hpp @@ -37,6 +37,78 @@ enum Interrupt: uint8_t { InterruptHighToneDetect = 0x40 }; +enum Key: uint16_t { + KeySpace = 0x0000 | 0x08, + KeyCopy = 0x0000 | 0x02, + KeyRight = 0x0000 | 0x01, + + KeyDelete = 0x0010 | 0x08, + KeyReturn = 0x0010 | 0x04, + KeyDown = 0x0010 | 0x02, + KeyLeft = 0x0010 | 0x01, + + KeyColon = 0x0020 | 0x04, + KeyUp = 0x0020 | 0x02, + KeyMinus = 0x0020 | 0x01, + + KeySlash = 0x0030 | 0x08, + KeySemiColon = 0x0030 | 0x04, + KeyP = 0x0030 | 0x02, + Key0 = 0x0030 | 0x01, + + KeyFullStop = 0x0040 | 0x08, + KeyL = 0x0040 | 0x04, + KeyO = 0x0040 | 0x02, + Key9 = 0x0040 | 0x01, + + KeyComma = 0x0050 | 0x08, + KeyK = 0x0050 | 0x04, + KeyI = 0x0050 | 0x02, + Key8 = 0x0050 | 0x01, + + KeyM = 0x0060 | 0x08, + KeyJ = 0x0060 | 0x04, + KeyU = 0x0060 | 0x02, + Key7 = 0x0060 | 0x01, + + KeyN = 0x0070 | 0x08, + KeyH = 0x0070 | 0x04, + KeyY = 0x0070 | 0x02, + Key6 = 0x0070 | 0x01, + + KeyB = 0x0080 | 0x08, + KeyG = 0x0080 | 0x04, + KeyT = 0x0080 | 0x02, + Key5 = 0x0080 | 0x01, + + KeyV = 0x0090 | 0x08, + KeyF = 0x0090 | 0x04, + KeyR = 0x0090 | 0x02, + Key4 = 0x0090 | 0x01, + + KeyC = 0x00a0 | 0x08, + KeyD = 0x00a0 | 0x04, + KeyE = 0x00a0 | 0x02, + Key3 = 0x00a0 | 0x01, + + KeyX = 0x00b0 | 0x08, + KeyS = 0x00b0 | 0x04, + KeyW = 0x00b0 | 0x02, + Key2 = 0x00b0 | 0x01, + + KeyZ = 0x00c0 | 0x08, + KeyA = 0x00c0 | 0x04, + KeyQ = 0x00c0 | 0x02, + Key1 = 0x00c0 | 0x01, + + KeyShift = 0x00d0 | 0x08, + KeyControl = 0x00d0 | 0x04, + KeyFunc = 0x00d0 | 0x02, + KeyEscape = 0x00d0 | 0x01, + + KeyBreak = 0xffff +}; + class Machine: public CPU6502::Processor { public: @@ -47,6 +119,7 @@ class Machine: public CPU6502::Processor { unsigned int perform_bus_operation(CPU6502::BusOperation operation, uint16_t address, uint8_t *value); void set_rom(ROMSlot slot, size_t length, const uint8_t *data); + void set_key_state(Key key, bool isPressed); Outputs::CRT *get_crt() { return _crt; } const char *get_signal_decoder(); @@ -54,7 +127,8 @@ class Machine: public CPU6502::Processor { private: uint8_t _os[16384], _basic[16384], _ram[32768]; uint8_t _interruptStatus, _interruptControl; - uint8_t palette[16]; + uint8_t _palette[16]; + uint8_t _keyStates[14]; ROMSlot _activeRom; Outputs::CRT *_crt; diff --git a/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj b/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj index a6e376595..9f1210530 100644 --- a/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj +++ b/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj @@ -349,6 +349,7 @@ 4B55CE5C1C3B7D6F0093A61B /* CSCathodeRayView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CSCathodeRayView.m; sourceTree = ""; }; 4B55CE5E1C3B7D960093A61B /* MachineDocument.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MachineDocument.swift; sourceTree = ""; }; 4B92EAC91B7C112B00246143 /* TimingTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TimingTests.swift; sourceTree = ""; }; + 4BAE587D1C447B7A005B9AF0 /* KeyCodes.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = KeyCodes.h; sourceTree = ""; }; 4BB297DF1B587D8200A49093 /* Clock SignalTests-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Clock SignalTests-Bridging-Header.h"; sourceTree = ""; }; 4BB297E01B587D8300A49093 /* 6502_functional_test.bin */ = {isa = PBXFileReference; lastKnownFileType = archive.macbinary; path = 6502_functional_test.bin; sourceTree = ""; }; 4BB297E11B587D8300A49093 /* AllSuiteA.bin */ = {isa = PBXFileReference; lastKnownFileType = archive.macbinary; path = AllSuiteA.bin; sourceTree = ""; }; @@ -721,6 +722,7 @@ 4B55CE4F1C3B78A80093A61B /* CSMachine+Subclassing.h */, 4B55CE521C3B7ABF0093A61B /* CSElectron.h */, 4B55CE531C3B7ABF0093A61B /* CSElectron.mm */, + 4BAE587D1C447B7A005B9AF0 /* KeyCodes.h */, ); path = Wrappers; sourceTree = ""; diff --git a/OSBindings/Mac/Clock Signal/Documents/ElectronDocument.swift b/OSBindings/Mac/Clock Signal/Documents/ElectronDocument.swift index 86f06db98..f5a890a60 100644 --- a/OSBindings/Mac/Clock Signal/Documents/ElectronDocument.swift +++ b/OSBindings/Mac/Clock Signal/Documents/ElectronDocument.swift @@ -42,8 +42,18 @@ class ElectronDocument: MachineDocument { } // MARK: CSOpenGLViewResponderDelegate -// func keyDown(event: NSEvent) {} -// func keyUp(event: NSEvent) {} -// func flagsChanged(newModifiers: NSEvent) {} + override func keyDown(event: NSEvent) { + electron.setKey(event.keyCode, isPressed: true) + } + + override func keyUp(event: NSEvent) { + electron.setKey(event.keyCode, isPressed: false) + } + + override func flagsChanged(newModifiers: NSEvent) { + electron.setKey(kVK_Shift, isPressed: newModifiers.modifierFlags.contains(.ShiftKeyMask)) + electron.setKey(kVK_Control, isPressed: newModifiers.modifierFlags.contains(.ControlKeyMask)) + electron.setKey(kVK_Command, isPressed: newModifiers.modifierFlags.contains(.CommandKeyMask)) + } } diff --git a/OSBindings/Mac/Clock Signal/Wrappers/CSElectron.h b/OSBindings/Mac/Clock Signal/Wrappers/CSElectron.h index 1826efd24..b8af2bec4 100644 --- a/OSBindings/Mac/Clock Signal/Wrappers/CSElectron.h +++ b/OSBindings/Mac/Clock Signal/Wrappers/CSElectron.h @@ -7,10 +7,13 @@ // #include "CSMachine.h" +#import "KeyCodes.h" @interface CSElectron : CSMachine - (void)setOSROM:(nonnull NSData *)rom; - (void)setBASICROM:(nonnull NSData *)rom; +- (void)setKey:(uint16_t)key isPressed:(BOOL)isPressed; + @end diff --git a/OSBindings/Mac/Clock Signal/Wrappers/CSElectron.mm b/OSBindings/Mac/Clock Signal/Wrappers/CSElectron.mm index c800f98ab..5df5b09a2 100644 --- a/OSBindings/Mac/Clock Signal/Wrappers/CSElectron.mm +++ b/OSBindings/Mac/Clock Signal/Wrappers/CSElectron.mm @@ -36,4 +36,78 @@ [view setSignalDecoder:[NSString stringWithUTF8String:_electron.get_signal_decoder()] type:CSCathodeRayViewSignalTypeRGB]; } +- (void)setKey:(uint16_t)key isPressed:(BOOL)isPressed { + switch(key) + { + case kVK_ANSI_0: _electron.set_key_state(Electron::Key::Key0, isPressed); break; + case kVK_ANSI_1: _electron.set_key_state(Electron::Key::Key1, isPressed); break; + case kVK_ANSI_2: _electron.set_key_state(Electron::Key::Key2, isPressed); break; + case kVK_ANSI_3: _electron.set_key_state(Electron::Key::Key3, isPressed); break; + case kVK_ANSI_4: _electron.set_key_state(Electron::Key::Key4, isPressed); break; + case kVK_ANSI_5: _electron.set_key_state(Electron::Key::Key5, isPressed); break; + case kVK_ANSI_6: _electron.set_key_state(Electron::Key::Key6, isPressed); break; + case kVK_ANSI_7: _electron.set_key_state(Electron::Key::Key7, isPressed); break; + case kVK_ANSI_8: _electron.set_key_state(Electron::Key::Key8, isPressed); break; + case kVK_ANSI_9: _electron.set_key_state(Electron::Key::Key9, isPressed); break; + + case kVK_ANSI_Q: _electron.set_key_state(Electron::Key::KeyQ, isPressed); break; + case kVK_ANSI_W: _electron.set_key_state(Electron::Key::KeyW, isPressed); break; + case kVK_ANSI_E: _electron.set_key_state(Electron::Key::KeyE, isPressed); break; + case kVK_ANSI_R: _electron.set_key_state(Electron::Key::KeyR, isPressed); break; + case kVK_ANSI_T: _electron.set_key_state(Electron::Key::KeyT, isPressed); break; + case kVK_ANSI_Y: _electron.set_key_state(Electron::Key::KeyY, isPressed); break; + case kVK_ANSI_U: _electron.set_key_state(Electron::Key::KeyU, isPressed); break; + case kVK_ANSI_I: _electron.set_key_state(Electron::Key::KeyI, isPressed); break; + case kVK_ANSI_O: _electron.set_key_state(Electron::Key::KeyO, isPressed); break; + case kVK_ANSI_P: _electron.set_key_state(Electron::Key::KeyP, isPressed); break; + case kVK_ANSI_A: _electron.set_key_state(Electron::Key::KeyA, isPressed); break; + case kVK_ANSI_S: _electron.set_key_state(Electron::Key::KeyS, isPressed); break; + case kVK_ANSI_D: _electron.set_key_state(Electron::Key::KeyD, isPressed); break; + case kVK_ANSI_F: _electron.set_key_state(Electron::Key::KeyF, isPressed); break; + case kVK_ANSI_G: _electron.set_key_state(Electron::Key::KeyG, isPressed); break; + case kVK_ANSI_H: _electron.set_key_state(Electron::Key::KeyH, isPressed); break; + case kVK_ANSI_J: _electron.set_key_state(Electron::Key::KeyJ, isPressed); break; + case kVK_ANSI_K: _electron.set_key_state(Electron::Key::KeyK, isPressed); break; + case kVK_ANSI_L: _electron.set_key_state(Electron::Key::KeyL, isPressed); break; + case kVK_ANSI_Z: _electron.set_key_state(Electron::Key::KeyZ, isPressed); break; + case kVK_ANSI_X: _electron.set_key_state(Electron::Key::KeyX, isPressed); break; + case kVK_ANSI_C: _electron.set_key_state(Electron::Key::KeyC, isPressed); break; + case kVK_ANSI_V: _electron.set_key_state(Electron::Key::KeyV, isPressed); break; + case kVK_ANSI_B: _electron.set_key_state(Electron::Key::KeyB, isPressed); break; + case kVK_ANSI_N: _electron.set_key_state(Electron::Key::KeyN, isPressed); break; + case kVK_ANSI_M: _electron.set_key_state(Electron::Key::KeyM, isPressed); break; + + case kVK_Space: _electron.set_key_state(Electron::Key::KeySpace, isPressed); break; + case kVK_ANSI_Grave: + case kVK_ANSI_Backslash: + _electron.set_key_state(Electron::Key::KeyCopy, isPressed); break; + case kVK_Return: _electron.set_key_state(Electron::Key::KeyReturn, isPressed); break; + case kVK_ANSI_Minus: _electron.set_key_state(Electron::Key::KeyMinus, isPressed); break; + + case kVK_RightArrow: _electron.set_key_state(Electron::Key::KeyRight, isPressed); break; + case kVK_LeftArrow: _electron.set_key_state(Electron::Key::KeyLeft, isPressed); break; + case kVK_DownArrow: _electron.set_key_state(Electron::Key::KeyDown, isPressed); break; + case kVK_UpArrow: _electron.set_key_state(Electron::Key::KeyUp, isPressed); break; + + case kVK_Delete: _electron.set_key_state(Electron::Key::KeyDelete, isPressed); break; + case kVK_Escape: _electron.set_key_state(Electron::Key::KeyEscape, isPressed); break; + + case kVK_ANSI_Comma: _electron.set_key_state(Electron::Key::KeyComma, isPressed); break; + case kVK_ANSI_Period: _electron.set_key_state(Electron::Key::KeyFullStop, isPressed); break; + + case kVK_ANSI_Semicolon: + _electron.set_key_state(Electron::Key::KeySemiColon, isPressed); break; + case kVK_ANSI_Quote: _electron.set_key_state(Electron::Key::KeyColon, isPressed); break; + + case kVK_ANSI_Slash: _electron.set_key_state(Electron::Key::KeySlash, isPressed); break; + + case kVK_Shift: _electron.set_key_state(Electron::Key::KeyShift, isPressed); break; + case kVK_Control: _electron.set_key_state(Electron::Key::KeyControl, isPressed); break; + case kVK_Command: _electron.set_key_state(Electron::Key::KeyFunc, isPressed); break; + + default: + break; + } +} + @end diff --git a/OSBindings/Mac/Clock Signal/Wrappers/CSMachine.mm b/OSBindings/Mac/Clock Signal/Wrappers/CSMachine.mm index cb5a5f3f8..696c78438 100644 --- a/OSBindings/Mac/Clock Signal/Wrappers/CSMachine.mm +++ b/OSBindings/Mac/Clock Signal/Wrappers/CSMachine.mm @@ -26,9 +26,6 @@ typedef NS_ENUM(NSInteger, CSAtari2600RunningState) { dispatch_queue_t _serialDispatchQueue; NSConditionLock *_runningLock; - - int _frameCount; - NSTimeInterval _firstFrame; } - (void)perform:(dispatch_block_t)action { @@ -37,17 +34,6 @@ typedef NS_ENUM(NSInteger, CSAtari2600RunningState) { - (void)crt:(Outputs::CRT *)crt didEndFrame:(CRTFrame *)frame didDetectVSync:(BOOL)didDetectVSync { if([self.view pushFrame:frame]) crt->return_frame(); - - if(!_frameCount) _firstFrame = [NSDate timeIntervalSinceReferenceDate]; - _frameCount++; - -// NSLog(@"!-!"); - - if(!(_frameCount%50)) - { - NSTimeInterval timeSinceFirstFrame = [NSDate timeIntervalSinceReferenceDate] - _firstFrame; - NSLog(@"%d in %0.2f: %0.2f", _frameCount, timeSinceFirstFrame, (double)_frameCount / timeSinceFirstFrame); - } } - (void)runForNumberOfCycles:(int)cycles { diff --git a/OSBindings/Mac/Clock Signal/Wrappers/KeyCodes.h b/OSBindings/Mac/Clock Signal/Wrappers/KeyCodes.h new file mode 100644 index 000000000..bc30eaaf2 --- /dev/null +++ b/OSBindings/Mac/Clock Signal/Wrappers/KeyCodes.h @@ -0,0 +1,146 @@ +// +// KeyCodes.h +// Clock Signal +// +// Emancipated from Carbon's HIToolbox by Thomas Harte on 11/01/2016. +// Copyright © 2016 Thomas Harte. All rights reserved. +// + +#ifndef KeyCodes_h +#define KeyCodes_h + +/* + * Summary: + * Virtual keycodes + * + * Discussion: + * These constants are the virtual keycodes defined originally in + * Inside Mac Volume V, pg. V-191. They identify physical keys on a + * keyboard. Those constants with "ANSI" in the name are labeled + * according to the key position on an ANSI-standard US keyboard. + * For example, kVK_ANSI_A indicates the virtual keycode for the key + * with the letter 'A' in the US keyboard layout. Other keyboard + * layouts may have the 'A' key label on a different physical key; + * in this case, pressing 'A' will generate a different virtual + * keycode. + */ +enum: uint16_t { + kVK_ANSI_A = 0x00, + kVK_ANSI_S = 0x01, + kVK_ANSI_D = 0x02, + kVK_ANSI_F = 0x03, + kVK_ANSI_H = 0x04, + kVK_ANSI_G = 0x05, + kVK_ANSI_Z = 0x06, + kVK_ANSI_X = 0x07, + kVK_ANSI_C = 0x08, + kVK_ANSI_V = 0x09, + kVK_ANSI_B = 0x0B, + kVK_ANSI_Q = 0x0C, + kVK_ANSI_W = 0x0D, + kVK_ANSI_E = 0x0E, + kVK_ANSI_R = 0x0F, + kVK_ANSI_Y = 0x10, + kVK_ANSI_T = 0x11, + kVK_ANSI_1 = 0x12, + kVK_ANSI_2 = 0x13, + kVK_ANSI_3 = 0x14, + kVK_ANSI_4 = 0x15, + kVK_ANSI_6 = 0x16, + kVK_ANSI_5 = 0x17, + kVK_ANSI_Equal = 0x18, + kVK_ANSI_9 = 0x19, + kVK_ANSI_7 = 0x1A, + kVK_ANSI_Minus = 0x1B, + kVK_ANSI_8 = 0x1C, + kVK_ANSI_0 = 0x1D, + kVK_ANSI_RightBracket = 0x1E, + kVK_ANSI_O = 0x1F, + kVK_ANSI_U = 0x20, + kVK_ANSI_LeftBracket = 0x21, + kVK_ANSI_I = 0x22, + kVK_ANSI_P = 0x23, + kVK_ANSI_L = 0x25, + kVK_ANSI_J = 0x26, + kVK_ANSI_Quote = 0x27, + kVK_ANSI_K = 0x28, + kVK_ANSI_Semicolon = 0x29, + kVK_ANSI_Backslash = 0x2A, + kVK_ANSI_Comma = 0x2B, + kVK_ANSI_Slash = 0x2C, + kVK_ANSI_N = 0x2D, + kVK_ANSI_M = 0x2E, + kVK_ANSI_Period = 0x2F, + kVK_ANSI_Grave = 0x32, + kVK_ANSI_KeypadDecimal = 0x41, + kVK_ANSI_KeypadMultiply = 0x43, + kVK_ANSI_KeypadPlus = 0x45, + kVK_ANSI_KeypadClear = 0x47, + kVK_ANSI_KeypadDivide = 0x4B, + kVK_ANSI_KeypadEnter = 0x4C, + kVK_ANSI_KeypadMinus = 0x4E, + kVK_ANSI_KeypadEquals = 0x51, + kVK_ANSI_Keypad0 = 0x52, + kVK_ANSI_Keypad1 = 0x53, + kVK_ANSI_Keypad2 = 0x54, + kVK_ANSI_Keypad3 = 0x55, + kVK_ANSI_Keypad4 = 0x56, + kVK_ANSI_Keypad5 = 0x57, + kVK_ANSI_Keypad6 = 0x58, + kVK_ANSI_Keypad7 = 0x59, + kVK_ANSI_Keypad8 = 0x5B, + kVK_ANSI_Keypad9 = 0x5C +}; + +/* keycodes for keys that are independent of keyboard layout*/ +enum: uint16_t { + kVK_Return = 0x24, + kVK_Tab = 0x30, + kVK_Space = 0x31, + kVK_Delete = 0x33, + kVK_Escape = 0x35, + kVK_Command = 0x37, + kVK_Shift = 0x38, + kVK_CapsLock = 0x39, + kVK_Option = 0x3A, + kVK_Control = 0x3B, + kVK_RightShift = 0x3C, + kVK_RightOption = 0x3D, + kVK_RightControl = 0x3E, + kVK_Function = 0x3F, + kVK_F17 = 0x40, + kVK_VolumeUp = 0x48, + kVK_VolumeDown = 0x49, + kVK_Mute = 0x4A, + kVK_F18 = 0x4F, + kVK_F19 = 0x50, + kVK_F20 = 0x5A, + kVK_F5 = 0x60, + kVK_F6 = 0x61, + kVK_F7 = 0x62, + kVK_F3 = 0x63, + kVK_F8 = 0x64, + kVK_F9 = 0x65, + kVK_F11 = 0x67, + kVK_F13 = 0x69, + kVK_F16 = 0x6A, + kVK_F14 = 0x6B, + kVK_F10 = 0x6D, + kVK_F12 = 0x6F, + kVK_F15 = 0x71, + kVK_Help = 0x72, + kVK_Home = 0x73, + kVK_PageUp = 0x74, + kVK_ForwardDelete = 0x75, + kVK_F4 = 0x76, + kVK_End = 0x77, + kVK_F2 = 0x78, + kVK_PageDown = 0x79, + kVK_F1 = 0x7A, + kVK_LeftArrow = 0x7B, + kVK_RightArrow = 0x7C, + kVK_DownArrow = 0x7D, + kVK_UpArrow = 0x7E +}; + +#endif /* KeyCodes_h */