#pragma once #include "autocorrect.h" #include "storage.h" #include "update.h" #include "sync.h" #include #include #include #include #include #include namespace ks { inline constexpr UINT TrayMessage = WM_APP + 1, ErrorMessage = WM_APP + 2, HistoryMessage = WM_APP + 3, SnippetMessage = WM_APP + 4; inline constexpr int Toggle = 1, Case = 2, Translit = 3, Undo = 4, ShowHistory = 5, AutoCorrect = 6, Screenshot = 7, Direct = 100; inline constexpr UINT AutoCorrectMessage = WM_APP + 6; inline constexpr UINT ReplayTypingMessage = WM_APP + 30; inline constexpr UINT CaptureHotkeyMessage = WM_APP + 5; struct LastTransform { HWND window{}; std::wstring original, result; int layout = -1; ULONGLONG at{}; uint64_t version{}; int sourceLayout = -1; bool autoCorrected = false; }; class App { public: HWND window{}, historyWindow{}, settingsWindow{}, snippetsWindow{}; HWND historyService{}; // Non-null only in the short-lived history UI process. bool isolateHistory{}; unsigned historyEntryWindows{}; std::wstring historySelection, historyTop, historyQuery; bool historyPinnedOnly{}; HINSTANCE instance{}; std::filesystem::path data; std::vector layouts; Settings settings; std::unique_ptr history; AutoCorrector autoCorrector; AutoCorrector autoPredictor; // Preloaded, hook-thread-only lookup; no file access while typing. std::atomic busy{false}, suspended{false}; std::atomic ownSequence{0}; std::atomic inputVersion{0}; std::atomic pauseUntil{0}; HWND pasteTarget{}; HWND hotkeyCapture{}; DWORD hotkeyCaptureProcess{}; HWND logWindow{}; std::mutex stateMutex; Run run; std::optional last; std::wstring registrationWarning; bool smoke{}; int startCommand{}; std::wstring updateStartupEvent; App(HINSTANCE, bool = false, const std::filesystem::path &dataRoot = {}, HWND historyService = nullptr); ~App(); int execute(); void dispatch(int); void transform(int, int snippet = -1); void pasteEntry(std::wstring, bool plain); void recognizeEntry(std::wstring); void captureHistory(); void enqueue(std::function); void enqueueHistorySearch(std::function); void report(const std::wstring &); void trayMenu(); void addTray(); bool registerHotkeys(const Settings &, bool rollback = false); void applySettings(const Settings &); void reloadLayouts(); void clearHistory(); void openHistoryProcess(); void refreshHistoryProcess(); void remoteHistory(const char *action, const std::wstring &id = {}, bool plain = false); LRESULT historyRequest(HWND, const COPYDATASTRUCT &); void saveHistoryView(const std::wstring &, const std::wstring &, const std::wstring &, bool); void clearLog(bool previous); void setHotkeyCapture(HWND); bool isHotkey(DWORD, UINT); void keyboard(const KBDLLHOOKSTRUCT &, UINT modifiers); bool handleKeyboard(const KBDLLHOOKSTRUCT &, bool down, UINT modifiers); void resetInput(); void checkUpdate(bool interactive, bool install = false, const std::wstring &version = {}); std::wstring syncCommand(int action = 0, const std::vector &choices = {}); Bytes syncConflictData(); void pollSync(); static App *current; private: friend struct InputRegressionAccess; void releaseIdleMemory(ULONGLONG now); HHOOK keyboardHook{}, mouseHook{}; HANDLE historyProcess{}; std::mutex jobsMutex; std::condition_variable jobsReady; std::deque> jobs; std::thread worker; HANDLE notificationRegistration{}; std::thread historySearchWorker; std::condition_variable historySearchReady; std::function pendingHistorySearch; std::thread historyOcrWorker; std::condition_variable historyOcrReady; bool historyOcrRequested{}; Settings historyOcrSettings; void scheduleHistoryOcr(const Settings &); std::thread updateWorker; std::thread syncWorker; std::atomic syncDone{false}; bool syncRunning{}; ULONGLONG nextSync{}, syncRetryAfter{}; SyncResult syncResult; SyncConfig syncConnection; SyncConfig conflictConnection; std::vector pendingSyncConflicts; Bytes syncSnapshot; std::wstring syncStatus = L"Not connected."; bool updateRunning{}, installingUpdate{}; std::wstring availableUpdate, notifiedUpdate; bool (*updateNotifier)(const std::wstring &){}; bool stop{}; UINT taskbarCreated{}; uint64_t transformAttempt{}, previousAttemptVersion{}; ULONGLONG previousAttemptAt{}; HWND previousAttemptWindow{}; int previousAttemptCommand{}, repeatAttempts{}; std::vector> hookBindings; HotkeyHook hotkeyHook; HWND typingTarget{}; bool autoPending{}; int snippetPending = -1; bool snippetTyping{}; std::vector deferredTyping; bool beginTypingDeferral(HWND, uint64_t, bool snippet = false); void replayTyping(); static LRESULT CALLBACK windowProc(HWND, UINT, WPARAM, LPARAM); static LRESULT CALLBACK keyProc(int, WPARAM, LPARAM); static LRESULT CALLBACK mouseProc(int, WPARAM, LPARAM); }; void showHistory(App &, bool visible = true); void launchScreenshot(App &); void launchScreenshotEditor(App &, const Clip &); void refreshHistory(App &); void showSettings(App &, bool visible = true); void showLogs(App &); void showSnippets(App &); void showShortcuts(App &); void showEntry(App &, const std::wstring &); } // namespace ks