mirror of
https://github.com/TomHarte/CLK.git
synced 2025-01-26 15:32:04 +00:00
Makes attempt at keyboard mapping.
This commit is contained in:
parent
eccf5ca043
commit
99c21925f4
@ -13,46 +13,212 @@ using namespace Apple::ADB;
|
||||
Keyboard::Keyboard(Bus &bus) : ReactiveDevice(bus, 2) {}
|
||||
|
||||
void Keyboard::perform_command(const Command &command) {
|
||||
if(command.type == Command::Type::Talk) {
|
||||
switch(command.reg) {
|
||||
case 0:
|
||||
// Post up to two key events, or nothing if there are
|
||||
// no events pending.
|
||||
//
|
||||
// Events are:
|
||||
//
|
||||
// b7 = 0 for down 1, for up;
|
||||
// b6–b0: key code (mostly 7-bit ASCII)
|
||||
// post_response({0x00, 0x00});
|
||||
break;
|
||||
switch(command.type) {
|
||||
case Command::Type::Reset:
|
||||
modifiers_ = 0xffff;
|
||||
case Command::Type::Flush: {
|
||||
std::lock_guard lock_guard(keys_mutex_);
|
||||
pending_events_.clear();
|
||||
} break;
|
||||
|
||||
case 2:
|
||||
/*
|
||||
In all cases below: 0 = pressed/on; 1 = released/off.
|
||||
case Command::Type::Talk:
|
||||
switch(command.reg) {
|
||||
case 0: {
|
||||
// Post up to two key events, or nothing if there are
|
||||
// no events pending.
|
||||
std::lock_guard lock_guard(keys_mutex_);
|
||||
|
||||
b15: None (reserved)
|
||||
b14: Delete
|
||||
b13: Caps lock
|
||||
b12: Reset
|
||||
b11: Control
|
||||
b10: Shift
|
||||
b9: Option
|
||||
b8: Command
|
||||
if(!pending_events_.empty()) {
|
||||
if(pending_events_.size() > 1) {
|
||||
post_response({pending_events_[0], pending_events_[1]});
|
||||
pending_events_.erase(pending_events_.begin(), pending_events_.begin()+2);
|
||||
} else {
|
||||
// Two bytes are required; provide a key up of the fictional
|
||||
// key zero as the second.
|
||||
// That's arbitrary; verify with real machines.
|
||||
post_response({pending_events_[0], 0x80});
|
||||
pending_events_.clear();
|
||||
}
|
||||
}
|
||||
} break;
|
||||
|
||||
-- From here onwards, available only on the extended keyboard.
|
||||
case 2: {
|
||||
std::lock_guard lock_guard(keys_mutex_);
|
||||
post_response({uint8_t(modifiers_ >> 8), uint8_t(modifiers_)});
|
||||
} break;
|
||||
|
||||
b7: Num lock/clear
|
||||
b6: Scroll lock
|
||||
b5–3: None (reserved)
|
||||
b2: Scroll Lock LED
|
||||
b1: Caps Lock LED
|
||||
b0: Num Lock LED
|
||||
*/
|
||||
post_response({0xff, 0xff});
|
||||
break;
|
||||
default: break;
|
||||
}
|
||||
break;
|
||||
|
||||
default: break;
|
||||
}
|
||||
return;
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
|
||||
bool Keyboard::set_key_pressed(Key key, bool is_pressed) {
|
||||
// ADB keyboard events: low 7 bits are a key code; bit 7 is either 0 for pressed or 1 for released.
|
||||
std::lock_guard lock_guard(keys_mutex_);
|
||||
pending_events_.push_back(uint8_t(key) | (is_pressed ? 0x00 : 0x80));
|
||||
pressed_keys_[size_t(key)] = is_pressed;
|
||||
|
||||
// Track modifier state also.
|
||||
|
||||
/*
|
||||
In all cases below: 0 = pressed/on; 1 = released/off.
|
||||
|
||||
b15: None (reserved)
|
||||
b14: Delete
|
||||
b13: Caps lock
|
||||
b12: Reset
|
||||
b11: Control
|
||||
b10: Shift
|
||||
b9: Option
|
||||
b8: Command
|
||||
|
||||
-- From here onwards, available only on the extended keyboard.
|
||||
|
||||
b7: Num lock/clear
|
||||
b6: Scroll lock
|
||||
b5–3: None (reserved)
|
||||
b2: Scroll Lock LED
|
||||
b1: Caps Lock LED
|
||||
b0: Num Lock LED
|
||||
*/
|
||||
|
||||
#define SetModifierBit(x) modifiers_ = (modifiers_ & ~x) | (is_pressed ? 0 : x);
|
||||
#define ToggleModifierBit(x) if(is_pressed) modifiers_ ^= x;
|
||||
switch(key) {
|
||||
default: break;
|
||||
case Key::Delete: SetModifierBit(0x4000); break;
|
||||
case Key::CapsLock: ToggleModifierBit(0x2000); break;
|
||||
case Key::Power: SetModifierBit(0x1000); break;
|
||||
|
||||
case Key::LeftControl:
|
||||
case Key::RightControl:
|
||||
SetModifierBit(0x0800);
|
||||
break;
|
||||
|
||||
case Key::LeftShift:
|
||||
case Key::RightShift:
|
||||
SetModifierBit(0x0400);
|
||||
break;
|
||||
|
||||
case Key::LeftOption:
|
||||
case Key::RightOption:
|
||||
SetModifierBit(0x0200);
|
||||
break;
|
||||
|
||||
case Key::Command:
|
||||
SetModifierBit(0x0100);
|
||||
break;
|
||||
|
||||
case Key::KeypadClear: ToggleModifierBit(0x0080); break;
|
||||
case Key::Help: ToggleModifierBit(0x0040); break;
|
||||
}
|
||||
#undef SetModifierBit
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void Keyboard::clear_all_keys() {
|
||||
// For all keys currently marked as down, enqueue key-up actions.
|
||||
std::lock_guard lock_guard(keys_mutex_);
|
||||
for(size_t key = 0; key < pressed_keys_.size(); key++) {
|
||||
if(pressed_keys_[key]) {
|
||||
pending_events_.push_back(0x80 | uint8_t(key));
|
||||
pressed_keys_[key] = false;
|
||||
}
|
||||
}
|
||||
|
||||
// Mark all modifiers as released.
|
||||
modifiers_ |= 0xfff8;
|
||||
}
|
||||
|
||||
// MARK: - KeyboardMapper
|
||||
|
||||
uint16_t KeyboardMapper::mapped_key_for_key(Inputs::Keyboard::Key key) const {
|
||||
using Key = Inputs::Keyboard::Key;
|
||||
using ADBKey = Apple::ADB::Key;
|
||||
switch(key) {
|
||||
default: return MachineTypes::MappedKeyboardMachine::KeyNotMapped;
|
||||
|
||||
#define Bind(x, y) case Key::x: return uint16_t(ADBKey::y)
|
||||
#define BindDirect(x) Bind(x, x)
|
||||
|
||||
BindDirect(BackTick);
|
||||
BindDirect(k1); BindDirect(k2); BindDirect(k3); BindDirect(k4); BindDirect(k5);
|
||||
BindDirect(k6); BindDirect(k7); BindDirect(k8); BindDirect(k9); BindDirect(k0);
|
||||
|
||||
BindDirect(Help);
|
||||
BindDirect(Home);
|
||||
BindDirect(PageUp);
|
||||
BindDirect(Delete);
|
||||
BindDirect(End);
|
||||
BindDirect(PageDown);
|
||||
|
||||
BindDirect(Escape);
|
||||
BindDirect(Hyphen);
|
||||
BindDirect(Equals);
|
||||
BindDirect(Backspace);
|
||||
BindDirect(Tab);
|
||||
|
||||
BindDirect(F1); BindDirect(F2); BindDirect(F3); BindDirect(F4);
|
||||
BindDirect(F5); BindDirect(F6); BindDirect(F7); BindDirect(F8);
|
||||
BindDirect(F9); BindDirect(F10); BindDirect(F11); BindDirect(F12);
|
||||
|
||||
BindDirect(Q); BindDirect(W); BindDirect(E); BindDirect(R);
|
||||
BindDirect(T); BindDirect(Y); BindDirect(U); BindDirect(I);
|
||||
BindDirect(O); BindDirect(P); BindDirect(A); BindDirect(S);
|
||||
BindDirect(D); BindDirect(F); BindDirect(G); BindDirect(H);
|
||||
BindDirect(J); BindDirect(K); BindDirect(L); BindDirect(Z);
|
||||
BindDirect(X); BindDirect(C); BindDirect(V); BindDirect(B);
|
||||
BindDirect(N); BindDirect(M);
|
||||
|
||||
BindDirect(OpenSquareBracket);
|
||||
BindDirect(CloseSquareBracket);
|
||||
BindDirect(Semicolon);
|
||||
BindDirect(Quote);
|
||||
BindDirect(Comma);
|
||||
BindDirect(FullStop);
|
||||
BindDirect(ForwardSlash);
|
||||
|
||||
BindDirect(CapsLock);
|
||||
BindDirect(LeftShift); BindDirect(RightShift);
|
||||
BindDirect(LeftControl); BindDirect(RightControl);
|
||||
BindDirect(LeftOption); BindDirect(RightOption);
|
||||
Bind(LeftMeta, Command); Bind(RightMeta, Command);
|
||||
|
||||
BindDirect(Space);
|
||||
BindDirect(Backslash);
|
||||
Bind(Enter, Return);
|
||||
|
||||
BindDirect(Left); BindDirect(Right);
|
||||
BindDirect(Up); BindDirect(Down);
|
||||
|
||||
Bind(KeypadDelete, KeypadClear);
|
||||
BindDirect(KeypadEquals);
|
||||
BindDirect(KeypadSlash);
|
||||
BindDirect(KeypadAsterisk);
|
||||
BindDirect(KeypadMinus);
|
||||
BindDirect(KeypadPlus);
|
||||
BindDirect(KeypadEnter);
|
||||
BindDirect(KeypadDecimalPoint);
|
||||
|
||||
BindDirect(Keypad9);
|
||||
BindDirect(Keypad8);
|
||||
BindDirect(Keypad7);
|
||||
BindDirect(Keypad6);
|
||||
BindDirect(Keypad5);
|
||||
BindDirect(Keypad4);
|
||||
BindDirect(Keypad3);
|
||||
BindDirect(Keypad2);
|
||||
BindDirect(Keypad1);
|
||||
BindDirect(Keypad0);
|
||||
|
||||
// Leaving unmapped:
|
||||
// Power, F13, F14, F15
|
||||
|
||||
#undef BindDirect
|
||||
#undef Bind
|
||||
}
|
||||
}
|
||||
|
@ -10,16 +10,112 @@
|
||||
#define Keyboard_hpp
|
||||
|
||||
#include "ReactiveDevice.hpp"
|
||||
#include "../../../Inputs/Keyboard.hpp"
|
||||
#include "../../KeyboardMachine.hpp"
|
||||
|
||||
#include <array>
|
||||
#include <cstdint>
|
||||
#include <mutex>
|
||||
#include <vector>
|
||||
|
||||
namespace Apple {
|
||||
namespace ADB {
|
||||
|
||||
/*!
|
||||
Defines the keycodes that could be passed directly via set_key_pressed; these
|
||||
are based on the Apple Extended Keyboard.
|
||||
*/
|
||||
enum class Key: uint16_t {
|
||||
/*
|
||||
These are transcribed from Page 19-11 of
|
||||
the Macintosh Family Hardware Reference.
|
||||
*/
|
||||
BackTick = 0x32,
|
||||
k1 = 0x12, k2 = 0x13, k3 = 0x14, k4 = 0x15, k5 = 0x17,
|
||||
k6 = 0x16, k7 = 0x1a, k8 = 0x1c, k9 = 0x19, k0 = 0x1d,
|
||||
|
||||
Help = 0x72,
|
||||
Home = 0x73,
|
||||
PageUp = 0x74,
|
||||
Delete = 0x75,
|
||||
End = 0x77,
|
||||
PageDown = 0x79,
|
||||
|
||||
Escape = 0x35,
|
||||
Hyphen = 0x1b,
|
||||
Equals = 0x18,
|
||||
Backspace = 0x33,
|
||||
Tab = 0x30,
|
||||
Power = 0x7f,
|
||||
|
||||
F1 = 0x7a, F2 = 0x78, F3 = 0x63, F4 = 0x76,
|
||||
F5 = 0x60, F6 = 0x61, F7 = 0x62, F8 = 0x64,
|
||||
F9 = 0x65, F10 = 0x6d, F11 = 0x67, F12 = 0x6f,
|
||||
F13 = 0x69, F14 = 0x6b, F15 = 0x71,
|
||||
|
||||
Q = 0x0c, W = 0x0d, E = 0x0e, R = 0x0f, T = 0x11, Y = 0x10, U = 0x20, I = 0x22, O = 0x1f, P = 0x23,
|
||||
A = 0x00, S = 0x01, D = 0x02, F = 0x03, G = 0x05, H = 0x04, J = 0x26, K = 0x28, L = 0x25,
|
||||
Z = 0x06, X = 0x07, C = 0x08, V = 0x09, B = 0x0b, N = 0x2d, M = 0x2e,
|
||||
|
||||
OpenSquareBracket = 0x21,
|
||||
CloseSquareBracket = 0x1e,
|
||||
Semicolon = 0x29,
|
||||
Quote = 0x27,
|
||||
Comma = 0x2b,
|
||||
FullStop = 0x2f,
|
||||
ForwardSlash = 0x2c,
|
||||
|
||||
CapsLock = 0x39,
|
||||
LeftShift = 0x38, RightShift = 0x7b,
|
||||
LeftControl = 0x36, RightControl = 0x7d,
|
||||
LeftOption = 0x3a, RightOption = 0x7c,
|
||||
Command = 0x37,
|
||||
|
||||
Space = 0x31,
|
||||
Backslash = 0x2a,
|
||||
Return = 0x24,
|
||||
|
||||
Left = 0x3b,
|
||||
Right = 0x3c,
|
||||
Up = 0x3e,
|
||||
Down = 0x3d,
|
||||
|
||||
KeypadClear = 0x47,
|
||||
KeypadEquals = 0x51,
|
||||
KeypadSlash = 0x4b,
|
||||
KeypadAsterisk = 0x43,
|
||||
KeypadMinus = 0x4e,
|
||||
KeypadPlus = 0x45,
|
||||
KeypadEnter = 0x4c,
|
||||
KeypadDecimalPoint = 0x41,
|
||||
|
||||
Keypad9 = 0x5c, Keypad8 = 0x5b, Keypad7 = 0x59,
|
||||
Keypad6 = 0x58, Keypad5 = 0x57, Keypad4 = 0x56,
|
||||
Keypad3 = 0x55, Keypad2 = 0x54, Keypad1 = 0x53,
|
||||
Keypad0 = 0x52,
|
||||
};
|
||||
|
||||
class Keyboard: public ReactiveDevice {
|
||||
public:
|
||||
Keyboard(Bus &);
|
||||
|
||||
bool set_key_pressed(Key key, bool is_pressed);
|
||||
void clear_all_keys();
|
||||
|
||||
private:
|
||||
void perform_command(const Command &command) override;
|
||||
|
||||
std::mutex keys_mutex_;
|
||||
std::array<bool, 128> pressed_keys_;
|
||||
std::vector<uint8_t> pending_events_;
|
||||
uint16_t modifiers_ = 0xffff;
|
||||
};
|
||||
|
||||
/*!
|
||||
Provides a mapping from idiomatic PC keys to ADB keys.
|
||||
*/
|
||||
class KeyboardMapper: public MachineTypes::MappedKeyboardMachine::KeyboardMapper {
|
||||
uint16_t mapped_key_for_key(Inputs::Keyboard::Key key) const final;
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -46,6 +46,10 @@ class GLU: public InstructionSet::M50740::PortHandler {
|
||||
|
||||
void set_vertical_blank(bool);
|
||||
|
||||
Apple::ADB::Keyboard &keyboard() {
|
||||
return keyboard_;
|
||||
}
|
||||
|
||||
private:
|
||||
InstructionSet::M50740::Executor executor_;
|
||||
|
||||
|
@ -51,6 +51,7 @@ class ConcreteMachine:
|
||||
public MachineTypes::MediaTarget,
|
||||
public MachineTypes::ScanProducer,
|
||||
public MachineTypes::TimedMachine,
|
||||
public MachineTypes::MappedKeyboardMachine,
|
||||
public CPU::MOS6502Esque::BusHandler<uint32_t> {
|
||||
|
||||
public:
|
||||
@ -909,6 +910,19 @@ class ConcreteMachine:
|
||||
m65816_.set_irq_line(video_.last_valid()->get_interrupt_line() || sound_glu_.get_interrupt_line());
|
||||
}
|
||||
|
||||
// MARK: - Keyboard input.
|
||||
KeyboardMapper *get_keyboard_mapper() final {
|
||||
return &keyboard_mapper_;
|
||||
}
|
||||
|
||||
void set_key_state(uint16_t key, bool is_pressed) final {
|
||||
adb_glu_.last_valid()->keyboard().set_key_pressed(Apple::ADB::Key(key), is_pressed);
|
||||
}
|
||||
|
||||
void clear_all_keys() final {
|
||||
adb_glu_.last_valid()->keyboard().clear_all_keys();
|
||||
}
|
||||
|
||||
private:
|
||||
CPU::WDC65816::Processor<ConcreteMachine, false> m65816_;
|
||||
MemoryMap memory_;
|
||||
@ -965,6 +979,9 @@ class ConcreteMachine:
|
||||
};
|
||||
friend AudioUpdater;
|
||||
|
||||
// MARK: - Keyboard.
|
||||
Apple::ADB::KeyboardMapper keyboard_mapper_;
|
||||
|
||||
// MARK: - Cards.
|
||||
|
||||
// TODO: most of cards.
|
||||
|
Loading…
x
Reference in New Issue
Block a user