-
how can i capture a key stroke of windows
like a capture Ctrl+B of any application before the
message run to the active window.
i want to get it to did a job. and this program will be acted like a deamon process, running at background.
so how can i create such program.
tong
-
Use the GetAsyncKeyState API function.
Code:
Private Declare Function GetAsyncKeyState _
Lib "user32.dll" (ByVal vKey As Long) As Integer
Private Sub Form_Load()
Timer1.Interval = 100
End Sub
Private Sub Timer1_Timer()
If GetAsyncKeyState(vbKeyControl) Then
If GetAsyncKeyState(vbKeyB) Then
Msgbox "Ctrl+B pressed"
End If
End If
End Sub
-
But that will not catch it before it reaches the active window. In order to do so, you would need to create a global (system-wide) hook.
-
Will this better?
Code:
'//Put this code under the Basic Module
Option Explicit
Declare Function CallNextHookEx Lib "user32" (ByVal hHook As Long, ByVal ncode As Long, ByVal wParam As Long, lParam As Any) As Long
Declare Function GetKeyState Lib "user32" (ByVal nVirtKey As Long) As Integer
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
Declare Function UnhookWindowsHookEx Lib "user32" (ByVal hHook As Long) As Long
Public hHook As Long
Public Const WH_KEYBOARD = 2
Private Const VK_CONTROL = &H11
Public Function KeyboardProc(ByVal idHook As Long, ByVal wParam As Long, ByVal lParam As Long) As Long
If idHook < 0 Then
KeyboardProc = CallNextHookEx(hHook, idHook, wParam, ByVal lParam)
Else
If (GetKeyState(VK_CONTROL) And &HF0000000) And GetKeyState(vbKeyB) Then
MsgBox "Ctrl+B"
End If
KeyboardProc = CallNextHookEx(hHook, idHook, wParam, ByVal lParam)
End If
End Function
Code:
'//Put this code under the Form
Option Explicit
Private Sub Form_Load()
hHook = SetWindowsHookEx(WH_KEYBOARD, AddressOf KeyboardProc, App.hInstance, App.ThreadID)
End Sub
Private Sub Form_QueryUnload(Cancel As Integer, UnloadMode As Integer)
UnhookWindowsHookEx hHook
End Sub
-
thanks.
and i am so sorry if what i wrote is not clear.
what i want is
i want to create my clipboard that get event of a key stroke such as 'Ctrl+A'
ok when you use any program and you want to keep
the screen you just press the key, then it activate my program to keep the current screen in memory.
conclusion
1. my program will run in background
2. it keep looking for a signal, a key stroke, to operate some task.
that is my scenario.
tong.
-
Sorry to interrupt,when u run an application in background and keeps looking for events or keystrokes, do you use a timer to constantly check for the events or keystrokes. Is there any other method?
-
thank you very much heavenhell
your method like active method that keep refresh, using time, information. it comsume more resources.
then, i want passive method that waiting for information which coming and response on it. how can we do?
tong.
-
You would need to create a global hook, and use the KeyboardProc callback function. It's similar to Chris's method, but instead of catching them locally, catch them globally.
-
On a related note...
Is there a way to catch all messages of any sort set to a window? The idea is to record all the mouse and keyboard messages so they can be replicated later.
-
No, a timer isn't the only way. You could have your program simply loop back on itself and give system time back with a doevents(). Have it execute code every 100 clock ticks or whatever.
Also, pressing the print screen button already saves what's on display to the clipboard FYI.
Capturing the keyboard and mouse:
You need to use several different api calls.
Use the ones above for the keyboard.
Use this one for mouse position:
Declare Function GetCursorPos& Lib "user32" (lpPoint As POINTAPI)
Type POINTAPI ' 8 Bytes
x As Long
y As Long
End Type
Obviously, position will only need to be read when a button has been pressed on the mouse.
I can't currently recall how to detect mouse presses. It wouldn't be hard if they click a form of yours.
The only other way i can think of right now is to subclass the message handler and detect the wm_lbuttondown or whatever. A side effect of this is to negate the need for the GetCursorPos api, since mouse x and y client positions are returned.
If any one knows an easier way, please post it. I've been puzzling on this one myself.
-
OK, going with what i said earlier, i did some research and found out that you can actually use the GetAsyncKeyState function shown above to determine the status of the mouse buttons. The Virtual Keys are:
VK_LBUTTON (&H01)
VK_RBUTTON (&H02)
VK_MBUTTON (&H04)
And If your mouse buttons are swapped, it doesn't make
any difference to the function. It detects the actual buttons themselves. Hope this helps.
If you are interested in recording every keystroke, your program might benefit from this subroutine:
Declare Function GetKeyboardState Lib "user32" _(pbKeyState As Byte) As Long
Private Sub Timer1_timer()
Dim keyarray(256) As Byte
dim dl
dl& = GetKeyboardState(keyarray(0))
control% = keyarray(vbKeyControl)
b% =keyarray(vbKeyB)
if (control% AND 128) = TRUE And (B% AND 128) = _
TRUE then msgbox "You pressed ctrl-b"
Virtual key codes work like indexes to the array. Bit one
of each index is "on" or "off" for toggle keys like caps lock. Bit 7 is 1 or 0 depending on if a button was pressed when the snapshot was taken.
So you could have just one API call to "snapshot" the
keyboard button status. This method is superior because of the time involved. Someone might have pressed ctrl-b (or whatever) and while you are processing the ctrl request using getasynckeystate, they might no longer have b pressed. My method insures you can tell they were both pressed at the same time.
If you want to actually INTERCEPT keyboard messages meant for an application and then prevent them from reaching that application, you would have to use some form of subclassing .dll or .ocx, since a vb program can only subclass itself. Since windows messages are sent to the top level window and trickle down to the child window that needs the message, i would guess that (if its possible) you would need to subclass the message handler of the desktop. If windows won't let you, you would need to subclass the message handler of each parent window open. Unless there is a specific application that you had in mind.
-
So, get keyboardstate can check the mouse buttons too? That's cool.
Now, let me see if I understand what you've got there.
keyarray is an array of 256 bytes, and when you do
dl& = GetKeyBoardState(keyarray(0)) it is filling keyarray with the "on" or "off" information for every key.
the b% = keyarray(VK_B) is true or false, and it determines this by checking the status of the byte with an index of VK_B. one question there. I know VK_B is a virtual key constant, but isn't it some weird hex number? If it's going to be an index number, doesn't it have to be an integer? oh, and what does the % after a variable name do?
then, if(B% and 128) = true. What does the 128 mean? I can see that the b% is checking if the previous statement returned true, but what relevance does the 128 have?
Sorry if I seem dense, but those couple things are confusing me.
-
YES, All of it's really COOL.........
for all of your reply it is work very well..
i have got and see that is a solution.....
thanks everyone
tong,
-
an answer to each question you posed about my code:
the keyboard array is filled with the following info: bit 7 is up/down info and bit one is on/off info. thus when i and the value by 128 (binary bit 7) i am ignoring the other bits. 1000000 = 128.
wierd hex number... hex numbers are really regular numbers represented in hex notation...
The API function is designed so that the virtual key you want to check for corresponds with that same index number in the array.
the % (and &) after a variable simply signify what kind of data the variable contains. check your help file, or visit this thread:
http://forums.vb-world.net/showthrea...2&goto=newpost
for an indepth discussion of the use (and why i, in particular, use them) of these symbols.
Hope this helps explain not only how, but WHY my code works.
-
heh heh buggy code. I can possibly see how (b and 128) = true could confuse you. I meant to type:
(ctrl and 128) > 0
(b and 128) > 0
{blush} You might get errors ...
-
actually, i hadn't tested it yet, and just figured that true would evaluate to 1.
-
Hmm, i think what ive been wondering was basicaly the same as what tongbiscom originaly wanted,,,
.... A Key logger :)
-
Quoted:
You could have your program simply loop back on itself and give system time back with a doevents(). Have it execute code every 100 clock ticks or whatever
How do you this?? Can someone tell mi how this can be done.
Thanks
-
sub main()
'sub main is required if youdon't have a form
dim zz as boolean
do
for cl = 1 to 100'set to some arbitrary number.
'the larger the better.
doevents()
next cl
zz= CheckForKeypressSub(ctrl-b)
'checkforkeypresssub is your sub (shown before)
'that you will check for keypresses with
if zz = true then call DoMeWhenTrue()
'DoMeWhenTrue is the code you want activated when
'ctrl-b or whatever is pressed.
'the beauty of this method is it's impossible to call the
'routine more than one time, since keypress checking
'stops while the code is being done.
loop