如何为WinForms RichTextBox重写Ctrl + Shift + 0(零)?

时间:2013-10-24 03:10:55

标签: c# winforms keyboard richtextbox shortcuts

对于我的子类RichTextBox类,我可以捕获,抑制默认行为并重新使用Ctrl + Shift +#,只要#在1到9之间。对于Ctrl + Shift + 0,我可以“T。我在表单类中尝试了ProcessCmdKey,在控件类中尝试了onKeyDownPreProcessMessage

以下是控制类的示例代码,它应该禁止Ctrl + Shift + 0但不会:

public override bool PreProcessMessage(ref Message msg)
{
    bool cancel = false;
    int vKeyCode = (int)msg.WParam;

    if(msg.Msg == WinApi.WM_KEYDOWN)
    {
        bool ctrlDown = (WinApi.GetKeyState(Keys.ControlKey) & (1 << 16)) == (1 << 16);
        bool altDown = (WinApi.GetKeyState(Keys.Alt) & (1 << 16)) == (1 << 16);
        bool shiftDown = (WinApi.GetKeyState(Keys.ShiftKey) & (1 << 16)) == (1 << 16);

        if(ctrlDown && shiftDown && vKeyCode == (int)Keys.D0)
        {
            Debug.WriteLine("Cancel!");
            cancel = true;
        }
    }

    return cancel ? true : base.PreProcessMessage(ref msg);
}

但是,将Keys.D0更改为Keys.D1会显示示例无效。

如果这是一个线索,RichTextBox的默认行为是响应Ctrl + Shift + 0,更改字体。我去寻找文档,提到这是一个内置的快捷方式,但我没有找到任何东西(也许我没有使用正确的搜索条件)。

我应该如何检测Ctrl + Shift + 0以便我可以抑制默认行为并编写自己的行为?

1 个答案:

答案 0 :(得分:1)

经过一些尝试,我发现了如何实际压制Ctrl + Shift + D0。然而,新问题更加严重,Ctrl + Shift + D0被禁止了,但beep sound在发布Ctrl and Shift时生成了,这太烦人了,因为你说你想要覆盖这些键组合不是丢弃它。因此不应生成beep sound

在充满希望的搜索之后,有一些style要应用于RichTextBox,以防止beep sound或某些邮件丢弃导致压缩beep sound,但有没有任何这样的事情。我几乎感到失望,并打算永远让你的问题无人接听。我不想添加部分解决您问题的答案。不过幸运的是,我尝试了sending some key而不是丢弃了0 keyconsume键组合,并使keys combination 有效所以没有{{ 1}}将生成。以下是整个代码,请注意我们必须在这里使用一些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); } } ,它只是抑制了消息引起的默认行为{ {1}}。我想这足以解决你的问题。