Skip to content

Commit 73272b2

Browse files
committed
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.
1 parent 37cca00 commit 73272b2

8 files changed

Lines changed: 346 additions & 20 deletions

File tree

core/hostevents_sdl.cpp

Lines changed: 161 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -22,10 +22,14 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
2222
#include <core/hostevents.h>
2323
#include <core/coresignal.h>
2424
#include <cpu/ppc/ppcemu.h>
25+
#include <devices/common/adb/adbkeyboard.h>
26+
#include <loguru.hpp>
2527
#include <SDL.h>
2628

2729
EventManager* EventManager::event_manager;
2830

31+
static int get_sdl_event_key_code(const SDL_KeyboardEvent &event);
32+
2933
void EventManager::poll_events()
3034
{
3135
SDL_Event event;
@@ -47,11 +51,28 @@ void EventManager::poll_events()
4751
break;
4852

4953
case SDL_KEYDOWN:
50-
key_downs++;
51-
break;
52-
53-
case SDL_KEYUP:
54-
key_ups++;
54+
case SDL_KEYUP: {
55+
int key_code = get_sdl_event_key_code(event.key);
56+
if (key_code != -1) {
57+
KeyboardEvent ke;
58+
ke.key = key_code;
59+
if (event.type == SDL_KEYDOWN) {
60+
ke.flags = KEYBOARD_EVENT_DOWN;
61+
key_downs++;
62+
} else {
63+
ke.flags = KEYBOARD_EVENT_UP;
64+
key_ups++;
65+
}
66+
// Caps Lock is a special case, since it's a toggle key
67+
if (ke.key == AdbKey_CapsLock) {
68+
ke.flags = SDL_GetModState() & KMOD_CAPS ?
69+
KEYBOARD_EVENT_DOWN : KEYBOARD_EVENT_UP;
70+
}
71+
this->_keyboard_signal.emit(ke);
72+
} else {
73+
LOG_F(WARNING, "Unknow key %x pressed", event.key.keysym.sym);
74+
}
75+
}
5576
break;
5677

5778
case SDL_MOUSEMOTION: {
@@ -87,3 +108,138 @@ void EventManager::poll_events()
87108
// perform post-processing
88109
this->_post_signal.emit();
89110
}
111+
112+
113+
static int get_sdl_event_key_code(const SDL_KeyboardEvent &event)
114+
{
115+
switch (event.keysym.sym) {
116+
case SDLK_a: return AdbKey_A;
117+
case SDLK_b: return AdbKey_B;
118+
case SDLK_c: return AdbKey_C;
119+
case SDLK_d: return AdbKey_D;
120+
case SDLK_e: return AdbKey_E;
121+
case SDLK_f: return AdbKey_F;
122+
case SDLK_g: return AdbKey_G;
123+
case SDLK_h: return AdbKey_H;
124+
case SDLK_i: return AdbKey_I;
125+
case SDLK_j: return AdbKey_J;
126+
case SDLK_k: return AdbKey_K;
127+
case SDLK_l: return AdbKey_L;
128+
case SDLK_m: return AdbKey_M;
129+
case SDLK_n: return AdbKey_N;
130+
case SDLK_o: return AdbKey_O;
131+
case SDLK_p: return AdbKey_P;
132+
case SDLK_q: return AdbKey_Q;
133+
case SDLK_r: return AdbKey_R;
134+
case SDLK_s: return AdbKey_S;
135+
case SDLK_t: return AdbKey_T;
136+
case SDLK_u: return AdbKey_U;
137+
case SDLK_v: return AdbKey_V;
138+
case SDLK_w: return AdbKey_W;
139+
case SDLK_x: return AdbKey_X;
140+
case SDLK_y: return AdbKey_Y;
141+
case SDLK_z: return AdbKey_Z;
142+
143+
case SDLK_1: return AdbKey_1;
144+
case SDLK_2: return AdbKey_2;
145+
case SDLK_3: return AdbKey_3;
146+
case SDLK_4: return AdbKey_4;
147+
case SDLK_5: return AdbKey_5;
148+
case SDLK_6: return AdbKey_6;
149+
case SDLK_7: return AdbKey_7;
150+
case SDLK_8: return AdbKey_8;
151+
case SDLK_9: return AdbKey_9;
152+
case SDLK_0: return AdbKey_0;
153+
154+
case SDLK_ESCAPE: return AdbKey_Escape;
155+
case SDLK_BACKQUOTE: return AdbKey_Grave;
156+
case SDLK_MINUS: return AdbKey_Minus;
157+
case SDLK_EQUALS: return AdbKey_Equal;
158+
case SDLK_LEFTBRACKET: return AdbKey_LeftBracket;
159+
case SDLK_RIGHTBRACKET: return AdbKey_RightBracket;
160+
case SDLK_BACKSLASH: return AdbKey_Backslash;
161+
case SDLK_SEMICOLON: return AdbKey_Semicolon;
162+
case SDLK_QUOTE: return AdbKey_Quote;
163+
case SDLK_COMMA: return AdbKey_Comma;
164+
case SDLK_PERIOD: return AdbKey_Period;
165+
case SDLK_SLASH: return AdbKey_Slash;
166+
167+
// Convert shifted variants to unshifted
168+
case SDLK_EXCLAIM: return AdbKey_1;
169+
case SDLK_AT: return AdbKey_2;
170+
case SDLK_HASH: return AdbKey_3;
171+
case SDLK_DOLLAR: return AdbKey_4;
172+
case SDLK_UNDERSCORE: return AdbKey_Minus;
173+
case SDLK_PLUS: return AdbKey_Equal;
174+
case SDLK_COLON: return AdbKey_Semicolon;
175+
case SDLK_QUOTEDBL: return AdbKey_Quote;
176+
case SDLK_LESS: return AdbKey_Comma;
177+
case SDLK_GREATER: return AdbKey_Period;
178+
case SDLK_QUESTION: return AdbKey_Slash;
179+
180+
case SDLK_TAB: return AdbKey_Tab;
181+
case SDLK_RETURN: return AdbKey_Return;
182+
case SDLK_SPACE: return AdbKey_Space;
183+
case SDLK_BACKSPACE: return AdbKey_Delete;
184+
185+
case SDLK_DELETE: return AdbKey_ForwardDelete;
186+
case SDLK_INSERT: return AdbKey_Help;
187+
case SDLK_HOME: return AdbKey_Home;
188+
case SDLK_HELP: return AdbKey_Home;
189+
case SDLK_END: return AdbKey_End;
190+
case SDLK_PAGEUP: return AdbKey_PageUp;
191+
case SDLK_PAGEDOWN: return AdbKey_PageDown;
192+
193+
case SDLK_LCTRL: return AdbKey_Control;
194+
case SDLK_RCTRL: return AdbKey_Control;
195+
case SDLK_LSHIFT: return AdbKey_Shift;
196+
case SDLK_RSHIFT: return AdbKey_Shift;
197+
case SDLK_LALT: return AdbKey_Option;
198+
case SDLK_RALT: return AdbKey_Option;
199+
case SDLK_LGUI: return AdbKey_Command;
200+
case SDLK_RGUI: return AdbKey_Command;
201+
case SDLK_MENU: return AdbKey_Grave;
202+
case SDLK_CAPSLOCK: return AdbKey_CapsLock;
203+
204+
case SDLK_UP: return AdbKey_ArrowUp;
205+
case SDLK_DOWN: return AdbKey_ArrowDown;
206+
case SDLK_LEFT: return AdbKey_ArrowLeft;
207+
case SDLK_RIGHT: return AdbKey_ArrowRight;
208+
;
209+
case SDLK_KP_0: return AdbKey_Keypad0;
210+
case SDLK_KP_1: return AdbKey_Keypad1;
211+
case SDLK_KP_2: return AdbKey_Keypad2;
212+
case SDLK_KP_3: return AdbKey_Keypad3;
213+
case SDLK_KP_4: return AdbKey_Keypad4;
214+
case SDLK_KP_5: return AdbKey_Keypad5;
215+
case SDLK_KP_6: return AdbKey_Keypad6;
216+
case SDLK_KP_7: return AdbKey_Keypad7;
217+
case SDLK_KP_9: return AdbKey_Keypad9;
218+
case SDLK_KP_8: return AdbKey_Keypad8;
219+
case SDLK_KP_PERIOD: return AdbKey_KeypadDecimal;
220+
case SDLK_KP_PLUS: return AdbKey_KeypadPlus;
221+
case SDLK_KP_MINUS: return AdbKey_KeypadMinus;
222+
case SDLK_KP_MULTIPLY: return AdbKey_KeypadMultiply;
223+
case SDLK_KP_DIVIDE: return AdbKey_KeypadDivide;
224+
case SDLK_KP_ENTER: return AdbKey_KeypadEnter;
225+
case SDLK_KP_EQUALS: return AdbKey_KeypadEquals;
226+
case SDLK_NUMLOCKCLEAR: return AdbKey_KeypadClear;
227+
;
228+
case SDLK_F1: return AdbKey_F1;
229+
case SDLK_F2: return AdbKey_F2;
230+
case SDLK_F3: return AdbKey_F3;
231+
case SDLK_F4: return AdbKey_F4;
232+
case SDLK_F5: return AdbKey_F5;
233+
case SDLK_F6: return AdbKey_F6;
234+
case SDLK_F7: return AdbKey_F7;
235+
case SDLK_F8: return AdbKey_F8;
236+
case SDLK_F9: return AdbKey_F9;
237+
case SDLK_F10: return AdbKey_F10;
238+
case SDLK_F11: return AdbKey_F11;
239+
case SDLK_F12: return AdbKey_F12;
240+
case SDLK_PRINTSCREEN: return AdbKey_F13;
241+
case SDLK_SCROLLLOCK: return AdbKey_F14;
242+
case SDLK_PAUSE: return AdbKey_F15;
243+
}
244+
return -1;
245+
}

devices/common/adb/adbbus.cpp

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,16 @@ void AdbBus::register_device(AdbDevice* dev_obj) {
3636
this->devices.push_back(dev_obj);
3737
}
3838

39+
uint8_t AdbBus::poll() {
40+
for (auto dev : this->devices) {
41+
uint8_t dev_poll = dev->poll();
42+
if (dev_poll) {
43+
return dev_poll;
44+
}
45+
}
46+
return 0;
47+
}
48+
3949
uint8_t AdbBus::process_command(const uint8_t* in_data, int data_size) {
4050
uint8_t dev_addr, dev_reg;
4151

@@ -76,8 +86,12 @@ uint8_t AdbBus::process_command(const uint8_t* in_data, int data_size) {
7686

7787
this->got_answer = false;
7888

79-
for (auto dev : this->devices)
89+
for (auto dev : this->devices) {
8090
this->got_answer = dev->talk(dev_addr, dev_reg);
91+
if (this->got_answer) {
92+
break;
93+
}
94+
}
8195

8296
if (!this->got_answer)
8397
return ADB_STAT_TIMEOUT;

devices/common/adb/adbbus.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,11 @@ class AdbBus : public HWComponent {
5555
uint8_t process_command(const uint8_t* in_data, int data_size);
5656
uint8_t get_output_count() { return this->output_count; };
5757

58+
// Polls devices that have a service request flag set. Returns the talk
59+
// command corresponding to the first device that responded with data, or
60+
// 0 if no device responded.
61+
uint8_t poll();
62+
5863
// callbacks meant to be called by devices
5964
const uint8_t* get_input_buf() { return this->input_buf; };
6065
uint8_t* get_output_buf() { return this->output_buf; };

devices/common/adb/adbdevice.cpp

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,21 @@ int AdbDevice::device_postinit() {
3939
return 0;
4040
};
4141

42+
uint8_t AdbDevice::poll() {
43+
if (!this->srq_flag) {
44+
return 0;
45+
}
46+
bool has_data = this->get_register_0();
47+
if (!has_data) {
48+
return 0;
49+
}
50+
51+
// Register 0 in bits 0-1 (both 0)
52+
// Talk command in bits 2-3 (both 1)
53+
// Device address in bits 4-7
54+
return 0xC | (this->my_addr << 4);
55+
}
56+
4257
bool AdbDevice::talk(const uint8_t dev_addr, const uint8_t reg_num) {
4358
if (dev_addr == this->my_addr && !this->got_collision) {
4459
// see if another device already responded to this command

devices/common/adb/adbdevice.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,10 @@ class AdbDevice : public HWComponent {
4949
virtual void listen(const uint8_t dev_addr, const uint8_t reg_num);
5050
virtual uint8_t get_address() { return this->my_addr; };
5151

52+
// Attempts to oolls the device. Returns the talk command corresponding to
53+
// the device if it has data, 0 otherwise.
54+
uint8_t poll();
55+
5256
protected:
5357
uint8_t gen_random_address();
5458

devices/common/adb/adbkeyboard.cpp

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,20 +34,45 @@ AdbKeyboard::AdbKeyboard(std::string name) : AdbDevice(name) {
3434
}
3535

3636
void AdbKeyboard::event_handler(const KeyboardEvent& event) {
37+
this->key = event.key;
3738
if (event.flags & KEYBOARD_EVENT_DOWN) {
39+
this->key_state = 0;
3840
}
3941
else if (event.flags & KEYBOARD_EVENT_UP) {
42+
this->key_state = 1;
4043
}
44+
this->changed = true;
4145
}
4246

4347
void AdbKeyboard::reset() {
4448
this->my_addr = ADB_ADDR_KBD;
4549
this->dev_handler_id = 2; // Extended ADB keyboard
46-
this->exc_event_flag = 2;
50+
this->exc_event_flag = 1;
4751
this->srq_flag = 1; // enable service requests
52+
this->key = 0;
53+
this->key_state = 0;
54+
this->changed = false;
4855
}
4956

5057
bool AdbKeyboard::get_register_0() {
58+
if (this->changed) {
59+
uint8_t* out_buf = this->host_obj->get_output_buf();
60+
61+
out_buf[0] = (this->key_state << 7) | (this->key & 0x7F);
62+
// It's possible that we get two events before the host polls us, but
63+
// in practice it has not come up. We need to set the key status bit to
64+
// 1 (released), otherwise if we leave it empty, the host will think
65+
// that the a key (code 0) is pressed.
66+
out_buf[1] = 1 << 7;
67+
68+
this->key = 0;
69+
this->key_state = 0;
70+
this->changed = false;
71+
72+
this->host_obj->set_output_count(2);
73+
return true;
74+
}
75+
5176
return false;
5277
}
5378

0 commit comments

Comments
 (0)