2019-11-02 23:47:44 +00:00
|
|
|
//
|
|
|
|
// IntelligentKeyboard.hpp
|
|
|
|
// Clock Signal
|
|
|
|
//
|
|
|
|
// Created by Thomas Harte on 02/11/2019.
|
|
|
|
// Copyright © 2019 Thomas Harte. All rights reserved.
|
|
|
|
//
|
|
|
|
|
2024-01-17 04:34:46 +00:00
|
|
|
#pragma once
|
2019-11-02 23:47:44 +00:00
|
|
|
|
2019-11-09 20:31:41 +00:00
|
|
|
#include "../../../ClockReceiver/ClockingHintSource.hpp"
|
|
|
|
#include "../../../Components/Serial/Line.hpp"
|
|
|
|
#include "../../KeyboardMachine.hpp"
|
2019-11-02 23:47:44 +00:00
|
|
|
|
2019-11-09 23:19:05 +00:00
|
|
|
#include "../../../Inputs/Joystick.hpp"
|
2019-11-09 20:31:41 +00:00
|
|
|
#include "../../../Inputs/Mouse.hpp"
|
2019-11-03 01:25:45 +00:00
|
|
|
|
|
|
|
#include <atomic>
|
2019-11-03 02:30:02 +00:00
|
|
|
#include <mutex>
|
2019-11-09 23:19:05 +00:00
|
|
|
#include <memory>
|
|
|
|
#include <vector>
|
2019-11-03 01:25:45 +00:00
|
|
|
|
2023-05-10 21:02:18 +00:00
|
|
|
namespace Atari::ST {
|
2019-11-02 23:47:44 +00:00
|
|
|
|
2019-11-03 02:30:02 +00:00
|
|
|
enum class Key: uint16_t {
|
|
|
|
Escape = 1,
|
|
|
|
k1, k2, k3, k4, k5, k6, k7, k8, k9, k0, Hyphen, Equals, Backspace,
|
|
|
|
Tab, Q, W, E, R, T, Y, U, I, O, P, OpenSquareBracket, CloseSquareBracket, Return,
|
|
|
|
Control, A, S, D, F, G, H, J, K, L, Semicolon, Quote, BackTick,
|
|
|
|
LeftShift, Backslash, Z, X, C, V, B, N, M, Comma, FullStop, ForwardSlash, RightShift,
|
|
|
|
/* 0x37 is unused. */
|
|
|
|
Alt = 0x38, Space, CapsLock, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10,
|
|
|
|
/* Various gaps follow. */
|
|
|
|
Home = 0x47, Up,
|
|
|
|
KeypadMinus = 0x4a, Left,
|
|
|
|
Right = 0x4d, KeypadPlus,
|
|
|
|
Down = 0x50,
|
|
|
|
Insert = 0x52, Delete,
|
|
|
|
ISO = 0x60, Undo, Help, KeypadOpenBracket, KeypadCloseBracket, KeypadDivide, KeypadMultiply,
|
2019-11-09 23:02:14 +00:00
|
|
|
Keypad7, Keypad8, Keypad9, Keypad4, Keypad5, Keypad6, Keypad1, Keypad2, Keypad3, Keypad0, KeypadDecimalPoint,
|
2020-01-04 14:45:59 +00:00
|
|
|
KeypadEnter,
|
|
|
|
Joystick1Button = 0x74, // These keycodes are used only in joystick keycode mode.
|
|
|
|
Joystick2Button = 0x75,
|
2019-11-03 02:30:02 +00:00
|
|
|
};
|
|
|
|
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");
|
|
|
|
static_assert(uint16_t(Key::KeypadEnter) == 0x72, "KeypadEnter should have key code 0x72; check intermediate entries");
|
|
|
|
|
2019-11-02 23:47:44 +00:00
|
|
|
/*!
|
|
|
|
A receiver for the Atari ST's "intelligent keyboard" commands, which actually cover
|
|
|
|
keyboard input and output and mouse handling.
|
|
|
|
*/
|
|
|
|
class IntelligentKeyboard:
|
2021-11-06 23:54:20 +00:00
|
|
|
public Serial::Line<false>::ReadDelegate,
|
2019-11-03 01:25:45 +00:00
|
|
|
public ClockingHint::Source,
|
|
|
|
public Inputs::Mouse {
|
2019-11-02 23:47:44 +00:00
|
|
|
public:
|
2021-11-06 23:54:20 +00:00
|
|
|
IntelligentKeyboard(Serial::Line<false> &input, Serial::Line<false> &output);
|
2020-05-10 01:22:51 +00:00
|
|
|
ClockingHint::Preference preferred_clocking() const final;
|
2019-11-02 23:47:44 +00:00
|
|
|
void run_for(HalfCycles duration);
|
|
|
|
|
2019-11-03 02:30:02 +00:00
|
|
|
void set_key_state(Key key, bool is_pressed);
|
2020-04-02 03:19:34 +00:00
|
|
|
class KeyboardMapper: public MachineTypes::MappedKeyboardMachine::KeyboardMapper {
|
2020-05-21 03:34:26 +00:00
|
|
|
uint16_t mapped_key_for_key(Inputs::Keyboard::Key key) const final;
|
2019-11-03 02:30:02 +00:00
|
|
|
};
|
|
|
|
|
2019-11-09 23:19:05 +00:00
|
|
|
const std::vector<std::unique_ptr<Inputs::Joystick>> &get_joysticks() {
|
|
|
|
return joysticks_;
|
|
|
|
}
|
|
|
|
|
2019-11-02 23:47:44 +00:00
|
|
|
private:
|
2019-11-03 02:30:02 +00:00
|
|
|
// MARK: - Key queue.
|
|
|
|
std::mutex key_queue_mutex_;
|
|
|
|
std::vector<uint8_t> key_queue_;
|
|
|
|
|
2019-11-02 23:47:44 +00:00
|
|
|
// MARK: - Serial line state.
|
|
|
|
int bit_count_ = 0;
|
|
|
|
int command_ = 0;
|
2021-11-06 23:54:20 +00:00
|
|
|
Serial::Line<false> &output_line_;
|
2019-11-02 23:47:44 +00:00
|
|
|
|
2019-11-03 01:25:45 +00:00
|
|
|
void output_bytes(std::initializer_list<uint8_t> value);
|
2021-11-06 23:54:20 +00:00
|
|
|
bool serial_line_did_produce_bit(Serial::Line<false> *, int bit) final;
|
2019-11-02 23:47:44 +00:00
|
|
|
|
|
|
|
// MARK: - Command dispatch.
|
|
|
|
std::vector<uint8_t> command_sequence_;
|
|
|
|
void dispatch_command(uint8_t command);
|
|
|
|
|
|
|
|
// MARK: - Flow control.
|
|
|
|
void reset();
|
|
|
|
void resume();
|
|
|
|
void pause();
|
|
|
|
|
|
|
|
// MARK: - Mouse.
|
|
|
|
void disable_mouse();
|
|
|
|
void set_relative_mouse_position_reporting();
|
|
|
|
void set_absolute_mouse_position_reporting(uint16_t max_x, uint16_t max_y);
|
|
|
|
void set_mouse_position(uint16_t x, uint16_t y);
|
|
|
|
void set_mouse_keycode_reporting(uint8_t delta_x, uint8_t delta_y);
|
|
|
|
void set_mouse_threshold(uint8_t x, uint8_t y);
|
|
|
|
void set_mouse_scale(uint8_t x, uint8_t y);
|
|
|
|
void set_mouse_y_downward();
|
|
|
|
void set_mouse_y_upward();
|
|
|
|
void set_mouse_button_actions(uint8_t actions);
|
|
|
|
void interrogate_mouse_position();
|
|
|
|
|
2019-11-03 01:25:45 +00:00
|
|
|
// Inputs::Mouse.
|
|
|
|
void move(int x, int y) final;
|
2024-11-30 23:57:56 +00:00
|
|
|
int get_number_of_buttons() const final;
|
2019-11-03 01:25:45 +00:00
|
|
|
void set_button_pressed(int index, bool is_pressed) final;
|
|
|
|
void reset_all_buttons() final;
|
|
|
|
|
|
|
|
enum class MouseMode {
|
2020-01-01 17:29:33 +00:00
|
|
|
Relative, Absolute, Disabled
|
2019-11-03 01:25:45 +00:00
|
|
|
} mouse_mode_ = MouseMode::Relative;
|
|
|
|
|
|
|
|
// Absolute positioning state.
|
2020-01-01 17:29:33 +00:00
|
|
|
int mouse_range_[2] = {320, 200};
|
|
|
|
int mouse_scale_[2] = {1, 1};
|
|
|
|
int mouse_position_[2] = {0, 0};
|
|
|
|
int mouse_y_multiplier_ = 1;
|
2019-11-03 01:25:45 +00:00
|
|
|
|
|
|
|
// 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.
|
2020-05-21 03:34:26 +00:00
|
|
|
std::atomic<int> mouse_movement_[2]{0, 0};
|
|
|
|
std::atomic<int> mouse_button_state_{0};
|
|
|
|
std::atomic<int> mouse_button_events_{0};
|
2019-11-03 01:25:45 +00:00
|
|
|
|
2019-11-02 23:47:44 +00:00
|
|
|
// MARK: - Joystick.
|
|
|
|
void disable_joysticks();
|
2019-11-04 02:58:15 +00:00
|
|
|
void set_joystick_event_mode();
|
|
|
|
void set_joystick_interrogation_mode();
|
2019-11-10 01:10:54 +00:00
|
|
|
void set_joystick_monitoring_mode(uint8_t rate);
|
|
|
|
void set_joystick_fire_button_monitoring_mode();
|
|
|
|
struct VelocityThreshold {
|
|
|
|
uint8_t threshold;
|
|
|
|
uint8_t prior_rate;
|
|
|
|
uint8_t post_rate;
|
|
|
|
};
|
|
|
|
void set_joystick_keycode_mode(VelocityThreshold horizontal, VelocityThreshold vertical);
|
2019-11-04 02:58:15 +00:00
|
|
|
void interrogate_joysticks();
|
|
|
|
|
2020-01-04 14:45:59 +00:00
|
|
|
void clear_joystick_events();
|
|
|
|
|
2019-11-04 02:58:15 +00:00
|
|
|
enum class JoystickMode {
|
2020-01-04 14:45:59 +00:00
|
|
|
Disabled, Event, Interrogation, KeyCode
|
2019-11-04 02:58:15 +00:00
|
|
|
} joystick_mode_ = JoystickMode::Event;
|
2019-11-09 23:39:22 +00:00
|
|
|
|
|
|
|
class Joystick: public Inputs::ConcreteJoystick {
|
|
|
|
public:
|
|
|
|
Joystick() :
|
|
|
|
ConcreteJoystick({
|
|
|
|
Input(Input::Up),
|
|
|
|
Input(Input::Down),
|
|
|
|
Input(Input::Left),
|
|
|
|
Input(Input::Right),
|
|
|
|
Input(Input::Fire, 0),
|
|
|
|
}) {}
|
|
|
|
|
2020-01-24 03:57:51 +00:00
|
|
|
void did_set_input(const Input &input, bool is_active) final {
|
2019-11-09 23:39:22 +00:00
|
|
|
uint8_t mask = 0;
|
|
|
|
switch(input.type) {
|
|
|
|
default: return;
|
|
|
|
case Input::Up: mask = 0x01; break;
|
|
|
|
case Input::Down: mask = 0x02; break;
|
|
|
|
case Input::Left: mask = 0x04; break;
|
|
|
|
case Input::Right: mask = 0x08; break;
|
|
|
|
case Input::Fire: mask = 0x80; break;
|
|
|
|
}
|
|
|
|
|
2019-11-10 01:10:54 +00:00
|
|
|
if(is_active) state_ |= mask; else state_ &= ~mask;
|
2019-11-09 23:39:22 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
uint8_t get_state() {
|
|
|
|
returned_state_ = state_;
|
|
|
|
return state_;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool has_event() {
|
|
|
|
return returned_state_ != state_;
|
|
|
|
}
|
|
|
|
|
2020-01-04 14:45:59 +00:00
|
|
|
uint8_t event_mask() {
|
|
|
|
return returned_state_ ^ state_;
|
|
|
|
}
|
|
|
|
|
2019-11-09 23:39:22 +00:00
|
|
|
private:
|
2019-11-10 01:10:54 +00:00
|
|
|
uint8_t state_ = 0x00;
|
|
|
|
uint8_t returned_state_ = 0x00;
|
2019-11-09 23:39:22 +00:00
|
|
|
};
|
2019-11-09 23:19:05 +00:00
|
|
|
std::vector<std::unique_ptr<Inputs::Joystick>> joysticks_;
|
2019-11-02 23:47:44 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
}
|