diff --git a/app/app.pro b/app/app.pro index 0a0855a1..afadc1ca 100644 --- a/app/app.pro +++ b/app/app.pro @@ -136,7 +136,6 @@ SOURCES += \ settings/mappingfetcher.cpp \ settings/streamingpreferences.cpp \ streaming/input/abstouch.cpp \ - streaming/input/clipboard.cpp \ streaming/input/gamepad.cpp \ streaming/input/input.cpp \ streaming/input/keyboard.cpp \ diff --git a/app/streaming/input/clipboard.cpp b/app/streaming/input/clipboard.cpp deleted file mode 100644 index 4851a48e..00000000 --- a/app/streaming/input/clipboard.cpp +++ /dev/null @@ -1,190 +0,0 @@ -#include "input.h" - -#include - -int SdlInputHandler::clipboardThreadProc(void *ptr) -{ - auto me = (SdlInputHandler*)ptr; - - while (!SDL_AtomicGet(&me->m_ShutdownClipboardThread)) { - QString clipboardData; - - SDL_LockMutex(me->m_ClipboardLock); - for (;;) { - clipboardData = me->m_ClipboardData; - me->m_ClipboardData.clear(); - if (!clipboardData.isEmpty() || SDL_AtomicGet(&me->m_ShutdownClipboardThread)) { - break; - } - SDL_CondWait(me->m_ClipboardHasData, me->m_ClipboardLock); - } - SDL_UnlockMutex(me->m_ClipboardLock); - - // We might get here on shutdown, so don't send text if there's - // nothing to send. - if (!clipboardData.isEmpty()) { - me->sendText(clipboardData); - } - } - - return 0; -} - -#define MAP_KEY(c, sc) \ - case c: \ - event.key.keysym.scancode = sc; \ - break - -#define MAP_KEY_SHIFT(c, sc) \ - case c: \ - event.key.keysym.scancode = sc; \ - event.key.keysym.mod = KMOD_SHIFT; \ - break - -void SdlInputHandler::sendText(QString& string) -{ - for (int i = 0; i < string.size(); i++) { - char16_t c = string[i].unicode(); - SDL_Event event = {}; - - // If we're sending a very long string, we might get a termination request - // while we're in the middle of sending a string. In that case, just bail. - if (SDL_AtomicGet(&m_ShutdownClipboardThread)) { - return; - } - - if (c >= 'A' && c <= 'Z') { - event.key.keysym.scancode = (SDL_Scancode)((c - 'A') + SDL_SCANCODE_A); - event.key.keysym.mod = KMOD_SHIFT; - } - else if (c >= 'a' && c <= 'z') { - event.key.keysym.scancode = (SDL_Scancode)((c - 'a') + SDL_SCANCODE_A); - } - else if (c >= '1' && c <= '9') { - event.key.keysym.scancode = (SDL_Scancode)((c - '1') + SDL_SCANCODE_1); - } - else { - // Fixup some Unicode characters to be expressible in ASCII - switch (c) { - case u'\U0000201C': // Left " - case u'\U0000201D': // Right " - c = '"'; - break; - - case u'\U00002018': // Left ' - case u'\U00002019': // Right ' - c = '\''; - break; - - case u'\U00002013': // Smart - - c = '-'; - break; - - case u'\U00002026': // Ellipsis (...) - // Convert this character into 3 periods - string.insert(i+1, '.'); - string.insert(i+1, '.'); - c = '.'; - break; - - case u'\U000000A0': // Non-breaking space - c = ' '; - break; - - default: - // Nothing - break; - } - - - switch (c) { - - // Handle CRLF separately to avoid duplicate newlines - case '\r': - if (string[i + 1] == '\n') { - i++; - } - event.key.keysym.scancode = SDL_SCANCODE_RETURN; - break; - - MAP_KEY('\b', SDL_SCANCODE_BACKSPACE); - MAP_KEY('\n', SDL_SCANCODE_RETURN); - MAP_KEY('\t', SDL_SCANCODE_TAB); - - MAP_KEY(' ', SDL_SCANCODE_SPACE); - MAP_KEY_SHIFT('!', SDL_SCANCODE_1); - MAP_KEY_SHIFT('"', SDL_SCANCODE_APOSTROPHE); - MAP_KEY_SHIFT('#', SDL_SCANCODE_3); - MAP_KEY_SHIFT('$', SDL_SCANCODE_4); - MAP_KEY_SHIFT('%', SDL_SCANCODE_5); - MAP_KEY_SHIFT('&', SDL_SCANCODE_7); - MAP_KEY('\'', SDL_SCANCODE_APOSTROPHE); - MAP_KEY_SHIFT('(', SDL_SCANCODE_9); - MAP_KEY_SHIFT(')', SDL_SCANCODE_0); - MAP_KEY_SHIFT('*', SDL_SCANCODE_8); - MAP_KEY_SHIFT('+', SDL_SCANCODE_EQUALS); - MAP_KEY(',', SDL_SCANCODE_COMMA); - MAP_KEY('-', SDL_SCANCODE_MINUS); - MAP_KEY('.', SDL_SCANCODE_PERIOD); - MAP_KEY('/', SDL_SCANCODE_SLASH); - MAP_KEY('0', SDL_SCANCODE_0); - - MAP_KEY_SHIFT(':', SDL_SCANCODE_SEMICOLON); - MAP_KEY(';', SDL_SCANCODE_SEMICOLON); - MAP_KEY_SHIFT('<', SDL_SCANCODE_COMMA); - MAP_KEY('=', SDL_SCANCODE_EQUALS); - MAP_KEY_SHIFT('>', SDL_SCANCODE_PERIOD); - MAP_KEY_SHIFT('?', SDL_SCANCODE_SLASH); - MAP_KEY_SHIFT('@', SDL_SCANCODE_2); - - MAP_KEY('[', SDL_SCANCODE_LEFTBRACKET); - MAP_KEY('\\', SDL_SCANCODE_BACKSLASH); - MAP_KEY(']', SDL_SCANCODE_RIGHTBRACKET); - MAP_KEY_SHIFT('^', SDL_SCANCODE_6); - MAP_KEY_SHIFT('_', SDL_SCANCODE_MINUS); - MAP_KEY('`', SDL_SCANCODE_GRAVE); - - MAP_KEY_SHIFT('{', SDL_SCANCODE_LEFTBRACKET); - MAP_KEY_SHIFT('|', SDL_SCANCODE_BACKSLASH); - MAP_KEY_SHIFT('}', SDL_SCANCODE_RIGHTBRACKET); - MAP_KEY_SHIFT('~', SDL_SCANCODE_GRAVE); - - default: - SDL_LogWarn(SDL_LOG_CATEGORY_APPLICATION, - "Pasting text - non-ASCII character value 'U+%x' ignored", - c); - continue; - } - } - - if (event.key.keysym.mod & KMOD_SHIFT) { - SDL_Event modifierEvent = {}; - modifierEvent.type = SDL_KEYDOWN; - modifierEvent.key.state = SDL_PRESSED; - modifierEvent.key.keysym.scancode = SDL_SCANCODE_LSHIFT; - handleKeyEvent(&modifierEvent.key); - - SDL_Delay(10); - } - - event.type = SDL_KEYDOWN; - event.key.state = SDL_PRESSED; - handleKeyEvent(&event.key); - - SDL_Delay(10); - - event.type = SDL_KEYUP; - event.key.state = SDL_RELEASED; - handleKeyEvent(&event.key); - - if (event.key.keysym.mod & KMOD_SHIFT) { - SDL_Event modifierEvent = {}; - modifierEvent.type = SDL_KEYUP; - modifierEvent.key.state = SDL_RELEASED; - modifierEvent.key.keysym.scancode = SDL_SCANCODE_LSHIFT; - handleKeyEvent(&modifierEvent.key); - - SDL_Delay(10); - } - } -} diff --git a/app/streaming/input/input.cpp b/app/streaming/input/input.cpp index 01b165cc..3871215f 100644 --- a/app/streaming/input/input.cpp +++ b/app/streaming/input/input.cpp @@ -33,8 +33,7 @@ SdlInputHandler::SdlInputHandler(StreamingPreferences& prefs, NvComputer*, int s m_RightButtonReleaseTimer(0), m_DragTimer(0), m_DragButton(0), - m_NumFingersDown(0), - m_ClipboardData() + m_NumFingersDown(0) { // System keys are always captured when running without a DE if (!WMUtils::isRunningDesktopEnvironment()) { @@ -198,13 +197,6 @@ SdlInputHandler::SdlInputHandler(StreamingPreferences& prefs, NvComputer*, int s } m_MouseMoveTimer = SDL_AddTimer(pollingInterval, SdlInputHandler::mouseMoveTimerCallback, this); - - // Initialize state used by the clipboard thread before we start it - SDL_AtomicSet(&m_ShutdownClipboardThread, 0); - m_ClipboardHasData = SDL_CreateCond(); - m_ClipboardLock = SDL_CreateMutex(); - - m_ClipboardThread = SDL_CreateThread(SdlInputHandler::clipboardThreadProc, "Clipboard Sender", this); } SdlInputHandler::~SdlInputHandler() @@ -230,17 +222,6 @@ SdlInputHandler::~SdlInputHandler() SDL_RemoveTimer(m_RightButtonReleaseTimer); SDL_RemoveTimer(m_DragTimer); - // Wake up the clipboard thread to terminate it - SDL_AtomicSet(&m_ShutdownClipboardThread, 1); - SDL_CondBroadcast(m_ClipboardHasData); - - // Wait for it to terminate - SDL_WaitThread(m_ClipboardThread, nullptr); - - // Now we can safely clean up its resources - SDL_DestroyCond(m_ClipboardHasData); - SDL_DestroyMutex(m_ClipboardLock); - #if !SDL_VERSION_ATLEAST(2, 0, 9) SDL_QuitSubSystem(SDL_INIT_HAPTIC); SDL_assert(!SDL_WasInit(SDL_INIT_HAPTIC)); diff --git a/app/streaming/input/input.h b/app/streaming/input/input.h index c1ba304c..90c92146 100644 --- a/app/streaming/input/input.h +++ b/app/streaming/input/input.h @@ -138,9 +138,6 @@ private: static Uint32 dragTimerCallback(Uint32 interval, void* param); - static - int clipboardThreadProc(void *ptr); - SDL_Window* m_Window; bool m_MultiController; bool m_GamepadMouse; @@ -191,11 +188,5 @@ private: char m_DragButton; int m_NumFingersDown; - SDL_Thread* m_ClipboardThread; - SDL_atomic_t m_ShutdownClipboardThread; - QString m_ClipboardData; - SDL_cond* m_ClipboardHasData; - SDL_mutex* m_ClipboardLock; - static const int k_ButtonMap[]; }; diff --git a/app/streaming/input/keyboard.cpp b/app/streaming/input/keyboard.cpp index 98d9d53f..0b756a7b 100644 --- a/app/streaming/input/keyboard.cpp +++ b/app/streaming/input/keyboard.cpp @@ -101,13 +101,18 @@ void SdlInputHandler::performSpecialKeyCombo(KeyCombo combo) // with the text we're going to type. raiseAllKeys(); - const char* text; + char* text; if (SDL_HasClipboardText() && (text = SDL_GetClipboardText()) != nullptr) { - // Append this data to the clipboard data string for the thread to process - SDL_LockMutex(m_ClipboardLock); - m_ClipboardData.append(text); - SDL_CondSignal(m_ClipboardHasData); - SDL_UnlockMutex(m_ClipboardLock); + // Sending both CR and LF will lead to two newlines in the destination for + // each newline in the source, so we fix up any CRLFs into just a single LF. + for (char* c = text; *c != 0; c++) { + if (*c == '\r' && *(c + 1) == '\n') { + memmove(c, c + 1, strlen(c) - 1); + } + } + + // Send this text to the PC + LiSendUtf8TextEvent(text, strlen(text)); // SDL_GetClipboardText() allocates, so we must free SDL_free((void*)text); @@ -124,8 +129,6 @@ void SdlInputHandler::performSpecialKeyCombo(KeyCombo combo) } } -#define IS_SYNTHETIC_KEY_EVENT(x) ((x)->timestamp == 0) - void SdlInputHandler::handleKeyEvent(SDL_KeyboardEvent* event) { short keyCode; @@ -138,9 +141,7 @@ void SdlInputHandler::handleKeyEvent(SDL_KeyboardEvent* event) } // Check for our special key combos - // Ignore timestamp == 0 which are sent from our keyboard code. - if (!IS_SYNTHETIC_KEY_EVENT(event) && - (event->state == SDL_PRESSED) && + if ((event->state == SDL_PRESSED) && (event->keysym.mod & KMOD_CTRL) && (event->keysym.mod & KMOD_ALT) && (event->keysym.mod & KMOD_SHIFT)) { @@ -403,16 +404,12 @@ void SdlInputHandler::handleKeyEvent(SDL_KeyboardEvent* event) } } - // If this is a synthetic keypress from the clipboard code, - // this will be on a non-main thread, so don't touch m_KeysDown. - if (!IS_SYNTHETIC_KEY_EVENT(event)) { - // Track the key state so we always know which keys are down - if (event->state == SDL_PRESSED) { - m_KeysDown.insert(keyCode); - } - else { - m_KeysDown.remove(keyCode); - } + // Track the key state so we always know which keys are down + if (event->state == SDL_PRESSED) { + m_KeysDown.insert(keyCode); + } + else { + m_KeysDown.remove(keyCode); } LiSendKeyboardEvent(0x8000 | keyCode, diff --git a/moonlight-common-c/moonlight-common-c b/moonlight-common-c/moonlight-common-c index 3b9d8a31..94d439e5 160000 --- a/moonlight-common-c/moonlight-common-c +++ b/moonlight-common-c/moonlight-common-c @@ -1 +1 @@ -Subproject commit 3b9d8a31763be77c921bd2581b5e75f4d40a1b11 +Subproject commit 94d439e5c3aa388a2cf98a26ad1a4be5d7563763