diff --git a/LunaTranslator/LunaTranslator/textsource/copyboard.py b/LunaTranslator/LunaTranslator/textsource/copyboard.py index 1c1220d5..12ff1955 100644 --- a/LunaTranslator/LunaTranslator/textsource/copyboard.py +++ b/LunaTranslator/LunaTranslator/textsource/copyboard.py @@ -1,30 +1,29 @@ import time from textsource.textsourcebase import basetext from myutils.config import globalconfig -import winsharedutils, os +import winsharedutils, os, queue import windows class copyboard(basetext): - def __init__(self) -> None: - self.last_paste_str = "" + def end(self): + winsharedutils.clipboard_callback_stop(self.__hwnd) + super().end() + + def __callback(self, string, ismy): + if globalconfig["excule_from_self"] and ismy: + return + return self.__queue.put(string) + + def __init__(self) -> None: + self.__ref = winsharedutils.clipboard_callback_type(self.__callback) + self.__hwnd = winsharedutils.clipboard_callback(self.__ref) + self.__queue = queue.Queue() super(copyboard, self).__init__("0", "copy") def gettextthread(self): - - time.sleep(0.1) - paste_str = winsharedutils.clipboard_get() - - if self.last_paste_str != paste_str: - self.last_paste_str = paste_str - if ( - globalconfig["excule_from_self"] - and windows.GetWindowThreadProcessId(windows.GetClipboardOwner()) - == os.getpid() - ): - return - return paste_str + return self.__queue.get() def gettextonce(self): return winsharedutils.clipboard_get() diff --git a/LunaTranslator/LunaTranslator/winsharedutils.py b/LunaTranslator/LunaTranslator/winsharedutils.py index 99866a5e..ddfd1df2 100644 --- a/LunaTranslator/LunaTranslator/winsharedutils.py +++ b/LunaTranslator/LunaTranslator/winsharedutils.py @@ -409,3 +409,10 @@ get_ZoomFactor.argtypes = (c_void_p,) get_ZoomFactor.restype = c_double put_ZoomFactor = utilsdll.put_ZoomFactor put_ZoomFactor.argtypes = c_void_p, c_double + +clipboard_callback = utilsdll.clipboard_callback +clipboard_callback.argtypes = (c_void_p,) +clipboard_callback.restype = HWND +clipboard_callback_stop = utilsdll.clipboard_callback_stop +clipboard_callback_stop.argtypes = (HWND,) +clipboard_callback_type = CFUNCTYPE(None, c_wchar_p, c_bool) diff --git a/plugins/CMakeLists.txt b/plugins/CMakeLists.txt index f07df090..5a0e29f1 100644 --- a/plugins/CMakeLists.txt +++ b/plugins/CMakeLists.txt @@ -29,7 +29,7 @@ include(generate_product_version) set(VERSION_MAJOR 3) set(VERSION_MINOR 2) -set(VERSION_PATCH 2) +set(VERSION_PATCH 3) add_library(pch pch.cpp) target_precompile_headers(pch PUBLIC pch.h) diff --git a/plugins/winsharedutils/clipboard.cpp b/plugins/winsharedutils/clipboard.cpp index b6250d82..ac41455e 100644 --- a/plugins/winsharedutils/clipboard.cpp +++ b/plugins/winsharedutils/clipboard.cpp @@ -64,4 +64,69 @@ bool clipboard_set(HWND hwnd, wchar_t *text) } while (false); CloseClipboard(); return success; -} \ No newline at end of file +} + +static void clipboard_callback_1(void (*callback)(wchar_t *, bool), HANDLE hsema, HWND *hwnd) +{ + const wchar_t CLASS_NAME[] = L"LunaClipboardListener"; + + WNDCLASS wc = {}; + wc.lpfnWndProc = [](HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) + { + if (WM_CLIPBOARDUPDATE == message) + { + auto data = clipboard_get(); + auto callback_ = reinterpret_cast(GetWindowLongPtrW(hWnd, GWLP_USERDATA)); + if (data && callback_) + { + auto ohwnd = GetClipboardOwner(); + DWORD pid; + GetWindowThreadProcessId(ohwnd, &pid); + callback_(data, pid == GetCurrentProcessId()); + delete data; + } + } + return DefWindowProc(hWnd, message, wParam, lParam); + }; + wc.hInstance = GetModuleHandle(0); + wc.lpszClassName = CLASS_NAME; + + static auto _ = RegisterClass(&wc); + HWND hWnd = CreateWindowEx( + WS_EX_CLIENTEDGE, CLASS_NAME, CLASS_NAME, WS_OVERLAPPEDWINDOW, + 0, 0, 0, 0, + NULL, NULL, GetModuleHandle(0), 0); + + SetWindowLongPtrW(hWnd, GWLP_USERDATA, (LONG_PTR)callback); + + *hwnd = hWnd; + ReleaseSemaphore(hsema, 1, 0); + MSG msg = {}; + while (GetMessage(&msg, NULL, 0, 0)) + { + TranslateMessage(&msg); + DispatchMessage(&msg); + } +} + +DECLARE HWND clipboard_callback(void (*callback)(wchar_t *, bool)) +{ + HANDLE hsema = CreateSemaphoreW(0, 0, 10, 0); + HWND hwnd; + + std::thread(std::bind(clipboard_callback_1, callback, hsema, &hwnd)).detach(); + + WaitForSingleObject(hsema, INFINITE); + CloseHandle(hsema); + if (AddClipboardFormatListener(hwnd)) + return hwnd; + else + return NULL; +} +DECLARE void clipboard_callback_stop(HWND hwnd) +{ + if (!hwnd) + return; + RemoveClipboardFormatListener(hwnd); + DestroyWindow(hwnd); +}