Files
msime-windows/server/src/window/window_hook.cpp
T

183 lines
5.1 KiB
C++

#include "window_hook.h"
#include "config/ime_config.h"
#include "ime_windows.h"
#include "settings/settings_launcher.h"
#include "utils/webview_utils.h"
#include "defines/globals.h"
#include "defines/defines.h"
#include <fmt/xchar.h>
#include <winuser.h>
void OnWinEvent(HWND hwnd);
bool IsKeyPressed(int vk)
{
return (GetAsyncKeyState(vk) & 0x8000) != 0;
}
LRESULT CALLBACK LowLevelKeyboardProc(int nCode, WPARAM wParam, LPARAM lParam)
{
if (nCode == HC_ACTION && wParam == WM_KEYDOWN)
{
KBDLLHOOKSTRUCT *p = (KBDLLHOOKSTRUCT *)lParam;
bool ctrl = IsKeyPressed(VK_CONTROL);
bool alt = IsKeyPressed(VK_MENU);
bool shift = IsKeyPressed(VK_SHIFT);
// Ctrl + Shift + Alt + K opens the standalone screen keyboard. Consume the
// shortcut so the foreground application does not receive a stray K.
if (ctrl && shift && alt && p->vkCode == 'K')
{
OpenKeyboardPanelApplication();
return 1;
}
//
// Ctrl + Shift + Alt + T to terminate
//
if (ctrl && shift && alt && p->vkCode == 'T')
{
CloseSettingsApplication();
CloseEmojiPanelApplication();
CloseKeyboardPanelApplication();
ExitProcess(0);
}
//
// Ctrl + Shift + Alt + R to restart
//
if (ctrl && shift && alt && p->vkCode == 'R')
{
UnhookWindowsHookEx(g_hHook);
wchar_t path[MAX_PATH];
GetModuleFileNameW(NULL, path, MAX_PATH);
// 即便没有参数,也必须给 command line
auto cmd = fmt::format(L"\"{}\"", path);
STARTUPINFOW si = {sizeof(si)};
PROCESS_INFORMATION pi = {};
// lpApplicationName 用 path
// lpCommandLine 用 cmd.data()
if (CreateProcessW(path, // 可执行路径
cmd.data(), // 必须是可写的 command line
NULL, //
NULL, //
FALSE, //
0, //
NULL, //
NULL, //
&si, //
&pi))
{
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
ExitProcess(0);
}
}
//
// Ctrl + Shift + Alt + C to clear ime engine cache
//
if (ctrl && shift && alt && p->vkCode == 'C')
{
PostMessage(::global_hwnd, WM_CLEAR_IME_ENGINE_CACHE, 0, 0);
}
//
// Ctrl + Alt + Shift + 1-8 to delete candidate
//
if (!::is_global_wnd_cand_shown)
{
return CallNextHookEx(g_hHook, nCode, wParam, lParam);
}
if (ctrl && alt && shift)
{
// 只处理主键盘数字
int idx = -1;
if (p->vkCode >= '1' && p->vkCode <= '8')
idx = p->vkCode - '1';
if (idx >= 0)
{
// 执行候选项删除逻辑,PostMessage 给窗口过程去执行
#ifdef FANY_DEBUG
OutputDebugString(fmt::format(L"[msime]: To delete candidate {}", idx + 1).c_str());
#endif
PostMessage(::global_hwnd, WM_DELETE_CANDIDATE, idx + 1, 0);
}
}
}
// 放行其他程序
return CallNextHookEx(g_hHook, nCode, wParam, lParam);
}
LRESULT CALLBACK LowLevelMouseProc(int nCode, WPARAM wParam, LPARAM lParam)
{
if (nCode >= 0)
{
if (wParam == WM_LBUTTONDOWN || wParam == WM_RBUTTONDOWN)
{
MSLLHOOKSTRUCT *p = (MSLLHOOKSTRUCT *)lParam;
POINT pt = p->pt;
RECT rc;
GetWindowRect(global_hwnd_menu, &rc);
if (!PtInRect(&rc, pt))
{
ShowWindow(global_hwnd_menu, SW_HIDE);
UnhookWindowsHookEx(g_mouseHook);
g_mouseHook = nullptr;
}
}
}
return CallNextHookEx(g_mouseHook, nCode, wParam, lParam);
}
void CALLBACK WinEventProc(HWINEVENTHOOK, DWORD event, HWND hwnd, LONG idObject, LONG, DWORD, DWORD)
{
if (idObject != OBJID_WINDOW || !hwnd)
return;
if (event == EVENT_OBJECT_LOCATIONCHANGE || event == EVENT_SYSTEM_FOREGROUND)
{
OnWinEvent(hwnd);
}
}
static bool g_isHiddenDueToFullscreen = false;
void OnWinEvent(HWND hwnd)
{
if (!IsWindow(hwnd) || !IsWindowVisible(hwnd))
return;
hwnd = GetForegroundWindow();
bool nowFullscreen = CheckFullscreen(hwnd);
// bool wasFullscreen = g_fullscreen_states[hwnd];
if (nowFullscreen)
{
if (IsWindowVisible(::global_hwnd_ftb))
{
ShowWindow(::global_hwnd_ftb, SW_HIDE);
g_isHiddenDueToFullscreen = true;
}
}
else
{
if (g_isHiddenDueToFullscreen)
{
ApplyConfiguredFloatingToolbarVisibility();
g_isHiddenDueToFullscreen = false;
}
}
// g_fullscreen_states[hwnd] = nowFullscreen;
}