1
0
mirror of https://github.com/TomHarte/CLK.git synced 2024-07-04 18:29:40 +00:00

Adds Joystick key code mode, ensures events aren't posted in interrogation mode.

This should fix Turrican due to the latter change; I'm not aware of software that uses the former.
This commit is contained in:
Thomas Harte 2020-01-04 09:45:59 -05:00
parent 56ebd08af0
commit 19ddfae6d6
2 changed files with 80 additions and 19 deletions

View File

@ -100,13 +100,46 @@ void IntelligentKeyboard::run_for(HalfCycles duration) {
// machine advertises as joystick 1 is mapped to the Atari ST's joystick 2, so as to
// maintain both the normal emulation expections that the first joystick is the primary
// one and the Atari ST's convention that the main joystick is in port 2.
for(size_t c = 0; c < 2; ++c) {
const auto joystick = static_cast<Joystick *>(joysticks_[c ^ 1].get());
if(joystick->has_event()) {
output_bytes({
uint8_t(0xfe | c),
joystick->get_state()
});
if(joystick_mode_ == JoystickMode::Event || joystick_mode_ == JoystickMode::KeyCode) {
for(size_t c = 0; c < 2; ++c) {
const auto joystick = static_cast<Joystick *>(joysticks_[c ^ 1].get());
if(joystick->has_event()) {
if(joystick_mode_ == JoystickMode::Event) {
// Event mode: forward a joystick event message.
output_bytes({
uint8_t(0xfe | c),
joystick->get_state()
});
} else {
// Key code mode: decompose the joystick event into
// instantaneous key events.
const auto event_mask = joystick->event_mask();
const auto new_state = joystick->get_state();
const auto new_presses = (event_mask ^ new_state) & new_state;
// Send cursor keys for the movement.
const Key keys[] = {Key::Up, Key::Down, Key::Left, Key::Right};
for(int key = 0; key < 4; ++key) {
if(new_presses & (1 << key)) {
output_bytes({
uint8_t(keys[key]),
uint8_t(0x80 | uint8_t(keys[key]))
});
}
}
// Check also for fire, but the key to send depends
// on the joystick.
if(new_presses & 0x80) {
const Key fire_buttons[] = {Key::Joystick1Button, Key::Joystick2Button};
output_bytes({
uint8_t(fire_buttons[c]),
uint8_t(0x80 | uint8_t(fire_buttons[c]))
});
}
}
}
}
}
@ -425,21 +458,45 @@ void IntelligentKeyboard::disable_joysticks() {
void IntelligentKeyboard::set_joystick_event_mode() {
joystick_mode_ = JoystickMode::Event;
clear_joystick_events();
}
void IntelligentKeyboard::set_joystick_interrogation_mode() {
joystick_mode_ = JoystickMode::Interrogation;
}
void IntelligentKeyboard::interrogate_joysticks() {
void IntelligentKeyboard::set_joystick_keycode_mode(VelocityThreshold horizontal, VelocityThreshold vertical) {
joystick_mode_ = JoystickMode::KeyCode;
clear_joystick_events();
}
void IntelligentKeyboard::clear_joystick_events() {
const auto joystick1 = static_cast<Joystick *>(joysticks_[0].get());
const auto joystick2 = static_cast<Joystick *>(joysticks_[1].get());
joystick1->get_state();
joystick2->get_state();
}
output_bytes({
0xfd,
joystick2->get_state(),
joystick1->get_state()
});
void IntelligentKeyboard::interrogate_joysticks() {
if(joystick_mode_ != JoystickMode::Interrogation) {
// Joystick::get_state() implicitly clears Joystick::has_event,
// so don't permit interrogation if the user isn't in interrogation
// mode because it might cause dropped events.
output_bytes({
0xfd,
0x00,
0x00
});
} else {
const auto joystick1 = static_cast<Joystick *>(joysticks_[0].get());
const auto joystick2 = static_cast<Joystick *>(joysticks_[1].get());
output_bytes({
0xfd,
joystick2->get_state(),
joystick1->get_state()
});
}
}
void IntelligentKeyboard::set_joystick_monitoring_mode(uint8_t rate) {
@ -449,7 +506,3 @@ void IntelligentKeyboard::set_joystick_monitoring_mode(uint8_t rate) {
void IntelligentKeyboard::set_joystick_fire_button_monitoring_mode() {
LOG("Unimplemented: joystick fire button monitoring mode");
}
void IntelligentKeyboard::set_joystick_keycode_mode(VelocityThreshold horizontal, VelocityThreshold vertical) {
LOG("Unimplemented: joystick keycode mode");
}

View File

@ -40,7 +40,9 @@ enum class Key: uint16_t {
Insert = 0x52, Delete,
ISO = 0x60, Undo, Help, KeypadOpenBracket, KeypadCloseBracket, KeypadDivide, KeypadMultiply,
Keypad7, Keypad8, Keypad9, Keypad4, Keypad5, Keypad6, Keypad1, Keypad2, Keypad3, Keypad0, KeypadDecimalPoint,
KeypadEnter
KeypadEnter,
Joystick1Button = 0x74, // These keycodes are used only in joystick keycode mode.
Joystick2Button = 0x75,
};
static_assert(uint16_t(Key::RightShift) == 0x36, "RightShift should have key code 0x36; check intermediate entries");
static_assert(uint16_t(Key::F10) == 0x44, "F10 should have key code 0x44; check intermediate entries");
@ -143,8 +145,10 @@ class IntelligentKeyboard:
void set_joystick_keycode_mode(VelocityThreshold horizontal, VelocityThreshold vertical);
void interrogate_joysticks();
void clear_joystick_events();
enum class JoystickMode {
Disabled, Event, Interrogation
Disabled, Event, Interrogation, KeyCode
} joystick_mode_ = JoystickMode::Event;
class Joystick: public Inputs::ConcreteJoystick {
@ -181,6 +185,10 @@ class IntelligentKeyboard:
return returned_state_ != state_;
}
uint8_t event_mask() {
return returned_state_ ^ state_;
}
private:
uint8_t state_ = 0x00;
uint8_t returned_state_ = 0x00;