How to get the Tab key click in the edit box?

I want to receive OnKeyPress events when the user presses the Tab key.

 procedure TForm1.Edit1(Sender: TObject; var Key: Char); begin case Key of #09: begin //Snip - Stuff i want to do end; end; end; 

Try subclassing the Edit field and processing the WM_GETDLGCODE message:

 procedure TfrmEnableVIPMode.AccountNumberWindowProc(var Message: TMessage); begin case Message.Msg of WM_GETDLGCODE: Message.Result := DLGC_WANTTAB; else FOldAccountNumberWindowProc(Message); end; end; 

And now I get Tab KeyPress events (as I hoped), but now pressing the Left or Right cursor keys will switch focus to the previous or next control in tab order.

What is the correct way to get the tab key of an event click ?

Reading bonuses

I tried to do what the MSDN documentation says:

WPARAM
The virtual key pressed by the user caused Windows to issue this notification. The handler must selectively process these keys. For example, a handler can accept and process VK_RETURN, but delegate VK_TAB to the owner window. For a list of values, see Virtual Key Codes.

lParam Pointer to an MSG structure (or NULL if the system is making a request).

but wParam and wParam are equal to zero.

Update two

I realized that I have the same error as this answer :

 if Message.Msg = WM_GETDLGCODE then Message.Result:= Message.Result or DLGC_WANTTAB else if Assigned(FOldWndProc) then FOldWndProc(Message); 

when should I use concepts from the correct code specified elsewhere in the same answer:

 if Assigned(FOldWndProc) then FOldWndProc(Message); if Message.Msg = WM_GETDLGCODE then Message.Result:= Message.Result or DLGC_WANTTAB; 

This helps explain why my source code is incorrect. Setting DLGC_WANTTAB to DLGC_WANTTAB is incorrect:

 procedure TfrmEnableVIPMode.AccountNumberWindowProc(var Message: TMessage); begin case Message.Msg of WM_GETDLGCODE: Message.Result := DLGC_WANTTAB; else FOldAccountNumberWindowProc(Message); end; end; 

it is also wrong to try bitwise or the DLGC_WANTTAB flag in DLGC_WANTTAB , because DLGC_WANTTAB doesn't matter yet:

 procedure TfrmEnableVIPMode.AccountNumberWindowProc(var Message: TMessage); begin case Message.Msg of WM_GETDLGCODE: Message.Result := Message.Result or DLGC_WANTTAB; else FOldAccountNumberWindowProc(Message); end; end; 

First, I must first call the original window procedure so that the Windows Edit management team sets the correct Message.Result values. Then I can do the bitwise combination of DLGC_WANTTAB :

 procedure TfrmEnableVIPMode.AccountNumberWindowProc(var Message: TMessage); begin FOldAccountNumberWindowProc(Message); case Message.Msg of WM_GETDLGCODE: Message.Result := Message.Result or DLGC_WANTTAB; end; end; 

To paraphrase a Raymond Chen blog entry and add emphasis as necessary:

After asking the source control what behavior it considers appropriate , we enable the DLGC_WANTTAB flag

So this is better. The cursor keys continue to move through the text in the Edit control (instead of shifting the focus), and I get OnKeyPress events (both OnKeyDown and OnKeyUp ) for the Tab key.

The rest of the problem is that the user, by pressing Tab , no longer shifts focus.

I tried to manually start manually breaking focus, changing myself:

 procedure TfrmEnableVIPMode.edAccountNumberKeyPress(Sender: TObject; var Key: Char); begin case Key of #09: begin //Snip - Stuff i want to do { The DLGC_WANTTAB technique broke Windows focus change. Keep throwing in hacks until it no longer obviously broken } //Perform(CM_DialogKey, VK_TAB, 0); //doesn't work Self.ActiveControl := Self.FindNextControl(edAccountNumber, True, True, False); end; end; end; 

The code above works if the user presses the Tab key. But the code is broken, as Raymond Chen notes six years ago:

There is much that is wrong with this approach. You can spend quite a bit of time detailing how this code cannot correctly set focus in a dialog box, how it does not take into account nested dialogs, how it does not cope with the navigation key Shift + Tab

In my case, I broke Shift + Tab . And who knows what else.


So my question is:

How to get the Tab key click in the edit box?

I do not want to eat them, I just want to know that the user has pressed the Tab key.

Bonus Chatter

+7
accessibility delphi subclassing delphi-5
source share
2 answers

You can process the CN_KEYDOWN message:

 procedure TfrmEnableVIPMode.AccountNumberWindowProc(var Message: TMessage); begin case Message.Msg of CN_KEYDOWN: if TWMKey(Message).CharCode = VK_TAB then .... end; FOldAccountNumberWindowProc(Message); end; 


It is also possible to detect a message with a key at the form level, without an editing subclass:

 procedure TfrmEnableVIPMode.CMDialogKey(var Message: TCMDialogKey); begin if (Message.CharCode = VK_TAB) and (ActiveControl = edAccountNumber) then ... inherited; end; 
+7
source share

First you need to call the previous WndProc so that TEdit default value for the key codes that TEdit initially wants, and then add the DLGC_WANTTAB flag to this result, for example:

 procedure TfrmEnableVIPMode.AccountNumberWindowProc(var Message: TMessage); begin FOldAccountNumberWindowProc(Message); if Message.Msg = WM_GETDLGCODE then Message.Result := Message.Result or DLGC_WANTTAB; end; 
+3
source share

All Articles