mirror of
https://github.com/TomHarte/CLK.git
synced 2025-01-14 13:33:42 +00:00
Adds relative mouse motion input.
This commit is contained in:
parent
14e790746b
commit
cbf25a16dc
@ -9,6 +9,7 @@
|
||||
#include "AtariST.hpp"
|
||||
|
||||
#include "../CRTMachine.hpp"
|
||||
#include "../MouseMachine.hpp"
|
||||
|
||||
//#define LOG_TRACE
|
||||
#include "../../Processors/68000/68000.hpp"
|
||||
@ -43,7 +44,8 @@ class ConcreteMachine:
|
||||
public ClockingHint::Observer,
|
||||
public Motorola::ACIA::ACIA::InterruptDelegate,
|
||||
public Motorola::MFP68901::MFP68901::InterruptDelegate,
|
||||
public DMAController::InterruptDelegate {
|
||||
public DMAController::InterruptDelegate,
|
||||
public MouseMachine::Machine {
|
||||
public:
|
||||
ConcreteMachine(const Target &target, const ROMMachine::ROMFetcher &rom_fetcher) :
|
||||
mc68000_(*this),
|
||||
@ -113,6 +115,11 @@ class ConcreteMachine:
|
||||
}
|
||||
|
||||
void run_for(const Cycles cycles) final {
|
||||
// Give the keyboard an opportunity to consume any events.
|
||||
if(!keyboard_needs_clock_) {
|
||||
ikbd_.run_for(HalfCycles(0));
|
||||
}
|
||||
|
||||
mc68000_.run_for(cycles);
|
||||
}
|
||||
|
||||
@ -476,7 +483,12 @@ class ConcreteMachine:
|
||||
mc68000_.set_interrupt_level(0);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// MARK: - MouseMachine
|
||||
Inputs::Mouse &get_mouse() final {
|
||||
return ikbd_;
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -13,6 +13,10 @@ using namespace Atari::ST;
|
||||
IntelligentKeyboard::IntelligentKeyboard(Serial::Line &input, Serial::Line &output) : output_line_(output) {
|
||||
input.set_read_delegate(this, Storage::Time(2, 15625));
|
||||
output_line_.set_writer_clock_rate(15625);
|
||||
|
||||
mouse_button_state_ = 0;
|
||||
mouse_movement_[0] = 0;
|
||||
mouse_movement_[1] = 0;
|
||||
}
|
||||
|
||||
bool IntelligentKeyboard::serial_line_did_produce_bit(Serial::Line *, int bit) {
|
||||
@ -36,12 +40,34 @@ ClockingHint::Preference IntelligentKeyboard::preferred_clocking() {
|
||||
}
|
||||
|
||||
void IntelligentKeyboard::run_for(HalfCycles duration) {
|
||||
// Take this opportunity to check for mouse and keyboard events,
|
||||
// which will have been received asynchronously.
|
||||
if(mouse_mode_ == MouseMode::Relative) {
|
||||
const int captured_movement[2] = { mouse_movement_[0].load(), mouse_movement_[1].load() };
|
||||
const int captured_button_state = mouse_button_state_;
|
||||
if(
|
||||
(posted_button_state_ != captured_button_state) ||
|
||||
(abs(captured_movement[0]) >= mouse_threshold_[0]) ||
|
||||
(abs(captured_movement[1]) >= mouse_threshold_[1]) ) {
|
||||
mouse_movement_[0] -= captured_movement[0];
|
||||
mouse_movement_[1] -= captured_movement[1];
|
||||
|
||||
post_relative_mouse_event(captured_movement[0], captured_movement[1]);
|
||||
}
|
||||
} else {
|
||||
|
||||
}
|
||||
|
||||
output_line_.advance_writer(duration);
|
||||
}
|
||||
|
||||
void IntelligentKeyboard::output_byte(uint8_t value) {
|
||||
void IntelligentKeyboard::output_bytes(std::initializer_list<uint8_t> values) {
|
||||
// Wrap the value in a start and stop bit, and send it on its way.
|
||||
for(auto value : values) {
|
||||
output_line_.write(2, 10, 0x200 | (value << 1));
|
||||
}
|
||||
|
||||
// TODO: this isn't thread safe! Might need this class to imply a poll?
|
||||
update_clocking_observer();
|
||||
}
|
||||
|
||||
@ -128,7 +154,7 @@ void IntelligentKeyboard::reset() {
|
||||
// Reset should perform a self test, lasting at most 200ms, then post 0xf0.
|
||||
// Following that it should look for any keys that currently seem to be pressed.
|
||||
// Those are considered stuck and a break code is generated for them.
|
||||
output_byte(0xf0);
|
||||
output_bytes({0xf0});
|
||||
}
|
||||
|
||||
void IntelligentKeyboard::resume() {
|
||||
@ -168,13 +194,61 @@ void IntelligentKeyboard::set_mouse_button_actions(uint8_t actions) {
|
||||
}
|
||||
|
||||
void IntelligentKeyboard::interrogate_mouse_position() {
|
||||
output_byte(0xf7); // Beginning of mouse response.
|
||||
output_byte(0x00); // 0000dcba; a = right button down since last interrogation, b = right button up since, c/d = left button.
|
||||
output_byte(0x00); // x motion: MSB, LSB
|
||||
output_byte(0x00);
|
||||
output_byte(0x00); // y motion: MSB, LSB
|
||||
output_byte(0x00);
|
||||
output_bytes({
|
||||
0xf7, // Beginning of mouse response.
|
||||
0x00, // 0000dcba; a = right button down since last interrogation, b = right button up since, c/d = left button.
|
||||
0x00, // x motion: MSB, LSB
|
||||
0x00,
|
||||
0x00, // y motion: MSB, LSB
|
||||
0x00
|
||||
});
|
||||
}
|
||||
|
||||
void IntelligentKeyboard::post_relative_mouse_event(int x, int y) {
|
||||
posted_button_state_ = mouse_button_state_;
|
||||
|
||||
// Break up the motion to impart, if it's too large.
|
||||
do {
|
||||
int stepped_motion[2] = {
|
||||
(x >= -128 && x < 127) ? x : (x > 0 ? 127 : -128),
|
||||
(y >= -128 && y < 127) ? y : (y > 0 ? 127 : -128),
|
||||
};
|
||||
|
||||
output_bytes({
|
||||
uint8_t(0xf8 | posted_button_state_), // Command code is a function of button state.
|
||||
uint8_t(stepped_motion[0]),
|
||||
uint8_t(stepped_motion[1]),
|
||||
});
|
||||
|
||||
x -= stepped_motion[0];
|
||||
y -= stepped_motion[1];
|
||||
} while(x || y);
|
||||
}
|
||||
|
||||
// MARK: - Mouse Input
|
||||
|
||||
void IntelligentKeyboard::move(int x, int y) {
|
||||
mouse_movement_[0] += x;
|
||||
mouse_movement_[1] += y;
|
||||
}
|
||||
|
||||
int IntelligentKeyboard::get_number_of_buttons() {
|
||||
return 2;
|
||||
}
|
||||
|
||||
void IntelligentKeyboard::set_button_pressed(int index, bool is_pressed) {
|
||||
const auto mask = 1 << index;
|
||||
if(is_pressed) {
|
||||
mouse_button_state_ |= mask;
|
||||
} else {
|
||||
mouse_button_state_ &= ~mask;
|
||||
}
|
||||
}
|
||||
|
||||
void IntelligentKeyboard::reset_all_buttons() {
|
||||
mouse_button_state_ = 0;
|
||||
}
|
||||
|
||||
// MARK: - Joystick Output
|
||||
void IntelligentKeyboard::disable_joysticks() {
|
||||
}
|
||||
|
@ -12,6 +12,10 @@
|
||||
#include "../../ClockReceiver/ClockingHintSource.hpp"
|
||||
#include "../../Components/SerialPort/SerialPort.hpp"
|
||||
|
||||
#include "../../Inputs/Mouse.hpp"
|
||||
|
||||
#include <atomic>
|
||||
|
||||
namespace Atari {
|
||||
namespace ST {
|
||||
|
||||
@ -21,7 +25,8 @@ namespace ST {
|
||||
*/
|
||||
class IntelligentKeyboard:
|
||||
public Serial::Line::ReadDelegate,
|
||||
public ClockingHint::Source {
|
||||
public ClockingHint::Source,
|
||||
public Inputs::Mouse {
|
||||
public:
|
||||
IntelligentKeyboard(Serial::Line &input, Serial::Line &output);
|
||||
ClockingHint::Preference preferred_clocking() final;
|
||||
@ -33,7 +38,7 @@ class IntelligentKeyboard:
|
||||
int command_ = 0;
|
||||
Serial::Line &output_line_;
|
||||
|
||||
void output_byte(uint8_t value);
|
||||
void output_bytes(std::initializer_list<uint8_t> value);
|
||||
bool serial_line_did_produce_bit(Serial::Line *, int bit) final;
|
||||
|
||||
// MARK: - Command dispatch.
|
||||
@ -58,6 +63,29 @@ class IntelligentKeyboard:
|
||||
void set_mouse_button_actions(uint8_t actions);
|
||||
void interrogate_mouse_position();
|
||||
|
||||
// Inputs::Mouse.
|
||||
void move(int x, int y) final;
|
||||
int get_number_of_buttons() final;
|
||||
void set_button_pressed(int index, bool is_pressed) final;
|
||||
void reset_all_buttons() final;
|
||||
|
||||
enum class MouseMode {
|
||||
Relative, Absolute
|
||||
} mouse_mode_ = MouseMode::Relative;
|
||||
|
||||
// Absolute positioning state.
|
||||
int mouse_range_[2] = {0, 0};
|
||||
int mouse_scale_[2] = {0, 0};
|
||||
|
||||
// Relative positioning state.
|
||||
int posted_button_state_ = 0;
|
||||
int mouse_threshold_[2] = {1, 1};
|
||||
void post_relative_mouse_event(int x, int y);
|
||||
|
||||
// Received mouse state.
|
||||
std::atomic<int> mouse_movement_[2];
|
||||
std::atomic<int> mouse_button_state_;
|
||||
|
||||
// MARK: - Joystick.
|
||||
void disable_joysticks();
|
||||
};
|
||||
|
Loading…
x
Reference in New Issue
Block a user