Files
QuickLook/QuickLook/Helpers/GlobalKeyboardHook.cs
T
2026-01-06 02:24:42 +08:00

112 lines
3.1 KiB
C#

// Copyright © 2017-2026 QL-Win Contributors
//
// This file is part of QuickLook program.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
using System;
using System.Windows.Forms;
using System.Windows.Input;
using QuickLook.Common.NativeMethods;
using KeyEventArgs = System.Windows.Forms.KeyEventArgs;
using KeyEventHandler = System.Windows.Forms.KeyEventHandler;
namespace QuickLook.Helpers;
internal class GlobalKeyboardHook : IDisposable
{
private static GlobalKeyboardHook _instance;
private User32.KeyboardHookProc _callback;
private nint _hHook = IntPtr.Zero;
protected GlobalKeyboardHook()
{
Hook();
}
public void Dispose()
{
GC.SuppressFinalize(this);
Unhook();
}
internal event KeyEventHandler KeyDown;
internal event KeyEventHandler KeyUp;
internal static GlobalKeyboardHook GetInstance()
{
return _instance ??= new GlobalKeyboardHook();
}
private void Hook()
{
_callback = HookProc;
var hInstance = Kernel32.LoadLibrary("user32.dll");
_hHook = User32.SetWindowsHookEx(User32.WH_KEYBOARD_LL, _callback, hInstance, 0);
}
private void Unhook()
{
if (_callback == null) return;
User32.UnhookWindowsHookEx(_hHook);
_callback = null;
}
private int HookProc(int code, int wParam, ref User32.KeyboardHookStruct lParam)
{
if (code < 0)
return User32.CallNextHookEx(_hHook, code, wParam, ref lParam);
if (IsWindowsKeyPressed())
return User32.CallNextHookEx(_hHook, code, wParam, ref lParam);
var key = (Keys)lParam.vkCode;
key = AddModifiers(key);
var kea = new KeyEventArgs(key);
if (wParam == User32.WM_KEYDOWN || wParam == User32.WM_SYSKEYDOWN)
KeyDown?.Invoke(this, kea);
else if (wParam == User32.WM_KEYUP || wParam == User32.WM_SYSKEYUP)
KeyUp?.Invoke(this, kea);
return kea.Handled ? 1 : User32.CallNextHookEx(_hHook, code, wParam, ref lParam);
}
private bool IsWindowsKeyPressed()
{
return Keyboard.IsKeyDown(Key.LWin) || Keyboard.IsKeyDown(Key.RWin);
}
private Keys AddModifiers(Keys key)
{
//Ctrl
if ((Keyboard.Modifiers & ModifierKeys.Control) != 0) key = key | Keys.Control;
//Shift
if ((Keyboard.Modifiers & ModifierKeys.Shift) != 0) key = key | Keys.Shift;
//Alt
if ((Keyboard.Modifiers & ModifierKeys.Alt) != 0) key = key | Keys.Alt;
return key;
}
}