Key Press Trapping (with example project)

Started by Martin Francom, January 08, 2010, 01:28:59 PM

Previous topic - Next topic

Martin Francom

Is there a topic the FF3 Help file that covers  Key Press Trapping?   I did a search on "Key Trapping" and came up empty handed.  May be I am searching for the wrong term?

What I want to do is to test for the  "ESC" key being pressed anywhere on a Form.  Any time the "ESC" key is pressed I want it to "Set Focus" to a particular TextBox.

Also, when in a particular TextBox I want to test for the "Up" or "Down" arrow Keys being pressed and if pressed I want a particular action to occur. 

Does a simple example program exist that shows how to do this sort of thing?  I looked at the FF example projects and didn't see one that covered this topic.

edited 11 Jan 2010:   
Added an simple example program:  KeyCapture
This program will demonstrate how you can easily capture Key Presses such as ESC, ENTER, Up and DOWN arrow keys,  F1 - F12 function keys.   The example program was possible because of Paul's help.    Hope this program will be of use to other programmers.
The link below is for a FF3 project "KeyCapture" :
   

Paul Squires

That stuff is not in the FF Help file because it is standard WinAPI programming type of information. What you're asking can be broken down into two answers:

(1) Global "ESC" for a form (Note, there will need to be a control on your form that has keyboard focus in order for this to work). We add code directly to the message pump via the FF_PUMPHOOK function and catch the incoming WM_KEYDOWN message and act on it.


Function FF_PUMPHOOK( Msg As tagMsg ) As Long


   ' If this function returns FALSE (zero) then the processing of the regular
   ' FireFly message pump will continue. Returning TRUE (non-zero) will bypass
   ' the regular message pump.

   Function = %FALSE    'return %TRUE if you need to bypass the FireFly message pump

   ' If you are dealing with a 'normal' OCX control then the following code will
   ' allow the message to be forwarded to the OCX.
   #If %DEF( %USE_JOSE_INCLUDES )
      #If %DEF( %USE_JOSE_OCX )
         Function = OC_ForwardMessage( GetFocus(), Msg)
      #EndIf
   #EndIf


   ' Is the message going to the control on the Form that we are interested in?
   If GetParent(Msg.hWnd) = HWND_FORM1 Then
      ' Determine if the ESC key was pressed.
      Select Case Msg.Message
         Case %WM_KEYDOWN
            If Msg.wParam = %VK_ESCAPE Then
            ? "escape"
               SetFocus HWND_FORM1_TEXT1
            End If   
      End Select
   End If
   
End Function



(2) Dealing with "UP" and "DOWN" arrows for a particular TextBox:


Function FORM1_TEXT1_WM_KEYDOWN ( _
                                ControlIndex  As Long,  _  ' index in Control Array
                                hWndForm      As Dword, _  ' handle of Form
                                hWndControl   As Dword, _  ' handle in Control
                                nVirtKey      As Long,  _  ' virtual key code
                                lKeyData      As Long   _  ' key data
                                ) As Long

   Select Case nVirtKey
      Case %VK_UP
         ? "Up key pressed"
         Function = %TRUE     ' prevent key from making it to the TextBox
      Case %VK_DOWN
         ? "Down key pressed"
         Function = %TRUE     ' prevent key from making it to the TextBox
   End Select
     
End Function


Paul Squires
PlanetSquires Software

Martin Francom

Thanks Paul

  Is there a list of these %VK_  constants somewhere? 

  The Win-API references I have found on the web are C oriented.  Is there a Win-API reference for the BASIC programmer that you would recommend?

Paul Squires

Quote from: Marty Francom on January 08, 2010, 08:21:01 PM
  Is there a list of these %VK_  constants somewhere? 

Using PowerBASIC includes: WinAPI.inc
Using Jose's includes:  WinUser.inc

Quote
  The Win-API references I have found on the web are C oriented.  Is there a Win-API reference for the BASIC programmer that you would recommend?

Not that I know of. I learned most of my stuff from reading endless posts in POFFS or on-line with the PB forums. Also, Jose's forum and website is invaluable. Over the years I have learned how to read "C" code pretty well so I can usually translate from C to PB.
Paul Squires
PlanetSquires Software

Martin Francom

Ok found them:

Here they are:


' Virtual Keys, Standard Set
%VK_LBUTTON  = &H01
%VK_RBUTTON  = &H02
%VK_CANCEL   = &H03
%VK_MBUTTON  = &H04    ' NOT contiguous with L RBUTTON
%VK_XBUTTON1 = &H05    ' NOT contiguous with L & RBUTTON
%VK_XBUTTON2 = &H06    ' NOT contiguous with L & RBUTTON
%VK_BACK     = &H08
%VK_TAB      = &H09
%VK_LINEFEED = &H0A
%VK_CLEAR    = &H0C
%VK_RETURN   = &H0D
%VK_SHIFT    = &H10
%VK_CONTROL  = &H11
%VK_MENU     = &H12
%VK_PAUSE    = &H13
%VK_CAPITAL  = &H14
%VK_KANA     = &H15
%VK_HANGEUL  = &H15  ' old name - should be here for compatibility
%VK_HANGUL   = &H15
%VK_JUNJA    = &H17
%VK_FINAL    = &H18
%VK_HANJA    = &H19
%VK_KANJI    = &H19
%VK_ESCAPE   = &H1B
%VK_CONVERT    = &H1C
%VK_NONCONVERT = &H1D
%VK_ACCEPT     = &H1E
%VK_MODECHANGE = &H1F
%VK_SPACE    = &H20
%VK_PGUP     = &H21
%VK_PRIOR    = &H21
%VK_NEXT     = &H22
%VK_PGDN     = &H22
%VK_END      = &H23
%VK_HOME     = &H24
%VK_LEFT     = &H25
%VK_UP       = &H26
%VK_RIGHT    = &H27
%VK_DOWN     = &H28
%VK_SELECT   = &H29
%VK_PRINT    = &H2A
%VK_EXECUTE  = &H2B
%VK_SNAPSHOT = &H2C
%VK_INSERT   = &H2D
%VK_DELETE   = &H2E
%VK_HELP     = &H2F
%VK_0        = &H30
%VK_1        = &H31
%VK_2        = &H32
%VK_3        = &H33
%VK_4        = &H34
%VK_5        = &H35
%VK_6        = &H36
%VK_7        = &H37
%VK_8        = &H38
%VK_9        = &H39
%VK_A        = &H41
%VK_B        = &H42
%VK_C        = &H43
%VK_D        = &H44
%VK_E        = &H45
%VK_F        = &H46
%VK_G        = &H47
%VK_H        = &H48
%VK_I        = &H49
%VK_J        = &H4A
%VK_K        = &H4B
%VK_L        = &H4C
%VK_M        = &H4D
%VK_N        = &H4E
%VK_O        = &H4F
%VK_P        = &H50
%VK_Q        = &H51
%VK_R        = &H52
%VK_S        = &H53
%VK_T        = &H54
%VK_U        = &H55
%VK_V        = &H56
%VK_W        = &H57
%VK_X        = &H58
%VK_Y        = &H59
%VK_Z        = &H5A
%VK_LWIN     = &H5B
%VK_RWIN     = &H5C
%VK_APPS     = &H5D
%VK_SLEEP    = &H5F
%VK_NUMPAD0  = &H60
%VK_NUMPAD1  = &H61
%VK_NUMPAD2  = &H62
%VK_NUMPAD3  = &H63
%VK_NUMPAD4  = &H64
%VK_NUMPAD5  = &H65
%VK_NUMPAD6  = &H66
%VK_NUMPAD7  = &H67
%VK_NUMPAD8  = &H68
%VK_NUMPAD9  = &H69
%VK_MULTIPLY = &H6A
%VK_ADD      = &H6B
%VK_SEPARATOR= &H6C
%VK_SUBTRACT = &H6D
%VK_DECIMAL  = &H6E
%VK_DIVIDE   = &H6F
%VK_F1       = &H70
%VK_F2       = &H71
%VK_F3       = &H72
%VK_F4       = &H73
%VK_F5       = &H74
%VK_F6       = &H75
%VK_F7       = &H76
%VK_F8       = &H77
%VK_F9       = &H78
%VK_F10      = &H79
%VK_F11      = &H7A
%VK_F12      = &H7B
%VK_F13      = &H7C
%VK_F14      = &H7D
%VK_F15      = &H7E
%VK_F16      = &H7F
%VK_F17      = &H80
%VK_F18      = &H81
%VK_F19      = &H82
%VK_F20      = &H83
%VK_F21      = &H84
%VK_F22      = &H85
%VK_F23      = &H86
%VK_F24      = &H87
%VK_NUMLOCK  = &H90
%VK_SCROLL   = &H91

' NEC PC-9800 kbd definitions

%VK_OEM_NEC_EQUAL  = &H92   ' "=" key on numpad

' Fujitsu/OASYS kbd definitions

%VK_OEM_FJ_JISHO   = &H92   ' "Dictionary" key
%VK_OEM_FJ_MASSHOU = &H93   ' "Unregister word" key
%VK_OEM_FJ_TOUROKU = &H94   ' "Register word" key
%VK_OEM_FJ_LOYA    = &H95   ' "Left OYAYUBI" key
%VK_OEM_FJ_ROYA    = &H96   ' "Right OYAYUBI" key

' VK_L* & VK_R* - left and right Alt, Ctrl and Shift virtual keys.
' Used only as parameters to GetAsyncKeyState() and GetKeyState().
' No other API or message will distinguish left and right keys in this way.

%VK_LSHIFT   = &HA0
%VK_RSHIFT   = &HA1
%VK_LCONTROL = &HA2
%VK_RCONTROL = &HA3
%VK_LMENU    = &HA4
%VK_RMENU    = &HA5
%VK_BROWSER_BACK        = &HA6
%VK_BROWSER_FORWARD     = &HA7
%VK_BROWSER_REFRESH     = &HA8
%VK_BROWSER_STOP        = &HA9
%VK_BROWSER_SEARCH      = &HAA
%VK_BROWSER_FAVORITES   = &HAB
%VK_BROWSER_HOME        = &HAC
%VK_VOLUME_MUTE         = &HAD
%VK_VOLUME_DOWN         = &HAE
%VK_VOLUME_UP           = &HAF
%VK_MEDIA_NEXT_TRACK    = &HB0
%VK_MEDIA_PREV_TRACK    = &HB1
%VK_MEDIA_STOP          = &HB2
%VK_MEDIA_PLAY_PAUSE    = &HB3
%VK_LAUNCH_MAIL         = &HB4
%VK_LAUNCH_MEDIA_SELECT = &HB5
%VK_LAUNCH_APP1         = &HB6
%VK_LAUNCH_APP2         = &HB7
%VK_OEM_1        = &HBA   ' ";:" for US
%VK_OEM_PLUS     = &HBB   ' "+" any country
%VK_OEM_COMMA    = &HBC   ' "," any country
%VK_OEM_MINUS    = &HBD   ' "-" any country
%VK_OEM_PERIOD   = &HBE   ' "." any country
%VK_OEM_2        = &HBF   ' "/?" for US
%VK_OEM_3        = &HC0   ' "`~" for US
%VK_OEM_4        = &HDB  ' "[{" for US
%VK_OEM_5        = &HDC  ' "\|" for US
%VK_OEM_6        = &HDD  ' "]}" for US
%VK_OEM_7        = &HDE  ' """" for US
%VK_OEM_8        = &HDF
%VK_OEM_AX       = &HE1  ' "AX" key on Japanese AX kbd
%VK_OEM_102      = &HE2  ' "<>" or "\|" on RT 102-key kbd.
%VK_ICO_HELP     = &HE3  ' Help key on ICO
%VK_ICO_00       = &HE4  ' 00 key on ICO
%VK_PROCESSKEY   = &HE5
%VK_ICO_CLEAR    = &HE6
%VK_PACKET       = &HE7

' Nokia/Ericsson definitions

%VK_OEM_RESET    = &HE9
%VK_OEM_JUMP     = &HEA
%VK_OEM_PA1      = &HEB
%VK_OEM_PA2      = &HEC
%VK_OEM_PA3      = &HED
%VK_OEM_WSCTRL   = &HEE
%VK_OEM_CUSEL    = &HEF
%VK_OEM_ATTN     = &HF0
%VK_OEM_FINISH   = &HF1
%VK_OEM_COPY     = &HF2
%VK_OEM_AUTO     = &HF3
%VK_OEM_ENLW     = &HF4
%VK_OEM_BACKTAB  = &HF5

%VK_ATTN         = &HF6
%VK_CRSEL        = &HF7
%VK_EXSEL        = &HF8
%VK_EREOF        = &HF9
%VK_PLAY         = &HFA
%VK_ZOOM         = &HFB
%VK_NONAME       = &HFC
%VK_PA1          = &HFD
%VK_OEM_CLEAR    = &HFE

#ENDIF '#IF NOT %DEF(%NOVIRTUALKEYCODES) '-------------------------------------


Martin Francom

Paul,
   I don't see in the list a constant for the "Enter" key.    I was expecting to find  %VK_ENTER   but did not find it.  Is it listed differently.

   There is one other thing I would like to do:   I would like to have an  "Enter" key press behave as if it were a  "Tab" key press.   ie:  When filling in the text boxes on the screen I would like to move from TextBox to TextBox by pressing the "Enter" key.

   I assume I would check for the "Enter Key" in the FF_PUMPHOOK function.  But how would I tell the program to move the focus to the next Tab Order control.
   I know that capturing the "Enter Key" could cause problems with multiline TextBox controls and with RichEdit Controls.   Is this situation would need to be dealt with.

José Roca

Quote
I was expecting to find  %VK_ENTER   but did not find it.  Is it listed differently.

When that constant was defined, the ENTER key was labeled RETURN in the keyboards :)

Rolf Brandt

Quote
   ' Is the message going to the control on the Form that we are interested in?
   If GetParent(Msg.hWnd) = HWND_FORM1 Then
      ' Determine if the ESC key was pressed.
      Select Case Msg.Message
         Case %WM_KEYDOWN
            If Msg.wParam = %VK_ESCAPE Then
            ? "escape"
               SetFocus HWND_FORM1_TEXT1
            End If   
      End Select
   End If

Nice piece of code, Paul. Just came in handy...
Rolf Brandt
http://www.rbsoft.eu
http://www.taxifreeware.com
I cook with wine, sometimes I even add it to the food.
(W. C. Fields)

Paul Squires

Quote
I would like to have an  "Enter" key press behave as if it were a  "Tab" key press.

Modify the FF_PUMPHOOK from the earlier post to act on all ENTER keys being sent to any EDIT (TextBox) control:


      Select Case Msg.Message
         Case %WM_KEYDOWN
            If Msg.wParam = %VK_RETURN Then
               Static zClass As Asciiz * 50
               GetClassName Msg.hWnd, zClass, SizeOf(zClass)
               If UCase$(zClass) = "EDIT" Then
                  ' change the key to be a "TAB" that should move us to the next control
                  Msg.wParam = %VK_TAB
               End If
            End If   
      End Select

Paul Squires
PlanetSquires Software

Martin Francom

#9
That's works wonderfully. 

Is there a way to test for a "MultiLine TextBox"  and if current focus is in a
"MultiLine Textbox"  then do not change %VK_RETURN  to %VK_TAB   so as
not to interfer with editing in a MultiLine TextBox.

I am pretty sure I need to check the TextBox's property of  ES_MULTILINE   I am just
not sure what the correct syntax would be.

I found that changing Enter Key press to a Tab key press does NOT interfer with editing
in an RichEdit Control.   So another way to avoid this problem with multline textboxes is to use a RichEdit Control instead of multiline text boxes on the form where the Enter Key is being captured.

Paul Squires

To test for multiline, try something like the following (not tested):

    If ( GetWindowLong(hWndControl, %GWL_STYLE) And %ES_MULTILINE ) = %ES_MULTILINE Then ....


Paul Squires
PlanetSquires Software

Martin Francom

#11
This didn't have the desired effect.   This stopped  converting %VK_RETURN  to %VK_TAB on all TextBox's.   Just wanted to prevent it on MultLine TextBoxs.
This is how I implimented it.  Maybe I not implimenting it quite the way you had in mind ??


            If Msg.wParam = %VK_RETURN Then
               If (GetWindowLong(HWND_FORM1_TEXT20, %GWL_STYLE) And %ES_MULTILINE ) = %ES_MULTILINE Then Exit Function
               Static zClass As Asciiz * 50
               GetClassName Msg.hWnd, zClass, SizeOf(zClass)
               If UCase$(zClass) = "EDIT" Then
                  ' change the key to be a "TAB" that should move us to the next control
                  Msg.wParam = %VK_TAB
               End If
           End If   



Is there a way to determine what the name of the current active TextBox ?
Th name of the control with focus?

Paul Squires

I guess this is what you're looking for?


      Select Case Msg.Message
         Case %WM_KEYDOWN
            If Msg.wParam = %VK_RETURN Then
               Static zClass As Asciiz * 10
               GetClassName Msg.hWnd, zClass, SizeOf(zClass)
               If UCase$(zClass) = "EDIT" Then
                  If (GetWindowLong(Msg.hWnd, %GWL_STYLE) And %ES_MULTILINE ) <> %ES_MULTILINE Then
                     ' change the key to be a "TAB" that show move us to the next control
                     Msg.wParam = %VK_TAB
                  End If   
               End If
            End If   
      End Select

Paul Squires
PlanetSquires Software

Martin Francom

Thanks again Paul.   
I added a example program, demonstarting how to use what you taught me.

Richard Kelly

#14

     Select Case Msg.Message
         Case %WM_KEYDOWN
            If Msg.wParam = %VK_ESCAPE Then
               PostMessage (GetParent(Msg.hWnd), %WM_CLOSE, 0, 0)
            End If
     End Select


This seems to close all child forms except for the main form (non-MDI) when there are no controls. How do you trap ESC on the main form that has no controls or any form without controls and post a WM_CLOSE?