From d8f1cf3cd022cc11c20b979d5ff055d33cfed228 Mon Sep 17 00:00:00 2001 From: loki Date: Fri, 6 Dec 2019 16:33:13 +0100 Subject: [PATCH] Emulate an xbox 360 controller --- input.cpp | 52 ++++++++++----- input.h | 2 +- platform/common.h | 29 ++++---- platform/linux.cpp | 162 --------------------------------------------- stream.cpp | 6 +- 5 files changed, 56 insertions(+), 195 deletions(-) diff --git a/input.cpp b/input.cpp index 6f2ff7d6..fb3c14d5 100644 --- a/input.cpp +++ b/input.cpp @@ -6,6 +6,7 @@ extern "C" { #include } +#include #include #include "input.h" @@ -95,48 +96,69 @@ void print(void *input) { } } -void passthrough(platf::display_t::element_type *display, PNV_MOUSE_MOVE_PACKET packet) { - platf::move_mouse(display, util::endian::big(packet->deltaX), util::endian::big(packet->deltaY)); +void passthrough(platf::input_t &input, PNV_MOUSE_MOVE_PACKET packet) { + platf::move_mouse(input, util::endian::big(packet->deltaX), util::endian::big(packet->deltaY)); } -void passthrough(platf::display_t::element_type *display, PNV_MOUSE_BUTTON_PACKET packet) { +void passthrough(platf::input_t &input, PNV_MOUSE_BUTTON_PACKET packet) { auto constexpr BUTTON_RELEASED = 0x09; - platf::button_mouse(display, util::endian::big(packet->button), packet->action == BUTTON_RELEASED); + platf::button_mouse(input, util::endian::big(packet->button), packet->action == BUTTON_RELEASED); } -void passthrough(platf::display_t::element_type *display, PNV_KEYBOARD_PACKET packet) { +void passthrough(platf::input_t &input, PNV_KEYBOARD_PACKET packet) { auto constexpr BUTTON_RELEASED = 0x04; - platf::keyboard(display, packet->keyCode & 0x00FF, packet->keyAction == BUTTON_RELEASED); + platf::keyboard(input, packet->keyCode & 0x00FF, packet->keyAction == BUTTON_RELEASED); } -void passthrough(platf::display_t::element_type *display, PNV_SCROLL_PACKET packet) { - platf::scroll(display, util::endian::big(packet->scrollAmt1)); +void passthrough(platf::input_t &input, PNV_SCROLL_PACKET packet) { + platf::scroll(input, util::endian::big(packet->scrollAmt1)); } -void passthrough(platf::display_t::element_type *display, void *input) { - int input_type = util::endian::big(*(int*)input); +void passthrough(platf::input_t &input, PNV_MULTI_CONTROLLER_PACKET packet) { + std::uint16_t bf; + + static_assert(sizeof(bf) == sizeof(packet->buttonFlags), "Can't memcpy :("); + std::memcpy(&bf, &packet->buttonFlags, sizeof(std::uint16_t)); + platf::gamepad_state_t gamepad_state { + bf, + packet->leftTrigger, + packet->rightTrigger, + packet->leftStickX, + packet->leftStickY, + packet->rightStickX, + packet->rightStickY + }; + + platf::gamepad(input, gamepad_state); +} + +void passthrough(platf::input_t &input, void *payload) { + int input_type = util::endian::big(*(int*)payload); switch(input_type) { case PACKET_TYPE_MOUSE_MOVE: - passthrough(display, (PNV_MOUSE_MOVE_PACKET)input); + passthrough(input, (PNV_MOUSE_MOVE_PACKET)payload); break; case PACKET_TYPE_MOUSE_BUTTON: - passthrough(display, (PNV_MOUSE_BUTTON_PACKET)input); + passthrough(input, (PNV_MOUSE_BUTTON_PACKET)payload); break; case PACKET_TYPE_SCROLL_OR_KEYBOARD: { - char *tmp_input = (char*)input + 4; + char *tmp_input = (char*)payload + 4; if(tmp_input[0] == 0x0A) { - passthrough(display, (PNV_SCROLL_PACKET)input); + passthrough(input, (PNV_SCROLL_PACKET)payload); } else { - passthrough(display, (PNV_KEYBOARD_PACKET)input); + passthrough(input, (PNV_KEYBOARD_PACKET)payload); } break; } + case PACKET_TYPE_MULTI_CONTROLLER: + passthrough(input, (PNV_MULTI_CONTROLLER_PACKET)payload); + break; } } } diff --git a/input.h b/input.h index 3232477e..0e66bc5b 100644 --- a/input.h +++ b/input.h @@ -10,7 +10,7 @@ namespace input { void print(void *input); -void passthrough(platf::display_t::element_type *display, void *input); +void passthrough(platf::input_t &, void *input); } #endif //SUNSHINE_INPUT_H diff --git a/platform/common.h b/platform/common.h index e8e4f5d3..92c1180f 100644 --- a/platform/common.h +++ b/platform/common.h @@ -14,42 +14,43 @@ void freeDisplay(void*); void freeImage(void*); void freeAudio(void*); void freeMic(void*); -void freeGamePad(void*); +void freeInput(void*); using display_t = util::safe_ptr; using img_t = util::safe_ptr; using mic_t = util::safe_ptr; using audio_t = util::safe_ptr; -using gamepad_t = util::safe_ptr; +using input_t = util::safe_ptr; struct gamepad_state_t { std::uint16_t buttonFlags; std::uint8_t lt; std::uint8_t rt; - std::uint16_t lsX; - std::uint16_t lsY; - std::uint16_t rsX; - std::uint16_t rsY; + std::int16_t lsX; + std::int16_t lsY; + std::int16_t rsX; + std::int16_t rsY; }; std::string get_local_ip(); -display_t display(); -img_t snapshot(display_t &display); + mic_t microphone(); audio_t audio(mic_t &mic, std::uint32_t sample_size); -gamepad_t gamepad(); +display_t display(); +img_t snapshot(display_t &display); int32_t img_width(img_t &); int32_t img_height(img_t &); uint8_t *img_data(img_t &); int16_t *audio_data(audio_t &); -void move_mouse(display_t::element_type *display, int deltaX, int deltaY); -void button_mouse(display_t::element_type *display, int button, bool release); -void scroll(display_t::element_type *display, int distance); -void keyboard(display_t::element_type *display, uint16_t modcode, bool release); -void gamepad_event(gamepad_t &gamepad, const gamepad_state_t &gamepad_state); +input_t input(); +void move_mouse(input_t &input, int deltaX, int deltaY); +void button_mouse(input_t &input, int button, bool release); +void scroll(input_t &input, int distance); +void keyboard(input_t &input, uint16_t modcode, bool release); +void gamepad(input_t &input, const gamepad_state_t &gamepad_state); } #endif //SUNSHINE_COMMON_H diff --git a/platform/linux.cpp b/platform/linux.cpp index b0b2657b..07b454d3 100644 --- a/platform/linux.cpp +++ b/platform/linux.cpp @@ -13,7 +13,6 @@ #include #include #include -#include #include #include @@ -202,167 +201,6 @@ std::int16_t *audio_data(audio_t &audio) { return (int16_t*)audio.get(); } - -void move_mouse(display_t::element_type *display, int deltaX, int deltaY) { - auto &disp = *((display_attr_t*)display); - - XWarpPointer(disp.display, None, None, 0, 0, 0, 0, deltaX, deltaY); - XFlush(disp.display); -} - -void button_mouse(display_t::element_type *display, int button, bool release) { - auto &disp = *((display_attr_t *) display); - - XTestFakeButtonEvent(disp.display, button, !release, CurrentTime); - - XFlush(disp.display); -} - -void scroll(display_t::element_type *display, int distance) { - auto &disp = *((display_attr_t *) display); - - int button = distance > 0 ? 4 : 5; - - distance = std::abs(distance / 120); - while(distance > 0) { - --distance; - - XTestFakeButtonEvent(disp.display, button, True, CurrentTime); - XTestFakeButtonEvent(disp.display, button, False, CurrentTime); - - XSync(disp.display, 0); - } - - XFlush(disp.display); -} - -uint16_t keysym(uint16_t modcode) { - constexpr auto VK_NUMPAD = 0x60; - constexpr auto VK_F1 = 0x70; - - if(modcode >= VK_NUMPAD && modcode < VK_NUMPAD + 10) { - return XK_KP_0 + (modcode - VK_NUMPAD); - } - - if(modcode >= VK_F1 && modcode < VK_F1 + 13) { - return XK_F1 + (modcode - VK_F1); - } - - - switch(modcode) { - case 0x08: - return XK_BackSpace; - case 0x09: - return XK_Tab; - case 0x0D: - return XK_Return; - case 0x13: - return XK_Pause; - case 0x14: - return XK_Caps_Lock; - case 0x1B: - return XK_Escape; - case 0x21: - return XK_Page_Up; - case 0x22: - return XK_Page_Down; - case 0x23: - return XK_End; - case 0x24: - return XK_Home; - case 0x25: - return XK_Left; - case 0x26: - return XK_Up; - case 0x27: - return XK_Right; - case 0x28: - return XK_Down; - case 0x29: - return XK_Select; - case 0x2B: - return XK_Execute; - case 0x2C: - return XK_Print; //FIXME: is this correct? (printscreen) - case 0x2D: - return XK_Insert; - case 0x2E: - return XK_Delete; - case 0x2F: - return XK_Help; - case 0x6A: - return XK_KP_Multiply; - case 0x6B: - return XK_KP_Add; - case 0x6C: - return XK_KP_Decimal; //FIXME: is this correct? (Comma) - case 0x6D: - return XK_KP_Subtract; - case 0x6E: - return XK_KP_Separator; //FIXME: is this correct? (Period) - case 0x6F: - return XK_KP_Divide; - case 0x90: - return XK_Num_Lock; //FIXME: is this correct: (NumlockClear) - case 0x91: - return XK_Scroll_Lock; - case 0xA0: - return XK_Shift_L; - case 0xA1: - return XK_Shift_R; - case 0xA2: - return XK_Control_L; - case 0xA3: - return XK_Control_R; - case 0xA4: - return XK_Alt_L; - case 0xA5: /* return XK_Alt_R; */ - return XK_Super_L; - case 0xBA: - return XK_semicolon; - case 0xBB: - return XK_equal; - case 0xBC: - return XK_comma; - case 0xBD: - return XK_minus; - case 0xBE: - return XK_period; - case 0xBF: - return XK_slash; - case 0xC0: - return XK_grave; - case 0xDB: - return XK_bracketleft; - case 0xDC: - return XK_backslash; - case 0xDD: - return XK_bracketright; - case 0xDE: - return XK_apostrophe; - case 0x01: //FIXME: Moonlight doesn't support Super key - return XK_Super_L; - case 0x02: - return XK_Super_R; - } - - return modcode; -} - -void keyboard(display_t::element_type *display, uint16_t modcode, bool release) { - auto &disp = *((display_attr_t *) display); - KeyCode kc = XKeysymToKeycode(disp.display, keysym(modcode)); - - if(!kc) { - return; - } - - XTestFakeKeyEvent(disp.display, kc, !release, 0); - - XSync(disp.display, 0); - XFlush(disp.display); -} - void freeDisplay(void*p) { delete (display_attr_t*)p; } diff --git a/stream.cpp b/stream.cpp index 812ff8af..39724a13 100644 --- a/stream.cpp +++ b/stream.cpp @@ -376,7 +376,7 @@ void server_t::map(uint16_t type, std::function void controlThread() { server_t server { CONTROL_PORT }; - std::shared_ptr display = platf::display(); + auto input = platf::input(); server.map(packetTypes[IDX_START_A], [](const std::string_view &payload) { session.pingTimeout = std::chrono::steady_clock::now() + config::stream.ping_timeout; @@ -420,7 +420,7 @@ void controlThread() { std::cout << "lastFrame [" << lastFrame << ']' << std::endl; }); - server.map(packetTypes[IDX_INPUT_DATA], [display](const std::string_view &payload) mutable { + server.map(packetTypes[IDX_INPUT_DATA], [&input](const std::string_view &payload) mutable { session.pingTimeout = std::chrono::steady_clock::now() + config::stream.ping_timeout; std::cout << "type [IDX_INPUT_DATA]"sv << std::endl; @@ -444,7 +444,7 @@ void controlThread() { } input::print(plaintext.data()); - input::passthrough(display.get(), plaintext.data()); + input::passthrough(input, plaintext.data()); }); while(session.client_state > 0) {