Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations TouchToneTommy on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

Capture key press in app 6

Status
Not open for further replies.

BiggerBrother

Technical User
Sep 9, 2003
702
GB
I have an app, made of 14 forms and an MDI form. The MDI form has a textbox, used as a command line.

What I want to achieve is that if the user presses a key, and the focus is not currently on another textbox, then the focus snaps to the command line, and the text is entered into the command line.

I realise that VB does not have form_keydown functions that take precidence, and that to use the keydown function, i have to enter this into every control on the forms. Is there any other way to intercept the input from the user?

I guess that it must be an API function, if any, and that is probably the wrong forum, but I reckon it's a good place to start.

Thanks for your help

BB
 
Ok, so any way I do this, I looks like I'm going to have to call a sub from a different if statement for every key.

Sometimes, you find the limitations of vb just a little bit too limiting!

BB
 
You could do something like...(depends what parameters you want to pass etc)


[green]'F2
[/green]KeyResult = GetAsyncKeyState(113)
[blue]If [/blue]KeyResult = -32767 [blue]Then
GoTo [/blue]KeyFound
[blue]End If


[/blue][green]'F3
[/green]KeyResult = GetAsyncKeyState(114)
[blue]If [/blue]KeyResult = -32767 [blue]Then
GoTo [/blue]KeyFound
[blue]End If

[/blue]KeyFound:

[blue]Call[/blue] YourSub(KeyResult)
 
lplates

I'm sorry, but I don't think I understand where you are going. What is the difference between the last post code and the one prior?
In both posts, you are using the same if statement, and it is only true if the key pressed is that which appears in the brackets at the end of the statement. So I would have to write this statement for every key value on the keyboard.

As nicsin said earlier, I wish there was a way to run a routine, and only return the keyvalue, without having to test for every key individually.

BB
 
If you have an Edit box on the MDI form, you can catch a key down in that control's keydown event...


If you catch the key pressed in the form, you do not need GetAsyncKeyState.

So, set the Form.KeyPreview to True.
Then, in the form's KeyPress event:

Private Sub Form_KeyPress(KeyAscii As Integer)
If Not TypeOf Me.ActiveControl Is TextBox Then
Select Case KeyAscii
Case Is > 32
myMDI.Text1.Text = Chr$(KeyAscii)
myMDI.Text1.SetFocus
End Select
Else
'Let the Form's TextBox handle
End If
End Sub
 
Thank you all. MMILLAN and CCLINT, I think this las t solution with the keypreview will be the best way to solve the problem ,and then the 4 forms that are not children, I will have to add this code to them as well.

Thanks for all your help

BB
 
> a way to run a routine, and only return the keyvalue

That's feasible...
 

That it's possible.

But there seemed (for me at least) to be some confusion understanding this thread at all and what was needed (and seemed to have more read into it by others, or too less understood by me), and the the suggestion of using the GetAsyncKeyState function (and of course there is more to it than just "using it" in a timer, as I outlined), which threw in more confusion (for me) into the understanding, and I didn't see the need to use it (maybe I need to read everything again).

What I understand is that you want all text boxes on the active form to catch the keypresses themselves, but key presses in any other control, or the form itself, should be "re-directed" to a text box on the MDI.

I feel anything else, is more than what you need...But then again it's late in the evening.





 
CCLINT - exactly. Thank you.

I have used your latter example, and it works like a dream.

BB
 
Fair enough. But I'll still post my proof of concept of an Application_KeyPreview (as opposed to Form_KeyPreview) idea. For the example you'll need two forms (one with at least a checkbox, textbox and command button; one or two extra controls that can get the focus would also be nice. The second form can have controls or not, as you please). And you'll need a module.

Drop the following code in Form1:
[tt]
Option Explicit

Private Sub chkHookIt_Click()
ApplicationKeyPreview (chkHookIt = vbChecked)
End Sub

Private Sub Command1_Click()
Form2.Show
End Sub

Private Sub Form_Unload(Cancel As Integer)
Application_KeyPreview False
End Sub
[/tt]
Then paste the following into the module:
[tt]
Option Explicit

Private Declare Function GetKeyState Lib "user32" (ByVal nVirtKey As Long) As Integer
Private Declare Function SetWindowsHookEx Lib "user32" Alias "SetWindowsHookExA" (ByVal idHook As Long, ByVal lpfn As Long, ByVal hmod As Long, ByVal dwThreadId As Long) As Long
Private Declare Function CallNextHookEx Lib "user32" (ByVal hHook As Long, ByVal nCode As Long, ByVal wParam As Long, lParam As Any) As Long
Private Declare Function UnhookWindowsHookEx Lib "user32" (ByVal hHook As Long) As Long
Private Declare Function MapVirtualKey Lib "user32" Alias "MapVirtualKeyA" (ByVal wCode As Long, ByVal wMapType As Long) As Long

Private Const WH_KEYBOARD = 2
Private Const HC_ACTION = 0
Private Const VK_SHIFT = &H10
Private Const VK_CAPITAL = &H14

Private prevLowLevelKybd As Long

Public Sub Application_KeyPreview(WantHook As Boolean)
If WantHook = True Then
prevLowLevelKybd = SetWindowsHookEx(WH_KEYBOARD, AddressOf vbKeyboardProc, App.hInstance, 0)
ElseIf prevLowLevelKybd Then
UnhookWindowsHookEx prevLowLevelKybd
prevLowLevelKybd = 0
End If
End Sub


Private Function vbKeyboardProc(ByVal nCode As Long, ByVal wParam As Long, ByVal lParam As Long) As Long
Dim KeyPress As Long

' Is it a keyboard message, with a key going down?
If (nCode = HC_ACTION) And ((lParam And &HC0000000) <> 0) Then

' OK, start processing key
' Note we only have a short period of time to do this, so do as little as possible here...


KeyPress = MapVirtualKey(wParam, 2) ' Convert virtual key code

' Cheap (and flawed, but good enough for sake of example) method of dealing with SHIFT and CAPS LOCK
If ((GetKeyState(VK_CAPITAL) And &H1)) <> 0 Then KeyPress = KeyPress Xor &H20 ' CAPS LOCK ON
If ((GetKeyState(VK_SHIFT) And &H80)) = 0 Then KeyPress = KeyPress Xor &H20 ' SHIFT not pressed

' In this example we just pop the pressed key into a textbox
Form1.Text1.Text = Chr(KeyPress)
End If

' OK, pass everything on for default processing
vbKeyboardProc = CallNextHookEx(0, nCode, wParam, ByVal lParam)

End Function
 
Ok, strongm, so it uses less code, and as space is an issue, i've changed to your example. Star for you too.

Thanks guys for all your help

BB
 
Two things actually Strongm wanted to let you know that I like the post and seems like something I am going to be using question for you... when using your code though I keep getting VB crashes ... occasionally I'll get this when stopping the code and I'll get a form instance creation error that crashes VB and just recently it crashed it on a windows DLL error? eh... any ideas why I seem to be tripping over this?

VB just unhappy about my wanting to use an API catch of my keys? hehe... let me know if you've run into any of these problems and suggestions please. Oh... eh... VB version 6

I always makes things much harder than they should be... that way later I can slap myself in the forhead after spending hours and hours on two lines of code and say to myself &quot;DUH!&quot;
 
Ah, yes. The issue you are facing here is that we are using a hook function, and one really shouldn't try and

a) debug a hook function (don't put a break in the hook function

b) use the End button or the Run/End menu option to stop the program before the hook is unhooked

in the IDE, as this will almost always crash VB. The reason for this is that Windows thinks the hook is still in place and tries to call it - but the routine itself is no longer where Windows expects to find it (because you've stopped the program), which means that Windows actually makes a call to a memory location that now contains junk and tries to run that junk as code...kaboom!

For this example to stop the program, use the form's close button (or the close option on it's window menu) which in turn will ensure that the form's Unload event is called, where you'll notice we unhook the key capture routine.
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top