Release KSwitcher v0.6.65

This commit is contained in:
agrynco committed 2026-11-12 01:18:21 +02:00
1 parent 14f33012a3
commit 8a65e7f7fb
21 files changed
+570 -111

No files matched your search

+56 -23
View File
@@ -733,6 +733,10 @@ Bytes App::lanCommand(const Bytes &command)
return reply;
}
void App::applySettings(const Settings &requested)
{
applySettings(requested, true);
}
void App::applySettings(const Settings &requested, bool validateOcrInstallation)
{
Settings s = requested;
std::set<std::wstring> present, removed(s.snippetTombstones.begin(), s.snippetTombstones.end());
@@ -745,7 +749,7 @@ void App::applySettings(const Settings &requested)
bool autostartChanged = false;
AutoCorrector predictor;
validateSettings(s);
validateTesseract(s);
if (validateOcrInstallation && ocrProfile(s) != ocrProfile(settings)) validateTesseract(s);
if (s.autoCorrect)
{
predictor.configure(std::filesystem::path(executable()).parent_path() / L"dictionaries", s.autoLanguages);
@@ -849,6 +853,8 @@ void App::resetLanInput()
chatSwitchHook = {};
pendingMouseClicks = {};
mouseActions.clear();
mouseWheelTarget = nullptr;
mouseWheelRemainder = 0;
resetInput();
}
void App::resetInput()
@@ -1399,6 +1405,8 @@ LRESULT CALLBACK App::mouseProc(int code, WPARAM wp, LPARAM lp)
auto &app = *current;
const auto &mouse = *reinterpret_cast<const MSLLHOOKSTRUCT *>(lp);
const int button = mouse.flags & LLMHF_INJECTED ? -1 : mouseButton(UINT(wp), HIWORD(mouse.mouseData));
const auto wheelDelta = static_cast<SHORT>(HIWORD(mouse.mouseData));
const int wheel = mouse.flags & LLMHF_INJECTED ? -1 : mouseWheelEvent(UINT(wp), wheelDelta);
const bool down = mouseButtonDown(UINT(wp));
if (button >= 0 && app.mousePresses[button].held)
{
@@ -1430,7 +1438,8 @@ LRESULT CALLBACK App::mouseProc(int code, WPARAM wp, LPARAM lp)
if (app.lanService->takeInputChange()) app.resetLanInput();
if (consumed) return 1;
}
if (button >= 0 && down && !app.settings.mouseBindings.empty() && !app.busy && !app.suspended &&
if (((button >= 0 && down) || mouseEventEnabled(app.settings, wheel)) &&
!app.settings.mouseBindings.empty() && !app.busy && !app.suspended &&
!app.installingUpdate && !app.hotkeyCapture && modifiersReleased())
{
const auto hit = WindowFromPoint(mouse.pt);
@@ -1442,22 +1451,26 @@ LRESULT CALLBACK App::mouseProc(int code, WPARAM wp, LPARAM lp)
const bool shellSurface = target == GetShellWindow() || wcscmp(windowClass, L"Progman") == 0 ||
wcscmp(windowClass, L"WorkerW") == 0 || wcscmp(windowClass, L"Shell_TrayWnd") == 0 ||
wcscmp(windowClass, L"Shell_SecondaryTrayWnd") == 0;
const auto *global = mouseBinding(app.settings, GlobalMouseProfile, button);
const bool globalLaunch = button >= 2 && global && global->type == MouseActionType::Launch &&
const int event = wheel >= 0 ? wheel : button;
const auto *global = mouseBinding(app.settings, GlobalMouseProfile, event);
const bool globalLaunch = event >= 2 && global && global->type == MouseActionType::Launch &&
mouseActionApplies(*global, name);
const bool restricted = ownWindow || shellSurface || name.empty();
const bool testButton = name == L"kswitcher.config" && hit == GetDlgItem(target, 737);
const auto *fallback = restricted ? effectiveMouseAction(app.settings, L"", button, false) : nullptr;
wchar_t targetClass[64]{};
if (ownWindow) GetClassNameW(target, targetClass, std::size(targetClass));
const bool testButton = ownWindow && (hit == GetDlgItem(target, 737) ||
wcscmp(targetClass, L"KSwitcher.AddMouseEvent") == 0);
const auto *fallback = restricted ? effectiveMouseAction(app.settings, L"", event, false) : nullptr;
const auto *restrictedAction = isMouseVolumeAction(fallback) ? fallback : globalLaunch ? global : nullptr;
const bool eligible = target && !testButton && (!restricted || (button >= 2 && restrictedAction)) &&
(button >= 2 || target == GetForegroundWindow());
const bool eligible = target && !testButton && (!restricted || (event >= 2 && restrictedAction)) &&
(event >= 2 || target == GetForegroundWindow());
if (eligible)
{
const bool foreground = target == GetForegroundWindow();
bool singleScoped{}, doubleScoped{};
auto *single = restricted ? restrictedAction :
effectiveMouseAction(app.settings, name, button, foreground, &singleScoped);
auto *doubleClick = !restricted && button < 3 ?
effectiveMouseAction(app.settings, name, event, foreground, &singleScoped);
auto *doubleClick = wheel < 0 && !restricted && button < 3 ?
effectiveMouseAction(app.settings, name, 5 + button, foreground, &doubleScoped) : nullptr;
if (!foreground)
{
@@ -1465,25 +1478,45 @@ LRESULT CALLBACK App::mouseProc(int code, WPARAM wp, LPARAM lp)
if (doubleClick && doubleClick->type == MouseActionType::Shortcut) doubleClick = nullptr;
}
const auto now = GetTickCount64();
auto &pending = app.pendingMouseClicks[button];
const bool second = doubleClick && pending.target == target &&
doubleMouseClick(pending.point, mouse.pt, now - pending.started);
if (second) pending = {};
else if (pending.target) app.queueMouseAction(std::exchange(pending, {}));
const auto *action = second ? doubleClick : single;
if (action || doubleClick)
app.mousePresses[button] = {target, mouse.pt, now, action ? *action : MouseAction{},
true, doubleClick && !second};
if (action)
if (wheel >= 0 && single)
{
if (second ? doubleScoped : singleScoped) app.mousePresses[button].action.applications.insert(name);
if (isMouseVolumeStep(action->type))
app.beginMouseVolume(button);
if (app.mouseWheelTarget != target || app.mouseWheelSignal != wheel)
app.mouseWheelRemainder = 0;
app.mouseWheelTarget = target;
app.mouseWheelSignal = wheel;
const int steps = mouseWheelSteps(app.mouseWheelRemainder, wheelDelta);
for (int i = 0; i < steps; ++i)
app.queueMouseAction({target, mouse.pt, now, *single});
app.resetInput();
return 1;
}
if (wheel < 0)
{
auto &pending = app.pendingMouseClicks[button];
const bool second = doubleClick && pending.target == target &&
doubleMouseClick(pending.point, mouse.pt, now - pending.started);
if (second) pending = {};
else if (pending.target) app.queueMouseAction(std::exchange(pending, {}));
const auto *action = second ? doubleClick : single;
if (action || doubleClick)
app.mousePresses[button] = {target, mouse.pt, now, action ? *action : MouseAction{},
true, doubleClick && !second};
if (action)
{
if (second ? doubleScoped : singleScoped) app.mousePresses[button].action.applications.insert(name);
if (isMouseVolumeStep(action->type))
app.beginMouseVolume(button);
app.resetInput();
return 1;
}
}
}
}
if (wheel >= 0)
{
app.mouseWheelTarget = nullptr;
app.mouseWheelRemainder = 0;
}
// Remote clicks invalidate a typing range just like local clicks.
if (down || wp == WM_MOUSEWHEEL || wp == WM_MOUSEHWHEEL)
{