经过一些尝试,我发现了如何真正抑制Ctrl + Shift + D0
. 然而,新的问题更加棘手,Ctrl + Shift + D0
被抑制了 OK 但是beep sound
在释放 时生成了Ctrl and Shift
,这太烦人了,因为你说你想覆盖这些键组合而不是丢弃它。所以beep sound
不应该生成。
在搜索了很多希望之后,有一些style
可以应用以RichTextBox
防止beep sound
或某些消息被丢弃,从而导致抑制,beep sound
但没有任何这样的事情。我几乎感到失望,并打算让你的问题永远得不到回答。我不想添加只是部分解决了您的问题的答案。但是幸运的是,我尝试sending some key
了而不是丢弃0 key
到consume
键组合并使keys combination
有效,因此不会beep sound
生成。这是给你的整个代码,注意我们必须在global low-level keyboard hook
这里使用一些,正如我所说的应用程序级消息过滤器也无济于事:
[DllImport("user32")]
private static extern IntPtr SetWindowsHookEx(int hookType, KeyboardLowLevelProc proc, IntPtr moduleHandle, int threadID);
[DllImport("user32")]
private static extern int UnhookWindowsHookEx(IntPtr hHook);
[DllImport("user32")]
private static extern IntPtr CallNextHookEx(IntPtr hHook, int nCode, IntPtr wParam, IntPtr lParam);
[DllImport("kernel32")]
private static extern IntPtr GetModuleHandle(string moduleName);
public struct KBDLLHOOKSTRUCT
{
public Keys key;
public int scanCode;
public int flags;
public int time;
public IntPtr extra;
}
public delegate IntPtr KeyboardLowLevelProc(int hCode, IntPtr wParam, IntPtr lParam);
public IntPtr KeyboardLowLevelCallback(int nCode, IntPtr wParam, IntPtr lParam)
{
if (nCode >= 0) {
KBDLLHOOKSTRUCT kbd = (KBDLLHOOKSTRUCT)Marshal.PtrToStructure(lParam, typeof(KBDLLHOOKSTRUCT));
if (kbd.key == Keys.D0 && blockD0) {
if(ModifierKeys == (Keys.Control | Keys.Shift)) {
SendKeys.Send("{ESC}");
//Add custom code as the response to Ctrl + Shift + D0 here
//....
}
return new IntPtr(1);//Discard the default behavior
}
}
return CallNextHookEx(hHook, nCode, wParam, lParam);
}
bool blockD0;
KeyboardLowLevelProc proc; //this should be declared in the form scope
IntPtr hHook;
//your Form1 constructor
public Form1(){
InitializeComponent();
//Get current module Handle
IntPtr currentModuleHandle = GetModuleHandle(System.Diagnostics.Process.GetCurrentProcess().MainModule.ModuleName);
//Set the keyboard hook
hHook = SetWindowsHookEx(13, proc, currentModuleHandle, 0);//WH_KEYBOARD_LL = 13
//register these Key events for your richTextBox1
richTextBox1.KeyDown += (s, e) => {
if(e.KeyCode != Keys.D0) blockD0 = true;
};
richTextBox1.KeyUp += (s, e) => {
if (ModifierKeys == Keys.None) blockD0 = false;
};
//Unhook keyboard when form is closed
FormClosed += (s,e) => {
if (hHook != IntPtr.Zero) {
UnhookWindowsHookEx(hHook);
hHook = IntPtr.Zero;
}
}
}
稍微解释一下:我不明白为什么我们必须在Global Low-level Keyboard hook
这里使用,我猜当按键组合Ctrl + Shift + D0
被按下时,可能有一些按键消息被克隆并发送到另一个线程,这就是为什么当前所有手动拦截的原因线程不能拦截或覆盖Ctrl + Shift + D0
,但是global low-level keyboard hook
可以处理当前模块key messages
的所有线程并且它可以拦截任何关键消息。
我提到了这个beep sound
问题,如果您想体验它,只需删除SendKeys.Send("{ESC}");
,实际上您可以尝试其他一些键,例如1
, 2
, ... 它们也使组合键Ctrl + Shift + ...
有效并有助于避免任何beep sound
.
更新
上面的解决方案工作正常,这是最好的解决方案,Ctrl + Shift + D0
应该彻底彻底地丢弃。但是它有点长(如您所见)。我发现当您按下 时Ctrl + Shift + D0
,WM_INPUTLANGCHANGEREQUEST
会发送消息,此消息会导致您不想要的行为。所以我们可以尝试另一种解决方案,PreProcessMessage
你仍然可以捕获组合Ctrl + Shift + D0
但你不能丢弃它(因为它被分派到另一个线程),这意味着你可以在那里添加你自己的代码,而不是丢弃Ctrl + Shift + D0
,我们可以丢弃它通过丢弃消息而导致的效果/行为WM_INPUTLANGCHANGEREQUEST
。我们有以下代码:
//Create a custom RichTextBox class
public class CustomRichTextBox : RichTextBox {
protected override void WndProc(ref Message m){
if(m.Msg == 0x50) return; //WM_INPUTLANGCHANGEREQUEST = 0x50
base.WndProc(ref m);
}
public override bool PreProcessMessage(ref Message msg) {
if (msg.Msg == 0x100)//WM_KEYDOWN = 0x100
{
Keys keyData = (Keys)msg.WParam | ModifierKeys;
if(keyData == (Keys.Control | Keys.Shift | Keys.D0)){
//your own code goes here...
}
}
return base.PreProcessMessage(ref msg);
}
}
您可以看到第二种方法要短得多,但是正如我所说,它实际上并没有抑制Ctrl + Shift + D0
,它只是抑制了由 message 引起的默认行为WM_INPUTLANGCHANGEREQUEST
。我想这足以解决你的问题。