Articles   Members Online:
-Article/Tip Search
-News Group Search over 21 Million news group articles.
Member Area
-Account Center
-Top 10 NEW!!
-Submit Article/Tip
-Forums Upgraded!!
-My Articles
-Edit Information
-Become a Member
-Why sign up!
-Chat Online!
-Indexes NEW!!
-Build your resume
-Find a job
-Post a job
-Resume Search
-Link to us
Visit Embarcadero
Embarcadero Community
How to capture keyboard messages at application level Turn on/off line numbers in source code. Switch to Orginial background IDE or DSP color Comment or reply to this aritlce/tip for discussion. Bookmark this article to my favorite article(s). Print this article
Delphi 5.x
User Rating
No Votes
# Votes
DSP, Administrator
Reference URL:
			Author: Ernesto De Spirito 

We can migrate old DOS applications to the Windows environment, but frequently we 
can't migrate the users :)


We capture the keyboard messages with the OnMessage event of the Application 
object. You can find similar articles, but the code presented here is more complete 
and takes into account certain special cases. 

For the ENTER key (VK_RETURN) we want to move to the next control in the case of 
edit boxes and other controls, so we ask if the active control descends from 
TCustomEdit, which includes TEdit, TDBEdit, TMaskEdit, TDBMaskEdit, TMemo, TDBMemo 
and other components provided by third parties. Since we want to exclude TMemo, 
TDBMemo and, in general, all descendants of TCustomMemo, we make a special proviso 
in this case (leaving the message unchanged with no action), leaving us with the 
single-line edit controls, to which we add listboxes, comboxes, etc. For these 
elements we replace the ENTER key (VK_RETURN) by a TAB key (VK_TAB), both for the 
WM_KEYDOWN and WM_KEYUP events. 

However in the case of a combobox (any TCustomCombobox descendant), when the list 
is dropped down we wish to maintain the traditional behaviour of the ENTER key 
(i.e. closing the list). 

It would be nice to have a keyboard shortcut for the default button of a form (the 
button with its Default property set to True), for example CTRL+ENTER. This feature 
is included in the code. The way it is accomplished is a little bit complex to 
explain... Perhaps it would have been easier to iterate thru the components on a 
form to find a focuseable button with Default = True, and then call its Click 
method, but we used a code similar to the one used in VCL forms, which takes into 
account the fact that the ENTER key might be wanted to get trapped by many 
controls, not only a button. 

We also want the DOWN arrow key (VK_DOWN) to be mapped as a TAB key (VK_TAB). For 
this case we used a simpler code. Of course, we also want the UP arrow key (VK_UP) 
to be mapped to a SHIFT+TAB key combination. Well, it isn't possible to map a key 
with a modifier. We can descard the key and simulate the events of pressing SHIFT 
and then TAB, or we can change the state of the SHIFT key in the keyboard state 
array (like we did with the CTRL key in the CTRL+ENTER combination), but we took a 
different approach (simply focusing the previous control of the active control in 
the tab order). 

Finally, for Spanish applications, it is usually desirable to replace the decimal 
point of the numeric keypad with a coma (decimal separator in Spanish). 

Well, enough talking, and here's the code: 

1   type
2     TForm1 = class(TForm)
3       ...
4       private
5       ...
6         procedure ApplicationMessage(var Msg: TMsg; var Handled: Boolean);
7       ...
8     end;
10  var
11    Form1: TForm1;
13  implementation
15  {$R *.DFM}
17  procedure TForm1.FormCreate(Sender: TObject);
18  begin
19    Application.OnMessage := ApplicationMessage;
20  end;
22  procedure TForm1.ApplicationMessage(var Msg: TMsg;
23    var Handled: Boolean);
24  var
25    ActiveControl: TWinControl;
26    Form: TCustomForm;
27    ShiftState: TShiftState;
28    KeyState: TKeyboardState;
29  begin
30    case Msg.message of
32        case Msg.wParam of
33          VK_RETURN:
34            // Replaces ENTER with TAB, and CTRL+ENTER with ENTER...
35            begin
36              GetKeyboardState(KeyState);
37              ShiftState := KeyboardStateToShiftState(KeyState);
38              if (ShiftState = []) or (ShiftState = [ssCtrl]) then
39              begin
40                ActiveControl := Screen.ActiveControl;
41                if (ActiveControl is TCustomComboBox) and
42                  (TCustomComboBox(ActiveControl).DroppedDown) then
43                begin
44                  if ShiftState = [ssCtrl] then
45                  begin
46                    KeyState[VK_LCONTROL] := KeyState[VK_LCONTROL] and $7F;
47                    KeyState[VK_RCONTROL] := KeyState[VK_RCONTROL] and $7F;
48                    KeyState[VK_CONTROL] := KeyState[VK_CONTROL] and $7F;
49                    SetKeyboardState(KeyState);
50                  end;
51                end
52                else if (ActiveControl is TCustomEdit)
53                  and not (ActiveControl is TCustomMemo)
54                  or (ActiveControl is TCustomCheckbox)
55                  or (ActiveControl is TRadioButton)
56                  or (ActiveControl is TCustomListBox)
57                  or (ActiveControl is TCustomComboBox)
58                  {// You can add more controls to the list with "or" } then
59                  if ShiftState = [] then
60                  begin
61                    Msg.wParam := VK_TAB
62                  end
63                  else
64                  begin // ShiftState = [ssCtrl]
65                    Msg.wParam := 0; // Discard the key
66                    if Msg.message = WM_KEYDOWN then
67                    begin
68                      Form := GetParentForm(ActiveControl);
69                      if (Form <> nil) and
70                        (ActiveControl.Perform(CM_WANTSPECIALKEY,
71                        VK_RETURN, 0) = 0) and
72                        (ActiveControl.Perform(WM_GETDLGCODE, 0, 0)
73                        and DLGC_WANTALLKEYS = 0) then
74                      begin
75                        KeyState[VK_LCONTROL] := KeyState[VK_LCONTROL] and $7F;
76                        KeyState[VK_RCONTROL] := KeyState[VK_RCONTROL] and $7F;
77                        KeyState[VK_CONTROL] := KeyState[VK_CONTROL] and $7F;
78                        SetKeyboardState(KeyState);
79                        Form.Perform(CM_DIALOGKEY, VK_RETURN, Msg.lParam);
80                      end;
81                    end;
82                  end;
83              end;
84            end;
85          VK_DOWN:
86            begin
87              GetKeyboardState(KeyState);
88              if KeyboardStateToShiftState(KeyState) = [] then
89              begin
90                ActiveControl := Screen.ActiveControl;
91                if (ActiveControl is TCustomEdit)
92                  and not (ActiveControl is TCustomMemo)
93                  {// You can add more controls to the list with "or" } then
94                  Msg.wParam := VK_TAB;
95              end;
96            end;
97          VK_UP:
98            begin
99              GetKeyboardState(KeyState);
100             if KeyboardStateToShiftState(KeyState) = [] then
101             begin
102               ActiveControl := Screen.ActiveControl;
103               if (ActiveControl is TCustomEdit)
104                 and not (ActiveControl is TCustomMemo)
105                 {// You can add more controls to the list with "or" } then
106               begin
107                 Msg.wParam := 0; // Discard the key
108                 if Msg.message = WM_KEYDOWN then
109                 begin
110                   Form := GetParentForm(ActiveControl);
111                   if Form <> nil then // Move to previous control
112                     Form.Perform(WM_NEXTDLGCTL, 1, 0);
113                 end;
114               end;
115             end;
116           end;
117         // Replace the decimal point of the numeric key pad (VK_DECIMAL)
118         // with a comma (key code = 188). For Spanish applications.
119         VK_DECIMAL:
120           begin
121             GetKeyboardState(KeyState);
122             if KeyboardStateToShiftState(KeyState) = [] then
123             begin
124               Msg.wParam := 188;
125             end;
126           end;
127       end;
128   end;
129 end;

Copyright (c) 2001 Ernesto De Spirito

Vote: How useful do you find this Article/Tip?
Bad Excellent
1 2 3 4 5 6 7 8 9 10


Share this page
Download from Google

Copyright © Mendozi Enterprises LLC