Edit Menus and the RichTextBox Control
RichTextBox controls present an interesting problem to VB developers in the form of edit menus. If you are a VB developer, creating an application in which you need an edit menu with functions such as cut, copy, paste, undo and redo, then you will clearly want the user to have the ability to use their respective standard keyboard accelerators. When you're using the RichTextBox (or even the TextBox), what you find when you try to do this is that it performs all of these functions twice when you press the accelerator key (but not when you choose the item from your menu). We will look at the reason why this happens, and the solution to the problem.
The reason this happens is because the identifiers for the accelerators of standard edit menu functions are different to the standard windows ones, and thus two events are registered for one accelerator keyset. What this means is that the code perform the function is executed twice, in two different places. In practical terms, what this means for your application is that you will paste text twice, try to cut and copy text twice (which will double the time it takes, and that's a problem if there's a lot of text), and undo and redo twice (which results in effectively nothing happening for the user, since VB doesn't do multiple-level undo in RichTextBoxes).
The solution to the problem presented is a relatively simple one (or at least it is for anyone familiar with subclassing). The idea is to wait for the correct KeyDown message to arrive and simply consume it. That is to say that we never let the message actually get to the RichTextBox control, so it can't process it and perform the associated accelerator key action. Note that this sample uses code from another code sample ().
Implements ISubclass Private Sub Form_Load() SubclassWnd RichTextBox1.hwnd, Me End Sub Private Sub Form_Unload(Cancel As Integer) UnSubclassWnd RichTextBox1.hwnd End Sub Private Function ISubclass_WndProc( _ ByVal hwnd As Long, _ ByVal uMsg As Long, _ ByVal wParam As Long, _ ByVal lParam As Long, _ bHandled As Boolean, _ RetVal As Boolean _ ) As Long Select Case uMsg Case WM_KEYDOWN '-- We have a KeyDown message, see if we need to consume it ... If GetKeyState(vbKeyControl) And &HF0000000 Then '-- First check if the ctrl key is down Select Case wParam '-- See if it's one of our standard edit menu messages Case vbKeyV, vbKeyC, vbKeyX, vbKeyY, vbKeyV '-- Consume the message bHandled = True End Select End If End Select End Function
Simple as that.