mirror of
https://github.com/TomHarte/CLK.git
synced 2024-11-25 16:31:42 +00:00
Extends the keyboard protocol and adds keyboard input to the Apple II.
This commit is contained in:
parent
be05d51e07
commit
465c38f03c
@ -12,7 +12,7 @@ using namespace Inputs;
|
|||||||
|
|
||||||
Keyboard::Keyboard() {}
|
Keyboard::Keyboard() {}
|
||||||
|
|
||||||
void Keyboard::set_key_pressed(Key key, bool is_pressed) {
|
void Keyboard::set_key_pressed(Key key, char value, bool is_pressed) {
|
||||||
std::size_t key_offset = static_cast<std::size_t>(key);
|
std::size_t key_offset = static_cast<std::size_t>(key);
|
||||||
if(key_offset >= key_states_.size()) {
|
if(key_offset >= key_states_.size()) {
|
||||||
key_states_.resize(key_offset+1, false);
|
key_states_.resize(key_offset+1, false);
|
||||||
|
@ -40,7 +40,7 @@ class Keyboard {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Host interface.
|
// Host interface.
|
||||||
virtual void set_key_pressed(Key key, bool is_pressed);
|
virtual void set_key_pressed(Key key, char value, bool is_pressed);
|
||||||
virtual void reset_all_keys();
|
virtual void reset_all_keys();
|
||||||
|
|
||||||
// Delegate interface.
|
// Delegate interface.
|
||||||
|
@ -9,6 +9,7 @@
|
|||||||
#include "AppleII.hpp"
|
#include "AppleII.hpp"
|
||||||
|
|
||||||
#include "../CRTMachine.hpp"
|
#include "../CRTMachine.hpp"
|
||||||
|
#include "../KeyboardMachine.hpp"
|
||||||
#include "../Utility/MemoryFuzzer.hpp"
|
#include "../Utility/MemoryFuzzer.hpp"
|
||||||
|
|
||||||
#include "../../Processors/6502/6502.hpp"
|
#include "../../Processors/6502/6502.hpp"
|
||||||
@ -21,7 +22,9 @@ namespace {
|
|||||||
|
|
||||||
class ConcreteMachine:
|
class ConcreteMachine:
|
||||||
public CRTMachine::Machine,
|
public CRTMachine::Machine,
|
||||||
|
public KeyboardMachine::Machine,
|
||||||
public CPU::MOS6502::BusHandler,
|
public CPU::MOS6502::BusHandler,
|
||||||
|
public Inputs::Keyboard,
|
||||||
public AppleII::Machine {
|
public AppleII::Machine {
|
||||||
private:
|
private:
|
||||||
struct VideoBusHandler : public AppleII::Video::BusHandler {
|
struct VideoBusHandler : public AppleII::Video::BusHandler {
|
||||||
@ -50,6 +53,7 @@ class ConcreteMachine:
|
|||||||
std::vector<uint8_t> rom_;
|
std::vector<uint8_t> rom_;
|
||||||
std::vector<uint8_t> character_rom_;
|
std::vector<uint8_t> character_rom_;
|
||||||
uint16_t rom_start_address_;
|
uint16_t rom_start_address_;
|
||||||
|
uint8_t keyboard_input_ = 0x00;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
ConcreteMachine():
|
ConcreteMachine():
|
||||||
@ -94,8 +98,7 @@ class ConcreteMachine:
|
|||||||
break;
|
break;
|
||||||
case 0xc000:
|
case 0xc000:
|
||||||
// TODO: read keyboard.
|
// TODO: read keyboard.
|
||||||
// printf("Keyboard poll\n");
|
*value = keyboard_input_;
|
||||||
*value = 0x00;//0x80 | 'A';
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -116,6 +119,10 @@ class ConcreteMachine:
|
|||||||
case 0xc055: update_video(); video_->set_video_page(1); break;
|
case 0xc055: update_video(); video_->set_video_page(1); break;
|
||||||
case 0xc056: update_video(); video_->set_low_resolution(); break;
|
case 0xc056: update_video(); video_->set_low_resolution(); break;
|
||||||
case 0xc057: update_video(); video_->set_high_resolution(); break;
|
case 0xc057: update_video(); video_->set_high_resolution(); break;
|
||||||
|
|
||||||
|
case 0xc010:
|
||||||
|
keyboard_input_ &= 0x7f;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
// The Apple II has a slightly weird timing pattern: every 65th CPU cycle is stretched
|
// The Apple II has a slightly weird timing pattern: every 65th CPU cycle is stretched
|
||||||
@ -155,6 +162,16 @@ class ConcreteMachine:
|
|||||||
void run_for(const Cycles cycles) override {
|
void run_for(const Cycles cycles) override {
|
||||||
m6502_.run_for(cycles);
|
m6502_.run_for(cycles);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void set_key_pressed(Key key, char value, bool is_pressed) override {
|
||||||
|
if(is_pressed) {
|
||||||
|
keyboard_input_ = static_cast<uint8_t>(value | 0x80);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Inputs::Keyboard &get_keyboard() override {
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -45,7 +45,7 @@ template <class BusHandler> class Video {
|
|||||||
|
|
||||||
// Show only the centre 75% of the TV frame.
|
// Show only the centre 75% of the TV frame.
|
||||||
crt_->set_video_signal(Outputs::CRT::VideoSignal::Composite);
|
crt_->set_video_signal(Outputs::CRT::VideoSignal::Composite);
|
||||||
crt_->set_visible_area(Outputs::CRT::Rect(0.115f, 0.115f, 0.77f, 0.77f));
|
crt_->set_visible_area(Outputs::CRT::Rect(0.115f, 0.117f, 0.77f, 0.77f));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @returns The CRT this video feed is feeding.
|
/// @returns The CRT this video feed is feeding.
|
||||||
|
@ -24,12 +24,12 @@ struct KeyActions {
|
|||||||
Indicates that the key @c key has been either pressed or released, according to
|
Indicates that the key @c key has been either pressed or released, according to
|
||||||
the state of @c isPressed.
|
the state of @c isPressed.
|
||||||
*/
|
*/
|
||||||
virtual void set_key_state(uint16_t key, bool is_pressed) = 0;
|
virtual void set_key_state(uint16_t key, bool is_pressed) {}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
Instructs that all keys should now be treated as released.
|
Instructs that all keys should now be treated as released.
|
||||||
*/
|
*/
|
||||||
virtual void clear_all_keys() = 0;
|
virtual void clear_all_keys() {}
|
||||||
};
|
};
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
|
@ -23,6 +23,8 @@
|
|||||||
#import "NSBundle+DataResource.h"
|
#import "NSBundle+DataResource.h"
|
||||||
#import "NSData+StdVector.h"
|
#import "NSData+StdVector.h"
|
||||||
|
|
||||||
|
#include <bitset>
|
||||||
|
|
||||||
@interface CSMachine() <CSFastLoading>
|
@interface CSMachine() <CSFastLoading>
|
||||||
- (void)speaker:(Outputs::Speaker::Speaker *)speaker didCompleteSamples:(const int16_t *)samples length:(int)length;
|
- (void)speaker:(Outputs::Speaker::Speaker *)speaker didCompleteSamples:(const int16_t *)samples length:(int)length;
|
||||||
- (void)speakerDidChangeInputClock:(Outputs::Speaker::Speaker *)speaker;
|
- (void)speakerDidChangeInputClock:(Outputs::Speaker::Speaker *)speaker;
|
||||||
@ -54,6 +56,8 @@ struct SpeakerDelegate: public Outputs::Speaker::Speaker::Delegate, public LockP
|
|||||||
|
|
||||||
CSStaticAnalyser *_analyser;
|
CSStaticAnalyser *_analyser;
|
||||||
std::unique_ptr<Machine::DynamicMachine> _machine;
|
std::unique_ptr<Machine::DynamicMachine> _machine;
|
||||||
|
|
||||||
|
std::bitset<65536> _depressedKeys;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (instancetype)initWithAnalyser:(CSStaticAnalyser *)result {
|
- (instancetype)initWithAnalyser:(CSStaticAnalyser *)result {
|
||||||
@ -168,12 +172,25 @@ struct SpeakerDelegate: public Outputs::Speaker::Speaker::Delegate, public LockP
|
|||||||
- (void)setKey:(uint16_t)key characters:(NSString *)characters isPressed:(BOOL)isPressed {
|
- (void)setKey:(uint16_t)key characters:(NSString *)characters isPressed:(BOOL)isPressed {
|
||||||
auto keyboard_machine = _machine->keyboard_machine();
|
auto keyboard_machine = _machine->keyboard_machine();
|
||||||
if(keyboard_machine) {
|
if(keyboard_machine) {
|
||||||
|
// Don't pass anything on if this is not new information.
|
||||||
|
if(_depressedKeys[key] == !!isPressed) return;
|
||||||
|
_depressedKeys[key] = !!isPressed;
|
||||||
|
|
||||||
|
// Pick an ASCII code, if any.
|
||||||
|
char pressedKey = '\0';
|
||||||
|
if(characters.length) {
|
||||||
|
unichar firstCharacter = [characters characterAtIndex:0];
|
||||||
|
if(firstCharacter < 128) {
|
||||||
|
pressedKey = (char)firstCharacter;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@synchronized(self) {
|
@synchronized(self) {
|
||||||
Inputs::Keyboard &keyboard = keyboard_machine->get_keyboard();
|
Inputs::Keyboard &keyboard = keyboard_machine->get_keyboard();
|
||||||
|
|
||||||
// Connect the Carbon-era Mac keyboard scancodes to Clock Signal's 'universal' enumeration in order
|
// Connect the Carbon-era Mac keyboard scancodes to Clock Signal's 'universal' enumeration in order
|
||||||
// to pass into the platform-neutral realm.
|
// to pass into the platform-neutral realm.
|
||||||
#define BIND(source, dest) case source: keyboard.set_key_pressed(Inputs::Keyboard::Key::dest, isPressed); break
|
#define BIND(source, dest) case source: keyboard.set_key_pressed(Inputs::Keyboard::Key::dest, pressedKey, isPressed); break
|
||||||
switch(key) {
|
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_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_5, k5); BIND(VK_ANSI_6, k6); BIND(VK_ANSI_7, k7); BIND(VK_ANSI_8, k8); BIND(VK_ANSI_9, k9);
|
||||||
|
@ -239,7 +239,7 @@ int main(int argc, char *argv[]) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Determine the machine for the supplied file.
|
// Determine the machine for the supplied file.
|
||||||
TargetList targets = Analyser::Static::GetTargets(arguments.file_name);
|
Analyser::Static::TargetList targets = Analyser::Static::GetTargets(arguments.file_name);
|
||||||
if(targets.empty()) {
|
if(targets.empty()) {
|
||||||
std::cerr << "Cannot open " << arguments.file_name << "; no target machine found" << std::endl;
|
std::cerr << "Cannot open " << arguments.file_name << "; no target machine found" << std::endl;
|
||||||
return -1;
|
return -1;
|
||||||
@ -450,7 +450,12 @@ int main(int argc, char *argv[]) {
|
|||||||
if(keyboard_machine) {
|
if(keyboard_machine) {
|
||||||
Inputs::Keyboard::Key key = Inputs::Keyboard::Key::Space;
|
Inputs::Keyboard::Key key = Inputs::Keyboard::Key::Space;
|
||||||
if(!KeyboardKeyForSDLScancode(event.key.keysym.scancode, key)) break;
|
if(!KeyboardKeyForSDLScancode(event.key.keysym.scancode, key)) break;
|
||||||
keyboard_machine->get_keyboard().set_key_pressed(key, is_pressed);
|
|
||||||
|
char key_value = '\0';
|
||||||
|
const char *key_name = SDL_GetKeyName(event.key.keysym.sym);
|
||||||
|
if(key_name[0] >= 0) key_value = key_name[0];
|
||||||
|
|
||||||
|
keyboard_machine->get_keyboard().set_key_pressed(key, key_value, is_pressed);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user