diff --git a/core/hostevents_sdl.cpp b/core/hostevents_sdl.cpp index 1f245d0..2c049af 100644 --- a/core/hostevents_sdl.cpp +++ b/core/hostevents_sdl.cpp @@ -22,10 +22,14 @@ along with this program. If not, see . #include #include #include +#include +#include #include 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: - key_downs++; - break; - - case SDL_KEYUP: - key_ups++; + 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++; + } 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; +} diff --git a/devices/common/adb/adbbus.cpp b/devices/common/adb/adbbus.cpp index c67a379..be94dfa 100644 --- a/devices/common/adb/adbbus.cpp +++ b/devices/common/adb/adbbus.cpp @@ -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; diff --git a/devices/common/adb/adbbus.h b/devices/common/adb/adbbus.h index baa91eb..6af3757 100644 --- a/devices/common/adb/adbbus.h +++ b/devices/common/adb/adbbus.h @@ -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; }; diff --git a/devices/common/adb/adbdevice.cpp b/devices/common/adb/adbdevice.cpp index 281322a..da8cdf8 100644 --- a/devices/common/adb/adbdevice.cpp +++ b/devices/common/adb/adbdevice.cpp @@ -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 diff --git a/devices/common/adb/adbdevice.h b/devices/common/adb/adbdevice.h index e015266..d7a506b 100644 --- a/devices/common/adb/adbdevice.h +++ b/devices/common/adb/adbdevice.h @@ -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(); diff --git a/devices/common/adb/adbkeyboard.cpp b/devices/common/adb/adbkeyboard.cpp index 53e008e..f401ed7 100644 --- a/devices/common/adb/adbkeyboard.cpp +++ b/devices/common/adb/adbkeyboard.cpp @@ -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; } diff --git a/devices/common/adb/adbkeyboard.h b/devices/common/adb/adbkeyboard.h index c68201f..f0f5c8a 100644 --- a/devices/common/adb/adbkeyboard.h +++ b/devices/common/adb/adbkeyboard.h @@ -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 diff --git a/devices/common/viacuda.cpp b/devices/common/viacuda.cpp index da91f32..ff2f681 100644 --- a/devices/common/viacuda.cpp +++ b/devices/common/viacuda.cpp @@ -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;