Hotkeys

Well, I'll continue this description of resources. Now, I'd like to explain you an interesting technique that can be used when working with edit fields. When working with visual programming environments such as Visual Basic and Delphi, you probably noticed that edit fields can be programmed so that they allow only a predefined set of characters to be entered. For this purpose, it is necessary to specify certain field properties. For example, in Delphi, this property is called EditMask . I assume that you'd like to know how to implement such behavior using API functions only.

A standard window gets WM_KEYDOWN, WM_KEYUP , or their distillation, WM_CHAR , when a key is pressed (if it is active). However, in this case, you are dealing with the dialog and not with the standard window. Dialogs do not get such messages. It only remains to hope that the messages are sent in response to events that happen to the edit field. Unfortunately, here you'll also be disappointed. This element receives only two messages out of those that might be of any interest. These are EN_UPDATE and EN_CHANGE messages. Both messages arrive when any change has been made to the edit field. However, the EN_UPDATE message arrives when the changes have not been displayed on the screen yet, and the EN_CHANGE message is delivered after such changes. You'll have to first receive the contents of the edit field, determine which character was the last to be supplied there, and, if this is an invalid character, delete it from the string and send the string into the edit field. An additional problem relates to the cursor position and repeated delivery of the EN_UPDATE message. Would you proceed this way? Well, I never would!

There is another approach, much more elegant and convenient : using the hotkey concept. Limit yourself only to the programmatic properties of hotkeysthat is, the properties that every programmer must know to use hotkeys in programs.

The hotkey can be defined for every virtual keythat is, for every key defined using the macro constant with the VK prefix. For normal alphanumeric keys, the values of these constants coincide to ASCII codes. It is also possible to use combinations with control keys, such as <Alt>, <Ctrl>, and <Shift>. After the hotkey for a given window is defined, the WM_HOTKEY message arrives at the window function any time such a key or combination is pressed. By message parameters, it is possible to determine, which hotkey has been pressed. The important point is that the hotkey definition is global, which means that it will work even if other windows , possibly belonging to other applications, are active. This requires the programmer to work carefully , because pressing hotkeys can block normal operation of other applications. In other words, it is necessary to trace when the given window is active and when it is inactive. For this purpose, the WM_ACTIVATE and WM_ACTIVATEAPP messages can be helpful. The first message always arrives at the window function when the window is activated or deactivated. The first time this message arrives is when the window is created. After receiving this message, it makes sense to register hotkeys. The second message always arrives at the window function when the window loses the focusin other words, when another window is activated. Respectively, when this message arrives, it is necessary to cancel registration of these hotkeys.

For working with hotkeys, the following two functions are mainly used: RegisterHotKey and UnregisterHotKey . The RegisterHotKey function has the following parameters:

  • First parameterWindow descriptor

  • Second parameterHotkey identifier

  • Third parameterModifier defining whether a control key is pressed

  • Fourth parameterVirtual code of the key

    The UnregisterHotKey function has only two parameters:

  • First parameterWindow descriptor

  • Second parameterWindow identifier

If you have defined a hotkey, it stops to participate in any events and becomes locked. The only method that it is possible to use to determine whether this hotkey has been pressed is the WM_HOTKEY message.

Consider a simple example of a dialog box that contains two edit fields and an Exit button. Formulate the following goal: The first edit field must accept only digits from 0 to 9. The second edit field must accept all characters. A possible mechanism of using hotkeys with WM_ACTIVATE and WM_ACTIVATEAPP messages was considered previously. Clearly, in this case, such events will be of no help. Here, the situation is more complicated, and you need to use the messages related to the same edit field. These are the EN_SETFOCUS and EN_KILLFOCUS messages, passed using WM_COMMAND . The program demonstrating this mechanism, supplied with comments, is provided in Listing 10.2. The EN_SETFOCUS message informs the program that the edit window was activated, and the EN_KILLFOCUS message informs the program that the edit field was deactivated.

Listing 10.2: The use of hotkeys with a dialog box
image from book
 // The DIAL1.RC file // Constant definitions // Window styles #define WS_SYSMENU     0x00080000L #define WS_MINIMIZEBOX 0x00020000L #define WS_MAXIMIZEBOX 0x000l0000L // Text in the edit field is aligned on the left #define ES_LEFT        0x0000L // Style of all window elements #define WS_CHILD       0x40000000L // Window elements initially must be visible #define WS_VISIBLE     0x10000000L // Border around the element #define WS_BORDER      0x00800000L // Elements can be sequentially activated using the <Tab> key #define WS_TABSTOP     0x000l0000L // Left-align the string #define SS_LEFT        0x00000000L // Button style #define BS_PUSHBUTTON  0x00000000L // Center button text #define BS_CENTER      0x00000300L #define DS_LOCALEDIT   0x20L // Dialog definition DIAL1 DIALOG 0, 0, 240, 120 STYLE WS_SYSMENU  WS_MINIMIZEBOX  WS_MAXIMIZEBOX CAPTION "Dialog example" FONT 8, "Arial" { // Edit field, identifier 1  CONTROL "", 1, "edit", ES_LEFT  WS_CHILD   WS_VISIBLE  WS_BORDER  WS_TABSTOP, 24, 20, 128, 12 // Another edit field, identifier 2  CONTROL "", 2, "edit", ES_LEFT  WS_CHILD   WS_VISIBLE  WS_BORDER  WS_TABSTOP, 24, 52, 127, 12 // Text, identifier 3  CONTROL "String 1", 3, "static", SS_LEFT   WS_CHILD  WS_VISIBLE, 164, 22, 60, 8 // More text, identifier 4  CONTROL "String 2", 4, "static", SS_LEFT   WS_CHILD  WS_VISIBLE, 163, 54, 60, 8 // Button, identifier 5  CONTROL "Exit", 5, "button", BS_PUSHBUTTON   BS_CENTER  WS_CHILD  WS_VISIBLE  WS_TABSTOP,  180, 76, 50, 14 } ; The DIAL1.INC file ; Constants ; The message arrives when the window is closed WM_CLOSE      equ l0h WM_INITDIALOG equ 110h WM_COMMAND    equ 111h WM_SETTEXT    equ 0Ch WM_HOTKEY     equ 312h EN_SETFOCUS   equ 100h EN_KILLFOCUS  equ 200h ; Prototypes of external procedures EXTERN     UnregisterHotKey@8:NEAR EXTERN     RegisterHotKey@16:NEAR EXTERN     MessageBoxA@16:NEAR EXTERN     ExitProcess@4:NEAR EXTERN     GetModuleHandleA@ 4:NEAR EXTERN     DialogBoxParamA@20:NEAR EXTERN     EndDialog@8:NEAR EXTERN     SendMessageA@16:NEAR EXTERN     GetDlgItem@8:NEAR EXTERN     MessageBoxA@16:NEAR ; Structures ; Message structure MSGSTRUCT STRUC  MSHWND    DWORD ?  MSMESSAGE DWORD ?  MSWPARAM  DWORD ?  MSLPARAM  DWORD ?  MSTIME    DWORD ?  MSPT      DWORD ? MSGSTRUCT ENDS ; The DIAL.ASM file .586P ; Flat memory model .MODEL FLAT, stdcall include diall.inc ; INCLUDELIB directives for the linker to link libraries includelib c:\masm32\lib\user32.lib includelib c:\masm32\lib\kernel32.lib ;--------------------------------------------- ; Data segment _DATA SEGMENT MSG MSGSTRUCT <?> HINST DD 0  ; Application descriptor PA DB "DIAL1", 0 STR1 DB "Invalid character!", 0 STR2 DB "Error!", 0 ; Table for creating hotkeys TAB DB   32,  33,  34,  35,  36,  37,  38,  39,  40 DB  41,  42,  43,  44,  45,  46,  47,  58,  59,  60 DB  61,  62,  63,  64,  65,  66,  67,  68,  69,  70 DB  71,  72,  73,  74,  75,  76,  77,  78,  79,  80 DB  81,  82,  83,  84,  85,  86,  87,  88,  89,  90 DB  91,  92,  93,  94,  95,  96,  97,  98,  99, 100 DB 101, 102, 103, 104, 105, 106, 107, 108, 109, 110 DB 111, 112, 113, 114, 115, 116, 117, 118, 119, 120 DB 121, 122, 123, 124, 125, 126, 127, 128, 129, 130 DB 131, 132, 133, 134, 135, 136, 137, 138, 139, 140 DB 141, 142, 143, 144, 145, 146, 147, 148, 149, 150 DB 151, 152, 153, 154, 155, 156, 157, 158, 159, 160 DB 161, 162, 163, 164, 165, 166, 167, 168, 169, 170 DB 171, 172, 173, 174, 175, 176, 177, 178, 179, 180 DB 181, 182, 183, 184, 185, 186, 187, 188, 189, 190 DB 191, 192, 193, 194, 195, 196, 197, 198, 199, 200 DB 201, 202, 203, 204, 205, 206, 207, 208, 209, 210 DB 211, 212, 213, 214, 215, 216, 217, 218, 219, 220 DB 221, 222, 223, 224, 225, 226, 227, 228, 229, 230 DB 231, 232, 233; 234, 235, 236, 237, 238, 239, 240 DB 241, 242, 243, 244, 245, 246, 247, 248, 249, 250 DB 251, 252, 253, 254, 255 _DATA ENDS ; Code segment _TEXT SEGMENT START: ; Get the application descriptor    PUSH 0    CALL GetModuleHandleA@4    MOV  [HINST],. EAX ;----------------------------    PUSH 0    PUSH OFFSET WNDPROC    PUSH 0    PUSH OFFSET PA    PUSH [HINST]    CALL DialogBoxParamA@20    CMP  EAX, -1    JNE  KOL KOL: ;-----------------------------    PUSH 0    CALL ExitProcess@4 ;----------------------------- ; Window procedure ; Position of parameters in the stack ; [EBP+014H] ; LPARAM ; [EBP+10H]  ; WAPARAM ; [EBP+0CH]  ; MES ; [EBP+8] ; HWND WNDPROC    PROC    PUSH  EBP    MOV   EBP, ESP    PUSH  EBX    PUSH  ESI    PUSH  EDI ;---------------------------    CMP   DWORD PTR [EBP+0CH], WM_CLOSE    JNE   L1    PUSH  0    PUSH  DWORD PTR [EBP+08H]    CALL  EndDialog@8    MOV   EAX, 1    JMP   FIN L1:    CMP   DWORD PTR [EBP+0CH], WM_INITDIALOG    JNE   L2 ; If needed, fill edit fields here ; ;    MOV   EAX, 1    JMP   FIN L2:    CMP   DWORD PTR [EBP+0CH], WM_COMMAND    JNE   L5 ; Exit   button?    CMP   WORD PTR [EBP+10H], 5    JNE   L3    PUSH  0    PUSH  DWORD PTR [EBP+08H]    CALL  EndDialog@8    MOV   EAX, 1    JMP   FIN L3:    CMP   WORD PTR [EBP+10H], 1    JNE   FINISH ; Message-processing block for the first edit field    CMP   WORD PTR [EBP+12H], EN_KILLFOCUS    JNE   L4 ; Edit field with an identifier ; 1 loses focus    MOV   EBX, 0 ; Unregister all hotkeys    L33:    MOVZX EAX, BYTE PTR [TAB+EBX]    PUSH  EAX    PUSH  DWORD PTR [EBP+08H]    CALL  UnregisterHotKey@8    INC   EBX    CMP   EBX, 214    JNE   L33    MOV   EAX, 1    JMP   FIN L4:    CMP   WORD PTR [EBP+12H], EN_SETFOCUS    JNE   FINISH ; Edit field with an identifier ; 1 gains focus    MOV   EBX, 0 ; Registering hotkeys L44:    MOVZX EAX, BYTE PTR [TAB+EBX]    PUSH  EAX    PUSH  0    PUSH  EAX    PUSH  DWORD PTR [EBP+08H]    CALL  RegisterHotKey@16    INC   EBX    CMP   EBX, 214    JNE   L44    MOV   EAX, 1    JMP   FIN L5:    CMP   DWORD PTR [EBP+0CH], WM_HOTKEY    JNE   FINISH ; Reaction to invalid character    PUSH  0     ; MB_OK    PUSH  OFFSET STR2    PUSH  OFFSET STR1    PUSH  DWORD PTR [EBP+08H] ; Window descriptor    CALL  MessageBoxA@16 FINISH:    MOV   EAX, 0 FIN:    POP   EDI    POP   ESI    POP   EBX    POP   EBP    RET   16 WNDPROC ENDP _TEXT ENDS END START 
image from book
 

The following is comment related to the program presented in Listing 10.2:

  1. It is most important to understand when the first edit field loses and gains the focus. First, it is necessary to determine that the message has arrived from the edit field with identifier 1. Then, you need to determine which message has arrived EN_SETFOCUS or EN_KILLFOCUS . In the first case, you register the hotkeys; in the latter case, you unregister them.

  2. In the data area, specify the hotkey table. The RegisterHotKey function has the following parameters:

    • First parameterWindow identifier

    • Second parameterHotkey identifier

    • Third parameterHotkey-pressing flag

    • Fourth parameterVirtual code of the key

In Listing 10.2, the key virtual code and hotkey identifier match. Naturally, you have a wide field for improvement. For example, it is possible to exclude the arrow keys from the processing. I suggest that you carry out this task on your own.



The Assembly Programming Master Book
The Assembly Programming Master Book
ISBN: 8170088178
EAN: 2147483647
Year: 2004
Pages: 140
Authors: Vlad Pirogov

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net