mirror of
https://github.com/dingusdev/dingusppc.git
synced 2024-12-23 06:29:38 +00:00
Implement the ADB keyboard
Besides generating KeyboardEvents in the SDL event handler and returning the key state in the register 0 reads of the AdbKeyboard device, we also needed to generalize the ADB bus polling a bit. We now check all devices that have the service request bit set, instead of hardcoding the mouse. The SDL key event -> ADB raw key code mapping is based on BasiliskII/ SheepShaver's, but cleaned up a bit.
This commit is contained in:
parent
37cca00e13
commit
73272b28dd
@ -22,10 +22,14 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
#include <core/hostevents.h>
|
||||
#include <core/coresignal.h>
|
||||
#include <cpu/ppc/ppcemu.h>
|
||||
#include <devices/common/adb/adbkeyboard.h>
|
||||
#include <loguru.hpp>
|
||||
#include <SDL.h>
|
||||
|
||||
EventManager* EventManager::event_manager;
|
||||
|
||||
static int get_sdl_event_key_code(const SDL_KeyboardEvent &event);
|
||||
|
||||
void EventManager::poll_events()
|
||||
{
|
||||
SDL_Event event;
|
||||
@ -47,11 +51,28 @@ void EventManager::poll_events()
|
||||
break;
|
||||
|
||||
case SDL_KEYDOWN:
|
||||
case SDL_KEYUP: {
|
||||
int key_code = get_sdl_event_key_code(event.key);
|
||||
if (key_code != -1) {
|
||||
KeyboardEvent ke;
|
||||
ke.key = key_code;
|
||||
if (event.type == SDL_KEYDOWN) {
|
||||
ke.flags = KEYBOARD_EVENT_DOWN;
|
||||
key_downs++;
|
||||
break;
|
||||
|
||||
case SDL_KEYUP:
|
||||
} else {
|
||||
ke.flags = KEYBOARD_EVENT_UP;
|
||||
key_ups++;
|
||||
}
|
||||
// Caps Lock is a special case, since it's a toggle key
|
||||
if (ke.key == AdbKey_CapsLock) {
|
||||
ke.flags = SDL_GetModState() & KMOD_CAPS ?
|
||||
KEYBOARD_EVENT_DOWN : KEYBOARD_EVENT_UP;
|
||||
}
|
||||
this->_keyboard_signal.emit(ke);
|
||||
} else {
|
||||
LOG_F(WARNING, "Unknow key %x pressed", event.key.keysym.sym);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case SDL_MOUSEMOTION: {
|
||||
@ -87,3 +108,138 @@ void EventManager::poll_events()
|
||||
// perform post-processing
|
||||
this->_post_signal.emit();
|
||||
}
|
||||
|
||||
|
||||
static int get_sdl_event_key_code(const SDL_KeyboardEvent &event)
|
||||
{
|
||||
switch (event.keysym.sym) {
|
||||
case SDLK_a: return AdbKey_A;
|
||||
case SDLK_b: return AdbKey_B;
|
||||
case SDLK_c: return AdbKey_C;
|
||||
case SDLK_d: return AdbKey_D;
|
||||
case SDLK_e: return AdbKey_E;
|
||||
case SDLK_f: return AdbKey_F;
|
||||
case SDLK_g: return AdbKey_G;
|
||||
case SDLK_h: return AdbKey_H;
|
||||
case SDLK_i: return AdbKey_I;
|
||||
case SDLK_j: return AdbKey_J;
|
||||
case SDLK_k: return AdbKey_K;
|
||||
case SDLK_l: return AdbKey_L;
|
||||
case SDLK_m: return AdbKey_M;
|
||||
case SDLK_n: return AdbKey_N;
|
||||
case SDLK_o: return AdbKey_O;
|
||||
case SDLK_p: return AdbKey_P;
|
||||
case SDLK_q: return AdbKey_Q;
|
||||
case SDLK_r: return AdbKey_R;
|
||||
case SDLK_s: return AdbKey_S;
|
||||
case SDLK_t: return AdbKey_T;
|
||||
case SDLK_u: return AdbKey_U;
|
||||
case SDLK_v: return AdbKey_V;
|
||||
case SDLK_w: return AdbKey_W;
|
||||
case SDLK_x: return AdbKey_X;
|
||||
case SDLK_y: return AdbKey_Y;
|
||||
case SDLK_z: return AdbKey_Z;
|
||||
|
||||
case SDLK_1: return AdbKey_1;
|
||||
case SDLK_2: return AdbKey_2;
|
||||
case SDLK_3: return AdbKey_3;
|
||||
case SDLK_4: return AdbKey_4;
|
||||
case SDLK_5: return AdbKey_5;
|
||||
case SDLK_6: return AdbKey_6;
|
||||
case SDLK_7: return AdbKey_7;
|
||||
case SDLK_8: return AdbKey_8;
|
||||
case SDLK_9: return AdbKey_9;
|
||||
case SDLK_0: return AdbKey_0;
|
||||
|
||||
case SDLK_ESCAPE: return AdbKey_Escape;
|
||||
case SDLK_BACKQUOTE: return AdbKey_Grave;
|
||||
case SDLK_MINUS: return AdbKey_Minus;
|
||||
case SDLK_EQUALS: return AdbKey_Equal;
|
||||
case SDLK_LEFTBRACKET: return AdbKey_LeftBracket;
|
||||
case SDLK_RIGHTBRACKET: return AdbKey_RightBracket;
|
||||
case SDLK_BACKSLASH: return AdbKey_Backslash;
|
||||
case SDLK_SEMICOLON: return AdbKey_Semicolon;
|
||||
case SDLK_QUOTE: return AdbKey_Quote;
|
||||
case SDLK_COMMA: return AdbKey_Comma;
|
||||
case SDLK_PERIOD: return AdbKey_Period;
|
||||
case SDLK_SLASH: return AdbKey_Slash;
|
||||
|
||||
// Convert shifted variants to unshifted
|
||||
case SDLK_EXCLAIM: return AdbKey_1;
|
||||
case SDLK_AT: return AdbKey_2;
|
||||
case SDLK_HASH: return AdbKey_3;
|
||||
case SDLK_DOLLAR: return AdbKey_4;
|
||||
case SDLK_UNDERSCORE: return AdbKey_Minus;
|
||||
case SDLK_PLUS: return AdbKey_Equal;
|
||||
case SDLK_COLON: return AdbKey_Semicolon;
|
||||
case SDLK_QUOTEDBL: return AdbKey_Quote;
|
||||
case SDLK_LESS: return AdbKey_Comma;
|
||||
case SDLK_GREATER: return AdbKey_Period;
|
||||
case SDLK_QUESTION: return AdbKey_Slash;
|
||||
|
||||
case SDLK_TAB: return AdbKey_Tab;
|
||||
case SDLK_RETURN: return AdbKey_Return;
|
||||
case SDLK_SPACE: return AdbKey_Space;
|
||||
case SDLK_BACKSPACE: return AdbKey_Delete;
|
||||
|
||||
case SDLK_DELETE: return AdbKey_ForwardDelete;
|
||||
case SDLK_INSERT: return AdbKey_Help;
|
||||
case SDLK_HOME: return AdbKey_Home;
|
||||
case SDLK_HELP: return AdbKey_Home;
|
||||
case SDLK_END: return AdbKey_End;
|
||||
case SDLK_PAGEUP: return AdbKey_PageUp;
|
||||
case SDLK_PAGEDOWN: return AdbKey_PageDown;
|
||||
|
||||
case SDLK_LCTRL: return AdbKey_Control;
|
||||
case SDLK_RCTRL: return AdbKey_Control;
|
||||
case SDLK_LSHIFT: return AdbKey_Shift;
|
||||
case SDLK_RSHIFT: return AdbKey_Shift;
|
||||
case SDLK_LALT: return AdbKey_Option;
|
||||
case SDLK_RALT: return AdbKey_Option;
|
||||
case SDLK_LGUI: return AdbKey_Command;
|
||||
case SDLK_RGUI: return AdbKey_Command;
|
||||
case SDLK_MENU: return AdbKey_Grave;
|
||||
case SDLK_CAPSLOCK: return AdbKey_CapsLock;
|
||||
|
||||
case SDLK_UP: return AdbKey_ArrowUp;
|
||||
case SDLK_DOWN: return AdbKey_ArrowDown;
|
||||
case SDLK_LEFT: return AdbKey_ArrowLeft;
|
||||
case SDLK_RIGHT: return AdbKey_ArrowRight;
|
||||
;
|
||||
case SDLK_KP_0: return AdbKey_Keypad0;
|
||||
case SDLK_KP_1: return AdbKey_Keypad1;
|
||||
case SDLK_KP_2: return AdbKey_Keypad2;
|
||||
case SDLK_KP_3: return AdbKey_Keypad3;
|
||||
case SDLK_KP_4: return AdbKey_Keypad4;
|
||||
case SDLK_KP_5: return AdbKey_Keypad5;
|
||||
case SDLK_KP_6: return AdbKey_Keypad6;
|
||||
case SDLK_KP_7: return AdbKey_Keypad7;
|
||||
case SDLK_KP_9: return AdbKey_Keypad9;
|
||||
case SDLK_KP_8: return AdbKey_Keypad8;
|
||||
case SDLK_KP_PERIOD: return AdbKey_KeypadDecimal;
|
||||
case SDLK_KP_PLUS: return AdbKey_KeypadPlus;
|
||||
case SDLK_KP_MINUS: return AdbKey_KeypadMinus;
|
||||
case SDLK_KP_MULTIPLY: return AdbKey_KeypadMultiply;
|
||||
case SDLK_KP_DIVIDE: return AdbKey_KeypadDivide;
|
||||
case SDLK_KP_ENTER: return AdbKey_KeypadEnter;
|
||||
case SDLK_KP_EQUALS: return AdbKey_KeypadEquals;
|
||||
case SDLK_NUMLOCKCLEAR: return AdbKey_KeypadClear;
|
||||
;
|
||||
case SDLK_F1: return AdbKey_F1;
|
||||
case SDLK_F2: return AdbKey_F2;
|
||||
case SDLK_F3: return AdbKey_F3;
|
||||
case SDLK_F4: return AdbKey_F4;
|
||||
case SDLK_F5: return AdbKey_F5;
|
||||
case SDLK_F6: return AdbKey_F6;
|
||||
case SDLK_F7: return AdbKey_F7;
|
||||
case SDLK_F8: return AdbKey_F8;
|
||||
case SDLK_F9: return AdbKey_F9;
|
||||
case SDLK_F10: return AdbKey_F10;
|
||||
case SDLK_F11: return AdbKey_F11;
|
||||
case SDLK_F12: return AdbKey_F12;
|
||||
case SDLK_PRINTSCREEN: return AdbKey_F13;
|
||||
case SDLK_SCROLLLOCK: return AdbKey_F14;
|
||||
case SDLK_PAUSE: return AdbKey_F15;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
@ -36,6 +36,16 @@ void AdbBus::register_device(AdbDevice* dev_obj) {
|
||||
this->devices.push_back(dev_obj);
|
||||
}
|
||||
|
||||
uint8_t AdbBus::poll() {
|
||||
for (auto dev : this->devices) {
|
||||
uint8_t dev_poll = dev->poll();
|
||||
if (dev_poll) {
|
||||
return dev_poll;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint8_t AdbBus::process_command(const uint8_t* in_data, int data_size) {
|
||||
uint8_t dev_addr, dev_reg;
|
||||
|
||||
@ -76,8 +86,12 @@ uint8_t AdbBus::process_command(const uint8_t* in_data, int data_size) {
|
||||
|
||||
this->got_answer = false;
|
||||
|
||||
for (auto dev : this->devices)
|
||||
for (auto dev : this->devices) {
|
||||
this->got_answer = dev->talk(dev_addr, dev_reg);
|
||||
if (this->got_answer) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!this->got_answer)
|
||||
return ADB_STAT_TIMEOUT;
|
||||
|
@ -55,6 +55,11 @@ public:
|
||||
uint8_t process_command(const uint8_t* in_data, int data_size);
|
||||
uint8_t get_output_count() { return this->output_count; };
|
||||
|
||||
// Polls devices that have a service request flag set. Returns the talk
|
||||
// command corresponding to the first device that responded with data, or
|
||||
// 0 if no device responded.
|
||||
uint8_t poll();
|
||||
|
||||
// callbacks meant to be called by devices
|
||||
const uint8_t* get_input_buf() { return this->input_buf; };
|
||||
uint8_t* get_output_buf() { return this->output_buf; };
|
||||
|
@ -39,6 +39,21 @@ int AdbDevice::device_postinit() {
|
||||
return 0;
|
||||
};
|
||||
|
||||
uint8_t AdbDevice::poll() {
|
||||
if (!this->srq_flag) {
|
||||
return 0;
|
||||
}
|
||||
bool has_data = this->get_register_0();
|
||||
if (!has_data) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Register 0 in bits 0-1 (both 0)
|
||||
// Talk command in bits 2-3 (both 1)
|
||||
// Device address in bits 4-7
|
||||
return 0xC | (this->my_addr << 4);
|
||||
}
|
||||
|
||||
bool AdbDevice::talk(const uint8_t dev_addr, const uint8_t reg_num) {
|
||||
if (dev_addr == this->my_addr && !this->got_collision) {
|
||||
// see if another device already responded to this command
|
||||
|
@ -49,6 +49,10 @@ public:
|
||||
virtual void listen(const uint8_t dev_addr, const uint8_t reg_num);
|
||||
virtual uint8_t get_address() { return this->my_addr; };
|
||||
|
||||
// Attempts to oolls the device. Returns the talk command corresponding to
|
||||
// the device if it has data, 0 otherwise.
|
||||
uint8_t poll();
|
||||
|
||||
protected:
|
||||
uint8_t gen_random_address();
|
||||
|
||||
|
@ -34,20 +34,45 @@ AdbKeyboard::AdbKeyboard(std::string name) : AdbDevice(name) {
|
||||
}
|
||||
|
||||
void AdbKeyboard::event_handler(const KeyboardEvent& event) {
|
||||
this->key = event.key;
|
||||
if (event.flags & KEYBOARD_EVENT_DOWN) {
|
||||
this->key_state = 0;
|
||||
}
|
||||
else if (event.flags & KEYBOARD_EVENT_UP) {
|
||||
this->key_state = 1;
|
||||
}
|
||||
this->changed = true;
|
||||
}
|
||||
|
||||
void AdbKeyboard::reset() {
|
||||
this->my_addr = ADB_ADDR_KBD;
|
||||
this->dev_handler_id = 2; // Extended ADB keyboard
|
||||
this->exc_event_flag = 2;
|
||||
this->exc_event_flag = 1;
|
||||
this->srq_flag = 1; // enable service requests
|
||||
this->key = 0;
|
||||
this->key_state = 0;
|
||||
this->changed = false;
|
||||
}
|
||||
|
||||
bool AdbKeyboard::get_register_0() {
|
||||
if (this->changed) {
|
||||
uint8_t* out_buf = this->host_obj->get_output_buf();
|
||||
|
||||
out_buf[0] = (this->key_state << 7) | (this->key & 0x7F);
|
||||
// It's possible that we get two events before the host polls us, but
|
||||
// in practice it has not come up. We need to set the key status bit to
|
||||
// 1 (released), otherwise if we leave it empty, the host will think
|
||||
// that the a key (code 0) is pressed.
|
||||
out_buf[1] = 1 << 7;
|
||||
|
||||
this->key = 0;
|
||||
this->key_state = 0;
|
||||
this->changed = false;
|
||||
|
||||
this->host_obj->set_output_count(2);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -50,10 +50,122 @@ public:
|
||||
|
||||
|
||||
private:
|
||||
int32_t x_rel = 0;
|
||||
int32_t y_rel = 0;
|
||||
uint8_t buttons_state = 0;
|
||||
uint32_t key = 0;
|
||||
uint8_t key_state = 0;
|
||||
bool changed = false;
|
||||
};
|
||||
|
||||
// ADB Extended Keyboard raw key codes (most of which eventually became virtual
|
||||
// key codes, see HIToolbox/Events.h).
|
||||
enum AdbKey {
|
||||
AdbKey_A = 0x00,
|
||||
AdbKey_B = 0x0b,
|
||||
AdbKey_C = 0x08,
|
||||
AdbKey_D = 0x02,
|
||||
AdbKey_E = 0x0e,
|
||||
AdbKey_F = 0x03,
|
||||
AdbKey_G = 0x05,
|
||||
AdbKey_H = 0x04,
|
||||
AdbKey_I = 0x22,
|
||||
AdbKey_J = 0x26,
|
||||
AdbKey_K = 0x28,
|
||||
AdbKey_L = 0x25,
|
||||
AdbKey_M = 0x2e,
|
||||
AdbKey_N = 0x2d,
|
||||
AdbKey_O = 0x1f,
|
||||
AdbKey_P = 0x23,
|
||||
AdbKey_Q = 0x0c,
|
||||
AdbKey_R = 0x0f,
|
||||
AdbKey_S = 0x01,
|
||||
AdbKey_T = 0x11,
|
||||
AdbKey_U = 0x20,
|
||||
AdbKey_V = 0x09,
|
||||
AdbKey_W = 0x0d,
|
||||
AdbKey_X = 0x07,
|
||||
AdbKey_Y = 0x10,
|
||||
AdbKey_Z = 0x06,
|
||||
|
||||
AdbKey_1 = 0x12,
|
||||
AdbKey_2 = 0x13,
|
||||
AdbKey_3 = 0x14,
|
||||
AdbKey_4 = 0x15,
|
||||
AdbKey_5 = 0x17,
|
||||
AdbKey_6 = 0x16,
|
||||
AdbKey_7 = 0x1a,
|
||||
AdbKey_8 = 0x1c,
|
||||
AdbKey_9 = 0x19,
|
||||
AdbKey_0 = 0x1d,
|
||||
|
||||
AdbKey_Minus = 0x1b,
|
||||
AdbKey_Equal = 0x18,
|
||||
AdbKey_LeftBracket = 0x21,
|
||||
AdbKey_RightBracket = 0x1e,
|
||||
AdbKey_Backslash = 0x2a,
|
||||
AdbKey_Semicolon = 0x29,
|
||||
AdbKey_Quote = 0x27,
|
||||
AdbKey_Comma = 0x2b,
|
||||
AdbKey_Period = 0x2f,
|
||||
AdbKey_Slash = 0x2c,
|
||||
|
||||
AdbKey_Tab = 0x30,
|
||||
AdbKey_Return = 0x24,
|
||||
AdbKey_Space = 0x31,
|
||||
AdbKey_Delete = 0x33,
|
||||
|
||||
AdbKey_ForwardDelete = 0x75,
|
||||
AdbKey_Help = 0x72,
|
||||
AdbKey_Home = 0x73,
|
||||
AdbKey_End = 0x77,
|
||||
AdbKey_PageUp = 0x74,
|
||||
AdbKey_PageDown = 0x79,
|
||||
|
||||
AdbKey_Grave = 0x32,
|
||||
AdbKey_Escape = 0x35,
|
||||
AdbKey_Control = 0x36,
|
||||
AdbKey_Shift = 0x38,
|
||||
AdbKey_Option = 0x3a,
|
||||
AdbKey_Command = 0x37,
|
||||
AdbKey_CapsLock = 0x39,
|
||||
|
||||
AdbKey_ArrowUp = 0x3e,
|
||||
AdbKey_ArrowDown = 0x3d,
|
||||
AdbKey_ArrowLeft = 0x3b,
|
||||
AdbKey_ArrowRight = 0x3c,
|
||||
|
||||
AdbKey_Keypad0 = 0x52,
|
||||
AdbKey_Keypad1 = 0x53,
|
||||
AdbKey_Keypad2 = 0x54,
|
||||
AdbKey_Keypad3 = 0x55,
|
||||
AdbKey_Keypad4 = 0x56,
|
||||
AdbKey_Keypad5 = 0x57,
|
||||
AdbKey_Keypad6 = 0x58,
|
||||
AdbKey_Keypad7 = 0x59,
|
||||
AdbKey_Keypad9 = 0x5c,
|
||||
AdbKey_Keypad8 = 0x5b,
|
||||
AdbKey_KeypadDecimal = 0x41,
|
||||
AdbKey_KeypadPlus = 0x45,
|
||||
AdbKey_KeypadMinus = 0x4e,
|
||||
AdbKey_KeypadMultiply = 0x43,
|
||||
AdbKey_KeypadDivide = 0x4b,
|
||||
AdbKey_KeypadEnter = 0x4c,
|
||||
AdbKey_KeypadEquals = 0x51,
|
||||
AdbKey_KeypadClear = 0x47,
|
||||
|
||||
AdbKey_F1 = 0x7a,
|
||||
AdbKey_F2 = 0x78,
|
||||
AdbKey_F3 = 0x63,
|
||||
AdbKey_F4 = 0x76,
|
||||
AdbKey_F5 = 0x60,
|
||||
AdbKey_F6 = 0x61,
|
||||
AdbKey_F7 = 0x62,
|
||||
AdbKey_F8 = 0x64,
|
||||
AdbKey_F9 = 0x65,
|
||||
AdbKey_F10 = 0x6d,
|
||||
AdbKey_F11 = 0x67,
|
||||
AdbKey_F12 = 0x6f,
|
||||
AdbKey_F13 = 0x69,
|
||||
AdbKey_F14 = 0x6b,
|
||||
AdbKey_F15 = 0x71,
|
||||
};
|
||||
|
||||
#endif // ADB_KEYBOARD_H
|
||||
|
@ -473,25 +473,20 @@ void ViaCuda::process_adb_command() {
|
||||
}
|
||||
|
||||
void ViaCuda::autopoll_handler() {
|
||||
uint8_t adb_status, output_size;
|
||||
|
||||
if (!this->autopoll_enabled)
|
||||
return;
|
||||
|
||||
// send TALK R0 command to address 3 (mouse)
|
||||
uint8_t in_data[2] = { 0x3C, 0};
|
||||
uint8_t poll_command = this->adb_bus_obj->poll();
|
||||
|
||||
adb_status = this->adb_bus_obj->process_command(in_data, 1);
|
||||
|
||||
if (adb_status == ADB_STAT_OK) {
|
||||
if (poll_command) {
|
||||
if (!this->old_tip || !this->treq) {
|
||||
LOG_F(WARNING, "Cuda transaction probably in progress");
|
||||
}
|
||||
|
||||
// prepare autopoll packet
|
||||
response_header(CUDA_PKT_ADB, adb_status | ADB_STAT_AUTOPOLL);
|
||||
this->out_buf[2] = 0x3C; // put the proper ADB command
|
||||
output_size = this->adb_bus_obj->get_output_count();
|
||||
response_header(CUDA_PKT_ADB, ADB_STAT_OK | ADB_STAT_AUTOPOLL);
|
||||
this->out_buf[2] = poll_command; // put the proper ADB command
|
||||
uint8_t output_size = this->adb_bus_obj->get_output_count();
|
||||
if (output_size) {
|
||||
std::memcpy(&this->out_buf[3], this->adb_bus_obj->get_output_buf(), output_size);
|
||||
this->out_count += output_size;
|
||||
|
Loading…
Reference in New Issue
Block a user