|
-
Jan 21st, 2010, 01:04 AM
#1
Thread Starter
Lively Member
LowLevelKeyboardProc + Alt key
Hi,
How can I block all possible combinations with Alt key except Alt+Tab combination?
I can simply block Alt key when it is pressed, but then there is no way to allow Alt+Tab.
-
Jan 21st, 2010, 02:10 PM
#2
-
Jan 21st, 2010, 02:25 PM
#3
Re: LowLevelKeyboardProc + Alt key
 Originally Posted by manavo11
Why would you need something like this? Do you want to block it in your app or system wide?
Agreed. If system wide, horrible idea in my opinion. I'm a keyboard vs mouse type of guy. I often use Alt+F4 to close windows and Alt+Accelerator key to access controls in a window, not to mention the window's menu itself.
-
Jan 21st, 2010, 03:06 PM
#4
Thread Starter
Lively Member
Re: LowLevelKeyboardProc + Alt key
 Originally Posted by manavo11
Why would you need something like this? Do you want to block it in your app or system wide?
I want to block it in my app.
-
Jan 21st, 2010, 03:09 PM
#5
Thread Starter
Lively Member
Re: LowLevelKeyboardProc + Alt key
 Originally Posted by LaVolpe
Agreed. If system wide, horrible idea in my opinion. I'm a keyboard vs mouse type of guy. I often use Alt+F4 to close windows and Alt+Accelerator key to access controls in a window, not to mention the window's menu itself.
When I find a way to block Alt key and allow Alt+Tab, I will think about other combinations like Alt+F4. But at the moment, I am not sure how to block Alt, but not combinations with it.
-
Jan 21st, 2010, 03:41 PM
#6
Re: LowLevelKeyboardProc + Alt key
Here is an example of using the low level keyboard hook. In the example, you can see where the ALT key is being tested. Though it is being tested with other keys to block that combination, just reverse it, if the key combo is Alt+Tab then let it thru else don't.
Oops, wrong link posted, this is the right one: http://vbnet.mvps.org/code/hooks/low...yboardproc.htm
Last edited by LaVolpe; Jan 21st, 2010 at 03:58 PM.
-
Jan 22nd, 2010, 01:04 AM
#7
Thread Starter
Lively Member
Re: LowLevelKeyboardProc + Alt key
Ok, that’s my code. It is working, but is it correct? I mean, have I left no mistakes here?
Code:
Function LowLevelKeyboardProc(ByVal nCode As Long, ByVal wParam As Long, lParam As KBDLLHOOKSTRUCT) As Long
If nCode = HC_ACTION Then
If CBool(lParam.flags And LLKHF_ALTDOWN) Then
If lParam.vkCode = VK_TAB Then
Debug.Print "Alt+Tab allowed"
LowLevelKeyboardProc = 0
Else
Debug.Print "Alt blocked"
LowLevelKeyboardProc = -1
End If
Exit Function
End If
End If
LowLevelKeyboardProc = CallNextHookEx(0, nCode, wParam, ByVal lParam)
End Function
I have found this on msdn:
If nCode is less than zero, the hook procedure must return the value returned by CallNextHookEx.
If nCode is greater than or equal to zero, and the hook procedure did not process the message, it is highly recommended that you call CallNextHookEx and return the value it returns; otherwise, other applications that have installed WH_KEYBOARD_LL hooks will not receive hook notifications and may behave incorrectly as a result.
According to this, my code is no correct or is it?
Last edited by riov; Jan 22nd, 2010 at 01:59 AM.
-
Jan 22nd, 2010, 02:09 AM
#8
Thread Starter
Lively Member
Re: LowLevelKeyboardProc + Alt key
But if I use this
Code:
If lParam.vkCode = VK_F4 Then
...
my code is not working. I am lost.
-
Jan 22nd, 2010, 08:42 AM
#9
Re: LowLevelKeyboardProc + Alt key
Do not exit function when you want the key combo to be processed. If you don't pass it to the next hook procedure, that window may not process things correctly. Only exit function if you want to block it.
Now are you using the code from the 2nd link I posted? If so, you shouldn't be using lParam. lParam is a pointer to a KBDLLHOOKSTRUCT structure and in the sample code it clearly shows how to get that structure with CopyMemory. With very minor tweaks to your code, Alt+F4 was blocked easily. Don't take shortcuts.
-
Jan 22nd, 2010, 10:13 AM
#10
Thread Starter
Lively Member
Re: LowLevelKeyboardProc + Alt key
I did what you told me, but still no luck. I know it is something minor, but what?
P.S. I want to allow Alt+F4, not block it.
Code:
Function LowLevelKeyboardProc(ByVal nCode As Long, ByVal wParam As Long, lParam As KBDLLHOOKSTRUCT) As Long
Static kbdllhs As KBDLLHOOKSTRUCT
CopyMemory kbdllhs, ByVal lParam, Len(kbdllhs)
If nCode = HC_ACTION Then
If CBool(kbdllhs.Flags And LLKHF_ALTDOWN) Then
If kbdllhs.vkCode = VK_F4 Then
Debug.Print "Alt allowed"
Else
Debug.Print "Alt blocked"
LowLevelKeyboardProc = -1
Exit Function
End If
End If
End If
LowLevelKeyboardProc = CallNextHookEx(0, nCode, wParam, ByVal lParam)
End Function
Last edited by riov; Jan 22nd, 2010 at 10:29 AM.
-
Jan 22nd, 2010, 12:52 PM
#11
Re: LowLevelKeyboardProc + Alt key
Ok, here's a working example.
1. In a NEW project, add a form and bas module
2. In the form, add this code
Code:
Option Explicit
Private Sub Form_Load()
HookUnhook
End Sub
Private Sub Form_Unload(Cancel As Integer)
HookUnhook
End Sub
3. In the module add this. I took out most of the comments and you can get them from the linked example in post #6 above.
Code:
Option Explicit
Private Const WH_KEYBOARD_LL = 13& 'enables monitoring of keyboard
'input events about to be posted
'in a thread input queue
Private Const HC_ACTION = 0& 'wParam and lParam parameters
'contain information about a
'keyboard message
Private Const LLKHF_EXTENDED = &H1& 'test the extended-key flag
Private Const LLKHF_INJECTED = &H10& 'test the event-injected flag
Private Const LLKHF_ALTDOWN = &H20& 'test the context code
Private Const LLKHF_UP = &H80& 'test the transition-state flag
Private Const VK_TAB = &H9 'virtual key constants
Private Const VK_CONTROL = &H11
Private Const VK_ESCAPE = &H1B
Private Type KBDLLHOOKSTRUCT
vkCode As Long 'a virtual-key code in the range 1 to 254
scanCode As Long 'hardware scan code for the key
flags As Long 'specifies the extended-key flag,
'event-injected flag, context code,
'and transition-state flag
time As Long 'time stamp for this message
dwExtraInfo As Long 'extra info associated with the message
End Type
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 UnhookWindowsHookEx Lib "user32" _
(ByVal hHook As Long) As Long
Private Declare Function CallNextHookEx Lib "user32" _
(ByVal hHook As Long, _
ByVal nCode As Long, _
ByVal wParam As Long, _
ByVal lParam As Long) As Long
Private Declare Sub CopyMemory Lib "kernel32" _
Alias "RtlMoveMemory" _
(pDest As Any, _
pSource As Any, _
ByVal cb As Long)
Private Declare Function GetAsyncKeyState Lib "user32" _
(ByVal vKey As Long) As Integer
Private m_hDllKbdHook As Long 'private variable holding
'the handle to the hook procedure
Public Sub HookUnhook()
'set and obtain the handle to the keyboard hook
If m_hDllKbdHook Then
Call UnhookWindowsHookEx(m_hDllKbdHook)
m_hDllKbdHook = 0&
Else
m_hDllKbdHook = SetWindowsHookEx(WH_KEYBOARD_LL, _
AddressOf LowLevelKeyboardProc, _
App.hInstance, 0&)
If m_hDllKbdHook = 0& Then MsgBox "Failed to install low-level keyboard hook - " & Err.LastDllError
End If
End Sub
Private Function LowLevelKeyboardProc(ByVal nCode As Long, _
ByVal wParam As Long, _
ByVal lParam As Long) As Long
Static kbdllhs As KBDLLHOOKSTRUCT
If nCode = HC_ACTION Then
Call CopyMemory(kbdllhs, ByVal lParam, Len(kbdllhs))
If CBool(kbdllhs.flags And LLKHF_ALTDOWN) Then
Select Case kbdllhs.vkCode
Case VK_TAB
Case vbKeyF4
' add other cases that you want to allow; can be combined on a single line;
' like... Case VK_TAB, vbKey4
Case Else
Debug.Print "Alt blocked"
LowLevelKeyboardProc = 1
Exit Function
End Select
Debug.Print "Alt+key allowed"
End If
End If 'nCode = HC_ACTION
LowLevelKeyboardProc = CallNextHookEx(m_hDllKbdHook, nCode, wParam, lParam)
End Function
Do NOT execute an END statement while hooking, do not END your project while in debug mode. Close your project normally by clicking on the window's captionbar X button. If you do END, suggest closing your VB instance, saving changes, then re-opening. Any hooks applied must be released.
-
Jan 22nd, 2010, 01:17 PM
#12
Thread Starter
Lively Member
Re: LowLevelKeyboardProc + Alt key
THANKS. It works. Except one combination: Alt + Shift. If I add line Case VK_LSHIFT, I get no effect.
Is it because Shift is a special key?
-
Jan 22nd, 2010, 01:30 PM
#13
Re: LowLevelKeyboardProc + Alt key
If VK_LShift is allowed, you should notice that it was allowed as soon as you hit Alt+Shift. Now when you tried a 3rd key: Alt+Shift+5 for example, .vkCode will be vbKey5, you won't know if Shift is down or not, and likewise, if a 4th key was held down, you wouldn't know if Shift or 5 was down previously.
One workaround is simply tracking what is down and what was released. The wParam parameter says if key is down or up during the hook event. See this MSDN documentation
-
Jan 22nd, 2010, 02:12 PM
#14
Thread Starter
Lively Member
Re: LowLevelKeyboardProc + Alt key
There is a combination Alt+Shift (only two keys), which is designed for changing keyboard layout.
Alt+Shift is not working, Alt+F4 is not working (I was wrong, it is unfortunately not working).
If you can, please take a look.
Last edited by riov; Jan 24th, 2010 at 12:52 PM.
-
Jan 22nd, 2010, 03:35 PM
#15
Re: LowLevelKeyboardProc + Alt key
Hmmm, sorry don't have that version of Excel. You probably should have mentioned this VBA related.
-
Jan 22nd, 2010, 03:49 PM
#16
Thread Starter
Lively Member
Re: LowLevelKeyboardProc + Alt key
Ok, that is another version, for 97-2003.
Almost every code in VB works for VBA. In your code I have changed only one thing: App to Application.
Edit:
Meanwhile I will try to explain what I am trying to show you with that xls file. Let’s say I allow Alt+F1. When I hook keyboard and press that combination, Excel receives only F1 instead of Alt+F1, the same happens with all other combinations - Alt+F4, Alt+Shift to name a few. Interesting but Alt+Tab is working.
Last edited by riov; Jan 24th, 2010 at 01:01 PM.
-
Jan 22nd, 2010, 04:03 PM
#17
Re: LowLevelKeyboardProc + Alt key
Maybe I can play with it later. Policies here prevent me from trying to run your macro. However, I did see something in that mvps example that isn't quite right for your situation.
The hModule and dwThreadId parameters of SetWindowHookEx are wrong if the scope of this hook is your workspace only (i.e., not global).
 Originally Posted by msdn
hMod
[in] Handle to the DLL containing the hook procedure pointed to by the lpfn parameter. The hMod parameter must be set to NULL if the dwThreadId parameter specifies a thread created by the current process and if the hook procedure is within the code associated with the current process.
dwThreadId
[in] Specifies the identifier of the thread with which the hook procedure is to be associated. If this parameter is zero, the hook procedure is associated with all existing threads running in the same desktop as the calling thread.
I don't know if Excel has a App.ThreadID like property, if not, you could use this instead:
Code:
' new API
Private Declare Function GetWindowThreadProcessId Lib "user32.dll" (ByVal hWnd As Long, ByRef lpdwProcessId As Long) As Long
m_hDllKbdHook = SetWindowsHookEx(WH_KEYBOARD_LL, _
AddressOf LowLevelKeyboardProc, _
0&, GetWindowThreadProcessId(Application.HWND, 0&))
-
Jan 22nd, 2010, 04:22 PM
#18
Thread Starter
Lively Member
Re: LowLevelKeyboardProc + Alt key
Excel does have Application.Hinstance property.
I can manage the scope of this hook with this line:
Code:
If GetActiveWindow = FindWindow("XLMAIN", Application.Caption) Then
If nCode = HC_ACTION Then
....
However, scope is not the problem here.
Your code blocks Alt key (if I press it alone), so logically thinking how is it possible that if Alt is blocked (which is true), combination of Alt+F1 is not blocked? What we get is something like this:
1) I press and hold Alt - program tells to skip it
2) Then I press F1, program recognizes that Alt+F1 is pressed, so last key, which is F1, is passed, but Alt was skipped in the first place.
And result is that when I press Alt+F1, Excel gets instructions only for F1.
-
Jan 22nd, 2010, 05:37 PM
#19
Re: LowLevelKeyboardProc + Alt key
I'm not sure what to tell you. I can't play along because my version of Excel (2000) doesn't even have an Application.hWnd or .HInstance property. The fact that it works perfectly in VB (i.e., if Alt+anyKey except those I let thru), the project does not get the key. Therefore, even if I press Alt+F1+F2+F3, no key is passed to my project 'cause Alt is held down and none of those Fkeys are let thru.
Obviously it isn't working as advertised for you. I can only make guesses as to why it isn't working & first guess is VBA.
P.S. I was wrong regarding post 17; as it doesn't apply for the low-level keyboard hook.
Edited: Here is a quick sample of what got thru and what did not. Part of the output is from the form itself:
Code:
Alt blocked ' passing Alt+someOtherKey
Alt blocked ' passing Alt+someOtherKey
Alt blocked ' passing Alt+someOtherKey
Alt blocked ' passing Alt+someOtherKey
Alt blocked ' passing Alt+someOtherKey
Alt blocked ' passing Alt+someOtherKey
Alt blocked ' passing Alt+someOtherKey
Alt blocked ' passing Alt+someOtherKey
Alt blocked ' passing Alt+someOtherKey
Alt+key allowed ' passed Alt+F1 & I had F1 allowed
>>> Rcvd KeyCode 112 ' F1 triggered in my form's KeyDown event
Alt+key allowed ' passed Alt+F4 & I had F4 allowed
>>> Rcvd KeyCode 115 ' F4 triggered in my form's KeyDown event
' form unloaded after that message
Last edited by LaVolpe; Jan 22nd, 2010 at 06:05 PM.
-
Jan 23rd, 2010, 02:11 AM
#20
Thread Starter
Lively Member
Re: LowLevelKeyboardProc + Alt key
Ok, so it is not working for you correctly as well. F1 and F4 events in your form must not be triggered, what should be triggered is Alt+F1 and Alt+F4.
That is exactly the same behavior I have. I press Alt+F1 and only F1 is triggered.
-
Jan 23rd, 2010, 01:01 PM
#21
Re: LowLevelKeyboardProc + Alt key
No, it works perfectly & bad wording on the output. I just showed you that the Fkeys came thru. The ALT came through too else my form would not have closed when the Alt+F4 was pressed. It was just a simple output. Trust me, the Alt came thru too.
Edited: If you own VB, you can verify it yourself.
Last edited by LaVolpe; Jan 23rd, 2010 at 02:05 PM.
-
Jan 23rd, 2010, 02:45 PM
#22
Thread Starter
Lively Member
Re: LowLevelKeyboardProc + Alt key
It is sad that you don't have Excel 2007.
-
Jan 23rd, 2010, 02:55 PM
#23
Re: LowLevelKeyboardProc + Alt key
 Originally Posted by riov
It is sad that you don't have Excel 2007.
Matter of opinion 
I very rarely use Excel and honestly, before I purchased another MS Office version of it, I'd give OpenOffice a shot first.
-
Jan 23rd, 2010, 03:20 PM
#24
Re: LowLevelKeyboardProc + Alt key
I don't know if this will be any better, but it doesn't use the LowLevel hook type, it uses the old-fashioned standard keyboard hook. Note that this does require the ThreadID. I've extracted this from existing projects of mine before the lowlevel option existed.
Code:
Option Explicit
Private Const WH_KEYBOARD As Long = 2
Private Const HC_ACTION = 0& 'wParam and lParam parameters
Private Const VK_TAB = &H9 'virtual key constants
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 UnhookWindowsHookEx Lib "user32" _
(ByVal hHook As Long) As Long
Private Declare Function CallNextHookEx Lib "user32" _
(ByVal hHook As Long, _
ByVal nCode As Long, _
ByVal wParam As Long, _
ByVal lParam As Long) As Long
Private Declare Sub CopyMemory Lib "kernel32" _
Alias "RtlMoveMemory" _
(pDest As Any, _
pSource As Any, _
ByVal cb As Long)
Private Declare Function GetAsyncKeyState Lib "user32" _
(ByVal vKey As Long) As Integer
Private m_hDllKbdHook As Long 'private variable holding
'the handle to the hook procedure
Public Sub HookUnhook()
'set and obtain the handle to the keyboard hook
If m_hDllKbdHook Then
Call UnhookWindowsHookEx(m_hDllKbdHook)
m_hDllKbdHook = 0&
Else
m_hDllKbdHook = SetWindowsHookEx(WH_KEYBOARD, _
AddressOf LowLevelKeyboardProc, _
0&, App.ThreadID)
If m_hDllKbdHook = 0& Then MsgBox "Failed to install low-level keyboard hook - " & Err.LastDllError
End If
End Sub
Private Function LowLevelKeyboardProc(ByVal nCode As Long, _
ByVal wParam As Long, _
ByVal lParam As Long) As Long
If nCode = HC_ACTION Then
If lParam < 0& Then 'wParam are vbKey... variables
Debug.Print "Keycode: "; wParam; Chr$(wParam), "key is up"
Else
If (lParam And &H40000000) Then
Debug.Print "Keycode: "; wParam; Chr$(wParam), "key is held down"
Else
Debug.Print "keycode: "; wParam; Chr$(wParam), "key is down first time"
End If
End If
' to test if extended key is pressed: (((lParam And &H1000000)) <> 0)
' to test if ALT is also pressed: (((lParam And &H20000000)) <> 0)
If ((lParam And &H20000000)) Then
Select Case wParam
Case vbKeyF1, vbKeyF4, VK_TAB
Debug.Print "Alt+Key allowed"
Case Else
Debug.Print "ALT+key blocked"
LowLevelKeyboardProc = 1
Exit Function
End Select
End If
End If 'nCode = HC_ACTION
LowLevelKeyboardProc = CallNextHookEx(m_hDllKbdHook, nCode, wParam, lParam)
End Function
Last edited by LaVolpe; Jan 23rd, 2010 at 03:45 PM.
-
Jan 23rd, 2010, 03:46 PM
#25
Thread Starter
Lively Member
Re: LowLevelKeyboardProc + Alt key
When this code is executed I get something like infinite loop. LowLevelKeyboardProc is beeing called N+1 times.
-
Jan 23rd, 2010, 03:49 PM
#26
Re: LowLevelKeyboardProc + Alt key
Well it was a thought. I assume you supplied the ThreadID and changed the call the SetWindowsHookEx as shown in the newly posted code?
Because it works in VB and not Excel, I can only assume Excel is preprocessing somehow or that not passing to the next hook is interferring with Excel or something else. How MS Office wraps the VBA modules and what does and does not screw that relationship, I do not know.
-
Jan 23rd, 2010, 03:50 PM
#27
Thread Starter
Lively Member
Re: LowLevelKeyboardProc + Alt key
I was trying a workaround – to use SendInput. As long as I can indentify when Alt+Key is pressed, I can send that combination. Unfortunately, that didn’t work either.
Is it a problem without a solution? I am almost convinced it is…
-
Jan 23rd, 2010, 03:51 PM
#28
Thread Starter
Lively Member
Re: LowLevelKeyboardProc + Alt key
I have used GetCurrentThreadId. GetWindowThreadProcessId have not worked at all for me.
Last edited by riov; Jan 23rd, 2010 at 03:58 PM.
Tags for this Thread
Posting Permissions
- You may not post new threads
- You may not post replies
- You may not post attachments
- You may not edit your posts
-
Forum Rules
|
Click Here to Expand Forum to Full Width
|