mirror of
https://github.com/TomHarte/CLK.git
synced 2025-08-08 14:25:05 +00:00
Merge pull request #952 from TomHarte/EnterpriseTyper
Add typer support for the Enterprise.
This commit is contained in:
@@ -13,6 +13,8 @@
|
|||||||
#include "../../../Reflection/Struct.hpp"
|
#include "../../../Reflection/Struct.hpp"
|
||||||
#include "../StaticAnalyser.hpp"
|
#include "../StaticAnalyser.hpp"
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
namespace Analyser {
|
namespace Analyser {
|
||||||
namespace Static {
|
namespace Static {
|
||||||
namespace Enterprise {
|
namespace Enterprise {
|
||||||
@@ -27,6 +29,7 @@ struct Target: public Analyser::Static::Target, public Reflection::StructImpl<Ta
|
|||||||
EXOSVersion exos_version = EXOSVersion::Any;
|
EXOSVersion exos_version = EXOSVersion::Any;
|
||||||
BASICVersion basic_version = BASICVersion::None;
|
BASICVersion basic_version = BASICVersion::None;
|
||||||
DOS dos = DOS::None;
|
DOS dos = DOS::None;
|
||||||
|
std::string loading_command;
|
||||||
|
|
||||||
Target() : Analyser::Static::Target(Machine::Enterprise) {
|
Target() : Analyser::Static::Target(Machine::Enterprise) {
|
||||||
if(needs_declare()) {
|
if(needs_declare()) {
|
||||||
|
@@ -14,6 +14,7 @@
|
|||||||
#include "Nick.hpp"
|
#include "Nick.hpp"
|
||||||
|
|
||||||
#include "../MachineTypes.hpp"
|
#include "../MachineTypes.hpp"
|
||||||
|
#include "../Utility/Typer.hpp"
|
||||||
|
|
||||||
#include "../../Analyser/Static/Enterprise/Target.hpp"
|
#include "../../Analyser/Static/Enterprise/Target.hpp"
|
||||||
#include "../../ClockReceiver/JustInTime.hpp"
|
#include "../../ClockReceiver/JustInTime.hpp"
|
||||||
@@ -69,7 +70,8 @@ template <bool has_disk_controller> class ConcreteMachine:
|
|||||||
public MachineTypes::MappedKeyboardMachine,
|
public MachineTypes::MappedKeyboardMachine,
|
||||||
public MachineTypes::MediaTarget,
|
public MachineTypes::MediaTarget,
|
||||||
public MachineTypes::ScanProducer,
|
public MachineTypes::ScanProducer,
|
||||||
public MachineTypes::TimedMachine {
|
public MachineTypes::TimedMachine,
|
||||||
|
public Utility::TypeRecipient<CharacterMapper> {
|
||||||
private:
|
private:
|
||||||
constexpr uint8_t min_ram_slot(const Analyser::Static::Enterprise::Target &target) {
|
constexpr uint8_t min_ram_slot(const Analyser::Static::Enterprise::Target &target) {
|
||||||
size_t ram_size = 128*1024;
|
size_t ram_size = 128*1024;
|
||||||
@@ -215,6 +217,9 @@ template <bool has_disk_controller> class ConcreteMachine:
|
|||||||
|
|
||||||
// Pass on any media.
|
// Pass on any media.
|
||||||
insert_media(target.media);
|
insert_media(target.media);
|
||||||
|
if(!target.loading_command.empty()) {
|
||||||
|
type_string(target.loading_command);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
~ConcreteMachine() {
|
~ConcreteMachine() {
|
||||||
@@ -425,6 +430,39 @@ template <bool has_disk_controller> class ConcreteMachine:
|
|||||||
update_interrupts();
|
update_interrupts();
|
||||||
break;
|
break;
|
||||||
case 0xb5:
|
case 0xb5:
|
||||||
|
// Logic here: the ROM scans the keyboard by checking ascending
|
||||||
|
// lines. It also seems to provide a line of 0 when using port B5
|
||||||
|
// for non-keyboard uses.
|
||||||
|
//
|
||||||
|
// So: use the rollover from line 9 back to line 0 as a trigger to
|
||||||
|
// spot that a scan of the keyboard just finished. Which makes it
|
||||||
|
// time to enqueue the next keypress.
|
||||||
|
//
|
||||||
|
// Re: is_past_splash_screen_ and typer_delay_, assume that a
|
||||||
|
// single keypress is necessary to get past the Enterprise splash
|
||||||
|
// screen, then a pause in keypressing while BASIC or whatever
|
||||||
|
// starts up, then presses can resume.
|
||||||
|
if(typer_ && active_key_line_ == 9 && !(*cycle.value & 0xf)) {
|
||||||
|
if(!is_past_splash_screen_) {
|
||||||
|
set_key_state(uint16_t(Key::Space), typer_delay_);
|
||||||
|
if(typer_delay_) {
|
||||||
|
--typer_delay_;
|
||||||
|
} else {
|
||||||
|
typer_delay_ = 60;
|
||||||
|
is_past_splash_screen_ = true;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if(!typer_delay_) {
|
||||||
|
if(!typer_->type_next_character()) {
|
||||||
|
clear_all_keys();
|
||||||
|
typer_ = nullptr;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
--typer_delay_;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
active_key_line_ = *cycle.value & 0xf;
|
active_key_line_ = *cycle.value & 0xf;
|
||||||
// TODO:
|
// TODO:
|
||||||
//
|
//
|
||||||
@@ -578,6 +616,21 @@ template <bool has_disk_controller> class ConcreteMachine:
|
|||||||
key_lines_.fill(0xff);
|
key_lines_.fill(0xff);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// MARK: - Utility::TypeRecipient
|
||||||
|
void type_string(const std::string &string) final {
|
||||||
|
Utility::TypeRecipient<CharacterMapper>::add_typer(string);
|
||||||
|
|
||||||
|
is_past_splash_screen_ = !z80_.get_is_resetting();
|
||||||
|
typer_delay_ = !is_past_splash_screen_;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool can_type(char c) const final {
|
||||||
|
return Utility::TypeRecipient<CharacterMapper>::can_type(c);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool is_past_splash_screen_ = false;
|
||||||
|
int typer_delay_ = 30;
|
||||||
|
|
||||||
// MARK: - MediaTarget
|
// MARK: - MediaTarget
|
||||||
bool insert_media(const Analyser::Static::Media &media) final {
|
bool insert_media(const Analyser::Static::Media &media) final {
|
||||||
if constexpr (has_disk_controller) {
|
if constexpr (has_disk_controller) {
|
||||||
|
@@ -20,7 +20,7 @@ uint16_t KeyboardMapper::mapped_key_for_key(Inputs::Keyboard::Key key) const {
|
|||||||
BIND(Tab, Tab);
|
BIND(Tab, Tab);
|
||||||
BIND(Escape, Escape);
|
BIND(Escape, Escape);
|
||||||
BIND(Hyphen, Hyphen);
|
BIND(Hyphen, Hyphen);
|
||||||
BIND(Equals, Tilde);
|
BIND(Equals, Caret);
|
||||||
BIND(Backspace, Erase);
|
BIND(Backspace, Erase);
|
||||||
BIND(Delete, Delete);
|
BIND(Delete, Delete);
|
||||||
BIND(Semicolon, Semicolon);
|
BIND(Semicolon, Semicolon);
|
||||||
@@ -72,3 +72,80 @@ uint16_t KeyboardMapper::mapped_key_for_key(Inputs::Keyboard::Key key) const {
|
|||||||
|
|
||||||
return MachineTypes::MappedKeyboardMachine::KeyNotMapped;
|
return MachineTypes::MappedKeyboardMachine::KeyNotMapped;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const uint16_t *CharacterMapper::sequence_for_character(char character) const {
|
||||||
|
#define KEYS(x) {uint16_t(x), MachineTypes::MappedKeyboardMachine::KeyEndSequence}
|
||||||
|
#define SHIFT(x) {uint16_t(Key::LeftShift), uint16_t(x), MachineTypes::MappedKeyboardMachine::KeyEndSequence}
|
||||||
|
#define _ {MachineTypes::MappedKeyboardMachine::KeyNotMapped}
|
||||||
|
static KeySequence key_sequences[] = {
|
||||||
|
/* NUL */ _, /* SOH */ _,
|
||||||
|
/* STX */ _, /* ETX */ _,
|
||||||
|
/* EOT */ _, /* ENQ */ _,
|
||||||
|
/* ACK */ _, /* BEL */ _,
|
||||||
|
/* BS */ KEYS(Key::Erase), /* HT */ KEYS(Key::Tab),
|
||||||
|
/* LF */ KEYS(Key::Enter), /* VT */ _,
|
||||||
|
/* FF */ _, /* CR */ KEYS(Key::Enter),
|
||||||
|
/* SO */ _, /* SI */ _,
|
||||||
|
/* DLE */ _, /* DC1 */ _,
|
||||||
|
/* DC2 */ _, /* DC3 */ _,
|
||||||
|
/* DC4 */ _, /* NAK */ _,
|
||||||
|
/* SYN */ _, /* ETB */ _,
|
||||||
|
/* CAN */ _, /* EM */ _,
|
||||||
|
/* SUB */ _, /* ESC */ KEYS(Key::Escape),
|
||||||
|
/* FS */ _, /* GS */ _,
|
||||||
|
/* RS */ _, /* US */ _,
|
||||||
|
/* space */ KEYS(Key::Space), /* ! */ SHIFT(Key::k1),
|
||||||
|
/* " */ SHIFT(Key::k2), /* # */ _,
|
||||||
|
/* $ */ SHIFT(Key::k4), /* % */ SHIFT(Key::k5),
|
||||||
|
/* & */ SHIFT(Key::k6), /* ' */ SHIFT(Key::k7),
|
||||||
|
/* ( */ SHIFT(Key::k8), /* ) */ SHIFT(Key::k9),
|
||||||
|
/* * */ SHIFT(Key::Colon), /* + */ SHIFT(Key::Semicolon),
|
||||||
|
/* , */ KEYS(Key::Comma), /* - */ KEYS(Key::Hyphen),
|
||||||
|
/* . */ KEYS(Key::FullStop), /* / */ KEYS(Key::ForwardSlash),
|
||||||
|
/* 0 */ KEYS(Key::k0), /* 1 */ KEYS(Key::k1),
|
||||||
|
/* 2 */ KEYS(Key::k2), /* 3 */ KEYS(Key::k3),
|
||||||
|
/* 4 */ KEYS(Key::k4), /* 5 */ KEYS(Key::k5),
|
||||||
|
/* 6 */ KEYS(Key::k6), /* 7 */ KEYS(Key::k7),
|
||||||
|
/* 8 */ KEYS(Key::k8), /* 9 */ KEYS(Key::k9),
|
||||||
|
/* : */ KEYS(Key::Colon), /* ; */ KEYS(Key::Semicolon),
|
||||||
|
/* < */ SHIFT(Key::Comma), /* = */ SHIFT(Key::Hyphen),
|
||||||
|
/* > */ SHIFT(Key::FullStop), /* ? */ SHIFT(Key::ForwardSlash),
|
||||||
|
/* @ */ KEYS(Key::At), /* A */ SHIFT(Key::A),
|
||||||
|
/* B */ SHIFT(Key::B), /* C */ SHIFT(Key::C),
|
||||||
|
/* D */ SHIFT(Key::D), /* E */ SHIFT(Key::E),
|
||||||
|
/* F */ SHIFT(Key::F), /* G */ SHIFT(Key::G),
|
||||||
|
/* H */ SHIFT(Key::H), /* I */ SHIFT(Key::I),
|
||||||
|
/* J */ SHIFT(Key::J), /* K */ SHIFT(Key::K),
|
||||||
|
/* L */ SHIFT(Key::L), /* M */ SHIFT(Key::M),
|
||||||
|
/* N */ SHIFT(Key::N), /* O */ SHIFT(Key::O),
|
||||||
|
/* P */ SHIFT(Key::P), /* Q */ SHIFT(Key::Q),
|
||||||
|
/* R */ SHIFT(Key::R), /* S */ SHIFT(Key::S),
|
||||||
|
/* T */ SHIFT(Key::T), /* U */ SHIFT(Key::U),
|
||||||
|
/* V */ SHIFT(Key::V), /* W */ SHIFT(Key::W),
|
||||||
|
/* X */ SHIFT(Key::X), /* Y */ SHIFT(Key::Y),
|
||||||
|
/* Z */ SHIFT(Key::Z), /* [ */ KEYS(Key::OpenSquareBracket),
|
||||||
|
/* \ */ KEYS(Key::Backslash), /* ] */ KEYS(Key::CloseSquareBracket),
|
||||||
|
/* ^ */ SHIFT(Key::Caret), /* _ */ SHIFT(Key::k0),
|
||||||
|
/* ` */ SHIFT(Key::At), /* a */ KEYS(Key::A),
|
||||||
|
/* b */ KEYS(Key::B), /* c */ KEYS(Key::C),
|
||||||
|
/* d */ KEYS(Key::D), /* e */ KEYS(Key::E),
|
||||||
|
/* f */ KEYS(Key::F), /* g */ KEYS(Key::G),
|
||||||
|
/* h */ KEYS(Key::H), /* i */ KEYS(Key::I),
|
||||||
|
/* j */ KEYS(Key::J), /* k */ KEYS(Key::K),
|
||||||
|
/* l */ KEYS(Key::L), /* m */ KEYS(Key::M),
|
||||||
|
/* n */ KEYS(Key::N), /* o */ KEYS(Key::O),
|
||||||
|
/* p */ KEYS(Key::P), /* q */ KEYS(Key::Q),
|
||||||
|
/* r */ KEYS(Key::R), /* s */ KEYS(Key::S),
|
||||||
|
/* t */ KEYS(Key::T), /* u */ KEYS(Key::U),
|
||||||
|
/* v */ KEYS(Key::V), /* w */ KEYS(Key::W),
|
||||||
|
/* x */ KEYS(Key::X), /* y */ KEYS(Key::Y),
|
||||||
|
/* z */ KEYS(Key::Z), /* { */ SHIFT(Key::OpenSquareBracket),
|
||||||
|
/* | */ SHIFT(Key::Backslash), /* } */ SHIFT(Key::CloseSquareBracket),
|
||||||
|
/* ~ */ SHIFT(Key::Caret)
|
||||||
|
};
|
||||||
|
#undef _
|
||||||
|
#undef SHIFT
|
||||||
|
#undef KEYS
|
||||||
|
|
||||||
|
return table_lookup_sequence_for_character(key_sequences, character);
|
||||||
|
}
|
||||||
|
@@ -10,6 +10,7 @@
|
|||||||
#define Machines_Enterprise_Keyboard_hpp
|
#define Machines_Enterprise_Keyboard_hpp
|
||||||
|
|
||||||
#include "../KeyboardMachine.hpp"
|
#include "../KeyboardMachine.hpp"
|
||||||
|
#include "../Utility/Typer.hpp"
|
||||||
|
|
||||||
namespace Enterprise {
|
namespace Enterprise {
|
||||||
|
|
||||||
@@ -32,7 +33,7 @@ enum class Key: uint16_t {
|
|||||||
F5 = 0x0400 | 0x10, F7 = 0x0400 | 0x20, F2 = 0x0400 | 0x40, F1 = 0x0400 | 0x80,
|
F5 = 0x0400 | 0x10, F7 = 0x0400 | 0x20, F2 = 0x0400 | 0x40, F1 = 0x0400 | 0x80,
|
||||||
|
|
||||||
k8 = 0x0500 | 0x01, k9 = 0x0500 | 0x04, Hyphen = 0x0500 | 0x08,
|
k8 = 0x0500 | 0x01, k9 = 0x0500 | 0x04, Hyphen = 0x0500 | 0x08,
|
||||||
k0 = 0x0500 | 0x10, Tilde = 0x0500 | 0x20, Erase = 0x0500 | 0x40,
|
k0 = 0x0500 | 0x10, Caret = 0x0500 | 0x20, Erase = 0x0500 | 0x40,
|
||||||
|
|
||||||
J = 0x0600 | 0x01, K = 0x0600 | 0x04, Semicolon = 0x0600 | 0x08,
|
J = 0x0600 | 0x01, K = 0x0600 | 0x04, Semicolon = 0x0600 | 0x08,
|
||||||
L = 0x0600 | 0x10, Colon = 0x0600 | 0x20, CloseSquareBracket = 0x0600 | 0x40,
|
L = 0x0600 | 0x10, Colon = 0x0600 | 0x20, CloseSquareBracket = 0x0600 | 0x40,
|
||||||
@@ -56,6 +57,10 @@ struct KeyboardMapper: public MachineTypes::MappedKeyboardMachine::KeyboardMappe
|
|||||||
uint16_t mapped_key_for_key(Inputs::Keyboard::Key key) const final;
|
uint16_t mapped_key_for_key(Inputs::Keyboard::Key key) const final;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct CharacterMapper: public ::Utility::CharacterMapper {
|
||||||
|
const uint16_t *sequence_for_character(char character) const override;
|
||||||
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif /* Keyboard_hpp */
|
#endif /* Keyboard_hpp */
|
||||||
|
Reference in New Issue
Block a user