本文經原作者授權以原創方式二次分享,歡迎轉載、分享。
原文作者:唐宋元明清
原文地址:https://www.cnblogs.com/kybs0/p/12558056.html
?C# 禁用 全局快捷鍵
給軟件添加快捷鍵時,經常遇到其它軟件或者系統已設置的快捷鍵,導致功能沖突。
HotKey函數
下面介紹一個
user32.dll
的RegisterHotKey
以及UnregisterHotKey
熱鍵處理的函數;注冊熱鍵 RegisterHotKey function [1];
BOOL?RegisterHotKey(HWND?hWnd,?//響應熱鍵的窗口句柄,如果為空,則注冊到調用線程上Int?id,?//熱鍵的唯一標識UINT?fsModifiers,?//熱鍵的輔助按鍵UINT?vk?//熱鍵的鍵值
);
解除注冊熱鍵UnregisterHotKey function [2];
BOOL?WINAPI?UnregisterHotKey(?HWND?hWnd,//熱鍵注冊的窗口?int??id//要解除注冊的熱鍵ID?
);
添加熱鍵注冊和注銷函數
Register
方法 - ?注冊user32.dll
函數RegisterHotKey
以禁用全局鍵,并在緩存內添加禁用記錄;
ProcessHotKey
方法 - 外界全局鍵調用時,調用回調函數;
public?class?HotKeys{#region?注冊快捷鍵///?<summary>///?注冊快捷鍵///?</summary>///?<param?name="modifiers"></param>///?<param?name="key"></param>public?void?Register(int?modifiers,?Keys?key){Register(IntPtr.Zero,?modifiers,?key);}///?<summary>///?注冊快捷鍵///?</summary>///?<param?name="hWnd"></param>///?<param?name="modifiers"></param>///?<param?name="key"></param>///?<param?name="callBack"></param>public?void?Register(IntPtr?hWnd,?int?modifiers,?Keys?key,?HotKeyCallBackHanlder?callBack?=?null){var?registerRecord?=?_hotkeyRegisterRecords.FirstOrDefault(i?=>?i.IntPtr?==?hWnd?&&?i.Modifiers?==?modifiers?&&?i.Key?==?key);if?(registerRecord?!=?null){UnregisterHotKey(hWnd,?registerRecord.Id);_hotkeyRegisterRecords.Remove(registerRecord);}int?id?=?registerId++;if?(!RegisterHotKey(hWnd,?id,?modifiers,?key))throw?new?Exception("注冊失敗!");_hotkeyRegisterRecords.Add(new?HotkeyRegisterRecord(){Id?=?id,IntPtr?=?hWnd,Modifiers?=?modifiers,Key?=?key,CallBack?=?callBack});}#endregion#region?注銷快捷鍵///?<summary>///?注銷快捷鍵///?</summary>///?<param?name="hWnd"></param>///?<param?name="modifiers"></param>///?<param?name="key"></param>public?void?UnRegister(IntPtr?hWnd,?int?modifiers,?Keys?key){var?registerRecord?=?_hotkeyRegisterRecords.FirstOrDefault(i?=>?i.IntPtr?==?hWnd?&&?i.Modifiers?==?modifiers?&&?i.Key?==?key);if?(registerRecord?!=?null){UnregisterHotKey(hWnd,?registerRecord.Id);_hotkeyRegisterRecords.Remove(registerRecord);}}///?<summary>///?注銷快捷鍵///?</summary>///?<param?name="modifiers"></param>///?<param?name="key"></param>public?void?UnRegister(int?modifiers,?Keys?key){var?registerRecord?=?_hotkeyRegisterRecords.FirstOrDefault(i?=>?i.IntPtr?==?IntPtr.Zero?&&?i.Modifiers?==?modifiers?&&?i.Key?==?key);if?(registerRecord?!=?null){UnregisterHotKey(IntPtr.Zero,?registerRecord.Id);_hotkeyRegisterRecords.Remove(registerRecord);}}///?<summary>///?注銷快捷鍵///?</summary>///?<param?name="hWnd"></param>public?void?UnRegister(IntPtr?hWnd){var?registerRecords?=?_hotkeyRegisterRecords.Where(i?=>?i.IntPtr?==?hWnd);//注銷所有foreach?(var?registerRecord?in?registerRecords){UnregisterHotKey(hWnd,?registerRecord.Id);_hotkeyRegisterRecords.Remove(registerRecord);}}#endregion#region?快捷鍵消息處理//?快捷鍵消息處理public?void?ProcessHotKey(Message?message){ProcessHotKey(message.Msg,?message.WParam);}///?<summary>///?快捷鍵消息處理///?</summary>///?<param?name="msg"></param>///?<param?name="wParam">消息Id</param>public?void?ProcessHotKey(int?msg,?IntPtr?wParam){if?(msg?==?0x312){int?id?=?wParam.ToInt32();var?registerRecord?=?_hotkeyRegisterRecords.FirstOrDefault(i?=>?i.Id?==?id);registerRecord?.CallBack?.Invoke();}}#endregion#region?MyRegion//引入系統API[DllImport("user32.dll")]static?extern?bool?RegisterHotKey(IntPtr?hWnd,?int?id,?int?modifiers,?Keys?vk);[DllImport("user32.dll")]static?extern?bool?UnregisterHotKey(IntPtr?hWnd,?int?id);//標識-區分不同的快捷鍵int?registerId?=?10;//添加key值注冊字典,后續調用時有回調處理函數private?readonly?List<HotkeyRegisterRecord>?_hotkeyRegisterRecords?=?new?List<HotkeyRegisterRecord>();public?delegate?void?HotKeyCallBackHanlder();#endregion}public?class?HotkeyRegisterRecord{public?IntPtr?IntPtr?{?get;?set;?}public?int?Modifiers?{?get;?set;?}public?Keys?Key?{?get;?set;?}public?int?Id?{?get;?set;?}public?HotKeys.HotKeyCallBackHanlder?CallBack?{?get;?set;?}}//組合控制鍵public?enum?HotkeyModifiers{Alt?=?1,Control?=?2,Shift?=?4,Win?=?8}
在上方的
HotKeys
類中,注冊方法Register
提供了一個回調函數,后續監聽到外界全局鍵時,可以通知回調函數處理。參數
WParam
,是窗口響應時快捷鍵值,在winform
和WPF
窗口消息函數中都是有的。另,組合快捷鍵內部枚舉類
HotkeyModifiers
,枚舉值來自官網文檔WM_HOTKEY message
;
無感知禁用全局快捷鍵
比如:
禁用
Ctrl+Alt+1、Ctrl+Alt+2、Ctrl+Alt+3、Ctrl+Alt+4(Windows桌面圖標大小的調節快捷鍵
);
HotKeys?hotKeys?=?new?HotKeys();hotKeys.Register((int)HotkeyModifiers.Control,?Keys.N);hotKeys.Register((int)HotkeyModifiers.Control?+?(int)HotkeyModifiers.Alt,?Keys.D1);hotKeys.Register((int)HotkeyModifiers.Control?+?(int)HotkeyModifiers.Alt,?Keys.D2);hotKeys.Register((int)HotkeyModifiers.Control?+?(int)HotkeyModifiers.Alt,?Keys.D3);hotKeys.Register((int)HotkeyModifiers.Control?+?(int)HotkeyModifiers.Alt,?Keys.D4);
注:
窗口句柄參數,如果提供空的話,則注冊到調用線程上。
Keys
類型在system.windows.Forms
程序集下,如果是WPF
的Key
,可以使用KeyInterop
將Wpf
鍵值類型轉換為Winform
鍵值再調用此函數。
無感知禁用全局快捷鍵后回調
如果禁用全局快捷鍵的同時,外界觸發快捷鍵時需要此程序回調處理,可以添加窗口消息處理:
1) 新建一個類HotKeyHandleWindow
,繼承自Window
;
窗口樣式 - 高寬為
0
,窗口樣式None
;添加熱鍵注冊的調用;
添加
WndProc
,處理窗口消息;
public?class?HotKeyHandleWindow?:?Window{private?readonly?HotKeys?_hotKeys?=?new?HotKeys();public?HotKeyHandleWindow(){WindowStyle?=?WindowStyle.None;Width?=?0;Height?=?0;Loaded?+=?(s,?e)?=>{//這里注冊了Ctrl+Alt+1?快捷鍵_hotKeys.Register(new?WindowInteropHelper(this).Handle,(int)HotkeyModifiers.Control?+?(int)HotkeyModifiers.Alt,?Keys.D1,?CallBack);};}protected?override?void?OnSourceInitialized(EventArgs?e){base.OnSourceInitialized(e);var?hwndSource?=?PresentationSource.FromVisual(this)?as?HwndSource;hwndSource?.AddHook(new?HwndSourceHook(WndProc));}public?IntPtr?WndProc(IntPtr?hwnd,?int?msg,?IntPtr?wParam,?IntPtr?lParam,?ref?bool?handled){//窗口消息處理函數_hotKeys.ProcessHotKey(msg,?wParam);return?hwnd;}//按下快捷鍵時被調用的方法public?void?CallBack(){}}
2)調用窗口類;
var?hotKeyHandleWindow?=?new?HotKeyHandleWindow();
hotKeyHandleWindow.Show();
hotKeyHandleWindow.Hide();
以上有回調響應,但是也是無感知的
。
源碼下載[3]
參考資料
[1]
RegisterHotKey function : https://docs.microsoft.com/zh-cn/windows/win32/api/winuser/nf-winuser-registerhotkey?redirectedfrom=MSDN
[2]UnregisterHotKey function : https://docs.microsoft.com/zh-cn/windows/win32/api/winuser/nf-winuser-unregisterhotkey
[3]源碼下載: https://github.com/Kybs0/DiableGlobalShortcuts