1
0
mirror of https://github.com/TomHarte/CLK.git synced 2025-01-17 02:30:54 +00:00

Merge pull request #1235 from TomHarte/MissingKeys

Add missing key mappings, queue, cursor
This commit is contained in:
Thomas Harte 2023-12-03 18:06:53 -05:00 committed by GitHub
commit 881f9bc824
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 133 additions and 53 deletions

View File

@ -112,7 +112,7 @@ template <class T> class CRTC6845 {
void run_for(Cycles cycles) {
auto cyles_remaining = cycles.as_integral();
while(cyles_remaining--) {
// check for end of visible characters
// Check for end of visible characters.
if(character_counter_ == registers_[1]) {
// TODO: consider skew in character_is_visible_. Or maybe defer until perform_bus_cycle?
character_is_visible_ = false;
@ -122,23 +122,26 @@ template <class T> class CRTC6845 {
perform_bus_cycle_phase1();
bus_state_.refresh_address = (bus_state_.refresh_address + 1) & 0x3fff;
// check for end-of-line
bus_state_.cursor = is_cursor_line_ &&
bus_state_.refresh_address == ((registers_[15] | (registers_[14] << 8))&0x3fff);
// Check for end-of-line.
if(character_counter_ == registers_[0]) {
character_counter_ = 0;
do_end_of_line();
character_is_visible_ = true;
} else {
// increment counter
// Increment counter.
character_counter_++;
}
// check for start of horizontal sync
// Check for start of horizontal sync.
if(character_counter_ == registers_[2]) {
hsync_counter_ = 0;
bus_state_.hsync = true;
}
// check for end of horizontal sync; note that a sync time of zero will result in an immediate
// Check for end of horizontal sync; note that a sync time of zero will result in an immediate
// cancellation of the plan to perform sync if this is an HD6845S or UM6845R; otherwise zero
// will end up counting as 16 as it won't be checked until after overflow.
if(bus_state_.hsync) {
@ -176,10 +179,14 @@ template <class T> class CRTC6845 {
}
inline void do_end_of_line() {
// check for end of vertical sync
// Check for cursor disable.
// TODO: this is handled differently on the EGA, should I ever implement that.
is_cursor_line_ &= bus_state_.row_address != (registers_[11] & 0x1f);
// Check for end of vertical sync.
if(bus_state_.vsync) {
vsync_counter_ = (vsync_counter_ + 1) & 15;
// on the UM6845R and AMS40226, honour the programmed vertical sync time; on the other CRTCs
// On the UM6845R and AMS40226, honour the programmed vertical sync time; on the other CRTCs
// always use a vertical sync count of 16.
switch(personality_) {
case HD6845S:
@ -199,12 +206,12 @@ template <class T> class CRTC6845 {
do_end_of_frame();
}
} else {
// advance vertical counter
// Advance vertical counter.
if(bus_state_.row_address == registers_[9]) {
bus_state_.row_address = 0;
line_address_ = end_of_line_address_;
// check for entry into the overflow area
// Check for entry into the overflow area.
if(line_counter_ == registers_[4]) {
if(registers_[5]) {
line_counter_ = 0;
@ -215,13 +222,13 @@ template <class T> class CRTC6845 {
} else {
line_counter_ = (line_counter_ + 1) & 0x7f;
// check for start of vertical sync
// Check for start of vertical sync.
if(line_counter_ == registers_[7]) {
bus_state_.vsync = true;
vsync_counter_ = 0;
}
// check for end of visible lines
// Check for end of visible lines.
if(line_counter_ == registers_[6]) {
line_is_visible_ = false;
}
@ -234,6 +241,9 @@ template <class T> class CRTC6845 {
bus_state_.refresh_address = line_address_;
character_counter_ = 0;
character_is_visible_ = (registers_[1] != 0);
// Check for cursor enable.
is_cursor_line_ |= bus_state_.row_address == (registers_[10] & 0x1f);
}
inline void do_end_of_frame() {
@ -266,6 +276,8 @@ template <class T> class CRTC6845 {
int display_skew_mask_ = 1;
unsigned int character_is_visible_shifter_ = 0;
bool is_cursor_line_ = false;
};
}

View File

@ -84,18 +84,54 @@ class KeyboardMapper: public MachineTypes::MappedKeyboardMachine::KeyboardMapper
case k::ForwardSlash: return 53;
case k::RightShift: return 54;
case k::KeypadAsterisk: return 55;
case k::LeftOption:
case k::RightOption: return 56;
case k::Space: return 57;
case k::CapsLock: return 58;
case k::F1: return 59;
case k::F2: return 60;
case k::F3: return 61;
case k::F4: return 62;
case k::F5: return 63;
case k::F6: return 64;
case k::F7: return 65;
case k::F8: return 66;
case k::F9: return 67;
case k::F10: return 68;
case k::NumLock: return 69;
case k::ScrollLock: return 70;
case k::Keypad7: return 71;
case k::Up:
case k::Keypad8: return 72;
case k::Keypad9: return 73;
case k::KeypadMinus: return 74;
case k::Left:
case k::Keypad4: return 75;
case k::Keypad5: return 76;
case k::Right:
case k::Keypad6: return 77;
case k::KeypadPlus: return 78;
case k::Keypad1: return 79;
case k::Down:
case k::Keypad2: return 80;
case k::Keypad3: return 81;
case k::Keypad0: return 82;
case k::KeypadDecimalPoint: return 83;
/* TODO: SysReq = 84 */
case k::F11: return 87;
case k::F12: return 88;
default: return MachineTypes::MappedKeyboardMachine::KeyNotMapped;
}
// TODO: extended functions, including all F keys and cursors.
}
};

View File

@ -410,15 +410,22 @@ class KeyboardController {
}
reset_delay_ -= cycles.as<int>();
if(reset_delay_ <= 0) {
input_.clear();
post(0xaa);
}
}
uint8_t read() {
pic_.apply_edge<1>(false);
if(input_.empty()) {
return 0;
}
const uint8_t key = input_;
input_ = 0;
const uint8_t key = input_.front();
input_.erase(input_.begin());
if(!input_.empty()) {
pic_.apply_edge<1>(true);
}
return key;
}
@ -426,7 +433,7 @@ class KeyboardController {
if(mode_ == Mode::NoIRQsIgnoreInput) {
return;
}
input_ = value;
input_.push_back(value);
pic_.apply_edge<1>(true);
}
@ -438,7 +445,7 @@ class KeyboardController {
Reset = 0b00,
} mode_;
uint8_t input_ = 0;
std::vector<uint8_t> input_;
PIC &pic_;
int reset_delay_ = 0;
@ -542,41 +549,50 @@ class MDA {
}
}
// TODO: cursor.
if(pixels) {
const uint8_t attributes = ram[((state.refresh_address << 1) + 1) & 0xfff];
const uint8_t glyph = ram[((state.refresh_address << 1) + 0) & 0xfff];
uint8_t row = font[(glyph * 14) + state.row_address];
static constexpr uint8_t high_intensity = 0x0d;
static constexpr uint8_t low_intensity = 0x09;
static constexpr uint8_t off = 0x00;
const uint8_t intensity = (attributes & 0x08) ? 0x0d : 0x09;
uint8_t blank = 0;
// Handle irregular attributes.
// Cf. http://www.seasip.info/VintagePC/mda.html#memmap
switch(attributes) {
case 0x00: case 0x08: case 0x80: case 0x88:
row = 0;
break;
case 0x70: case 0x78: case 0xf0: case 0xf8:
row ^= 0xff;
blank = intensity;
break;
}
if(((attributes & 7) == 1) && state.row_address == 13) {
// Draw as underline.
std::fill(pixel_pointer, pixel_pointer + 9, intensity);
if(state.cursor) {
pixel_pointer[0] = pixel_pointer[1] = pixel_pointer[2] = pixel_pointer[3] =
pixel_pointer[4] = pixel_pointer[5] = pixel_pointer[6] = pixel_pointer[7] =
pixel_pointer[8] = low_intensity;
} else {
// Draw according to ROM contents, possibly duplicating final column.
pixel_pointer[0] = (row & 0x80) ? intensity : 0;
pixel_pointer[1] = (row & 0x40) ? intensity : 0;
pixel_pointer[2] = (row & 0x20) ? intensity : 0;
pixel_pointer[3] = (row & 0x10) ? intensity : 0;
pixel_pointer[4] = (row & 0x08) ? intensity : 0;
pixel_pointer[5] = (row & 0x04) ? intensity : 0;
pixel_pointer[6] = (row & 0x02) ? intensity : 0;
pixel_pointer[7] = (row & 0x01) ? intensity : 0;
pixel_pointer[8] = (glyph >= 0xc0 && glyph < 0xe0) ? pixel_pointer[7] : blank;
const uint8_t attributes = ram[((state.refresh_address << 1) + 1) & 0xfff];
const uint8_t glyph = ram[((state.refresh_address << 1) + 0) & 0xfff];
uint8_t row = font[(glyph * 14) + state.row_address];
const uint8_t intensity = (attributes & 0x08) ? high_intensity : low_intensity;
uint8_t blank = off;
// Handle irregular attributes.
// Cf. http://www.seasip.info/VintagePC/mda.html#memmap
switch(attributes) {
case 0x00: case 0x08: case 0x80: case 0x88:
row = 0;
break;
case 0x70: case 0x78: case 0xf0: case 0xf8:
row ^= 0xff;
blank = intensity;
break;
}
if(((attributes & 7) == 1) && state.row_address == 13) {
// Draw as underline.
std::fill(pixel_pointer, pixel_pointer + 9, intensity);
} else {
// Draw according to ROM contents, possibly duplicating final column.
pixel_pointer[0] = (row & 0x80) ? intensity : off;
pixel_pointer[1] = (row & 0x40) ? intensity : off;
pixel_pointer[2] = (row & 0x20) ? intensity : off;
pixel_pointer[3] = (row & 0x10) ? intensity : off;
pixel_pointer[4] = (row & 0x08) ? intensity : off;
pixel_pointer[5] = (row & 0x04) ? intensity : off;
pixel_pointer[6] = (row & 0x02) ? intensity : off;
pixel_pointer[7] = (row & 0x01) ? intensity : off;
pixel_pointer[8] = (glyph >= 0xc0 && glyph < 0xe0) ? pixel_pointer[7] : blank;
}
}
pixel_pointer += 9;
}

View File

@ -359,12 +359,28 @@ class MachineDocument:
/// Synthesies appropriate key up and key down events upon any change in modifiers.
func flagsChanged(_ newModifiers: NSEvent) {
if let machine = self.machine {
machine.setKey(VK_Shift, characters: nil, isPressed: newModifiers.modifierFlags.contains(.shift))
machine.setKey(VK_Control, characters: nil, isPressed: newModifiers.modifierFlags.contains(.control))
machine.setKey(VK_Command, characters: nil, isPressed: newModifiers.modifierFlags.contains(.command))
machine.setKey(VK_Option, characters: nil, isPressed: newModifiers.modifierFlags.contains(.option))
if newModifiers.modifierFlags.contains(.shift) != shiftIsDown {
shiftIsDown = newModifiers.modifierFlags.contains(.shift)
machine.setKey(VK_Shift, characters: nil, isPressed: shiftIsDown)
}
if newModifiers.modifierFlags.contains(.control) != controlIsDown {
controlIsDown = newModifiers.modifierFlags.contains(.control)
machine.setKey(VK_Control, characters: nil, isPressed: controlIsDown)
}
if newModifiers.modifierFlags.contains(.command) != commandIsDown {
commandIsDown = newModifiers.modifierFlags.contains(.command)
machine.setKey(VK_Command, characters: nil, isPressed: commandIsDown)
}
if newModifiers.modifierFlags.contains(.option) != optionIsDown {
optionIsDown = newModifiers.modifierFlags.contains(.option)
machine.setKey(VK_Option, characters: nil, isPressed: optionIsDown)
}
}
}
private var shiftIsDown = false
private var controlIsDown = false
private var commandIsDown = false
private var optionIsDown = false
/// Forwards mouse movement events to the mouse.
func mouseMoved(_ event: NSEvent) {