The keyboard is a very important input device that we use the computer, even if the mouse big line of the today, many programs still can not leave the keyboard to operate. But sometimes, some repetitive, very cumbersome keyboard operation will always make people tired, so there is a procedure to replace people keys, so you can put a lot of repetitive keyboard operation to the program to simulate, save a lot of energy, key wizard is such a software. Then how can we use VB to write a program, to achieve a similar function with the key wizard? Let's take a look at the mechanisms in Windows that respond to keyboard events.
When the user presses a key on the keyboard, the chip in the keyboard detects the action and transmits the signal to the computer. How do you distinguish which key is being pressed? All keys on the keyboard have an encoding called the keyboard scan code. When you press a key, the scan code for this key is passed to the system. Scan code is related to the specific hardware, the same key, the scanning code on different keyboards may be different. The keyboard controller passes the scan code to the computer and then gives it to the keyboard driver. The keyboard driver will do the work and convert the scan code to a keyboard virtual code. What is a virtual code? Because the scanning code is related to the hardware, it is not universal, in order to unify the coding of all keys on the keyboard, the concept of virtual code is proposed. No matter what keyboard, the same key of the virtual code is always the same, so that the program can be identified. Simply put, the virtual code is what we can often see such as Vk_a,vk_b constant, such as the key A virtual code is 65, written 16 is &h41, note that people often use 16 binary to represent the virtual code. When the keyboard driver converts the scan code to a virtual code, it passes the scan code of the keyboard operation along with the virtual code and other information to the operating system. The operating system then encapsulates this information in a message and inserts the keyboard message into the message queue. Finally, if there is no accident, the keyboard message will eventually be sent to the current active window, the active window in which the application receives the message, you know which key on the keyboard is pressed, you can decide what to respond to the user. The process can be simply as follows:
The user presses the key-----The keyboard driver passes this event to the operating system-----The operating system inserts a keyboard event into the message queue-----The keyboard message is sent to the currently active window
With this process in order, we can programmatically implement one of these steps to simulate the keyboard operation. In VB, there are many ways to achieve keyboard simulation, we introduce a few more typical.
1. Department of Departmental Simulations
As can be seen from the above process, the keyboard event is eventually sent to the active window before it causes the target program to respond. Then the most direct simulation method is: Directly forge a keyboard message to the target program. Haha, this is really very simple, Windows provides several such API functions can be implemented directly to the target program to send messages to the function, commonly used are SendMessage and PostMessage, The difference is that the PostMessage function just keeps the message to the target program regardless, and SendMessage sends out the message and waits for the target program to return something. Note here that the analog keyboard message must be used PostMessage function only good, with SendMessage is not correct (because the analog keyboard message is not required to return the value, or the target program will not respond), remember! The VB declaration of the PostMessage function is as follows:
Declare Function PostMessage Lib "user32" Alias "Postmessagea" (ByVal hwnd as Long, ByVal wmsg as Long, ByVal WParam as Lo Ng, LParam as any) as Long
The parameter HWND is the handle to a control on the target program where you want to send the message, the parameter wmsg is the type of message, the message you want to send, the last wparam and lparam are the data attached to the message, and the content is determined by the message.
Take a look at this parameter of wmsg, to simulate the key to rely on this. Keyboard messages are commonly used in the following sections:
Wm_keydown indicates that a normal key is pressed
Wm_keyup indicates that a common key is released
Wm_syskeydown indicates that a system key is pressed, such as the ALT key
Wm_syskeyup indicates that a system key is released, such as the ALT key
If you are sure you want to send the above keyboard messages, then take a look at how to determine the parameters of wparam and lparam in the keyboard message. In a keyboard message, the meaning of the WParam parameter is simpler, it represents the keyboard event you want to send the key virtual code, such as you want to simulate the target program to press the A key, then the value of the WParam parameter is set to Vk_a, as for the lparam This parameter is more complex, because it contains a number of information, You can usually set it to 0, but if you want your simulation to be more realistic, it is recommended that you set this parameter. So let's learn more about lparam. LParam is a long parameter, it occupies 4 bytes in memory, is written as binary is 00000000 00000000 00000000 1 is 32 bits, we are right-to-left, assuming the rightmost bit is No. 0 bit (note that counting starts from 0 instead of 1 ), the leftmost is the 31st bit, then the parameter of the 0-15-bit indicates the number of times the key is sent and other extended information, 16-23-bit is the key scan code, 24-31-bit indicates whether the key or release key. Everyone generally used to write 16 in the system, then it should be &h00 00 00 00, 第0-15位 generally &h0001, if the key is pressed, then 24-31 bits for &h00, release the key is &HC0, So how did the 16-23-digit scan code get? This requires an API function Mapvirtualkey, which converts the virtual code to a scan code, or converts the scan code to a virtual code, and converts the virtual code to the ASCII code of the corresponding character. Its VB statement is as follows:
Declare Function mapvirtualkey Lib "user32" Alias "Mapvirtualkeya" (ByVal Wcode as Long, ByVal Wmaptype as long) as long
The parameter Wcode represents the code to be converted, the parameter wmaptype indicates from what conversion to what, if is the virtual code to scan the code, then Wmaptype set to 0, if is the virtual scan code to the virtual code, then Wmaptype set to 1, if is the virtual code to the ASCII code, The Wmaptype is set to 2. I believe that with this, we can construct the lparam parameters of the keyboard event. Here is a function to construct the lparam parameter:
Declare Function mapvirtualkey Lib "user32" Alias "Mapvirtualkeya" (ByVal Wcode as Long, ByVal Wmaptype as long) as long
Function Makekeylparam (ByVal virtualkey as Long, ByVal flag as long) as long
' Parameter Virtualkey indicates the key virtual code, flag indicates whether to press the key or release the key, with Wm_keydown and wm_keyup the two constants expressed
Dim S as String
Dim firstbyte as String ' lparam parameter of 24-31 bits
If flag = Wm_keydown Then ' If the key is pressed
Firstbyte = "00"
Else
Firstbyte = "C0" ' If the key is released
End If
Dim Scancode as Long
' Get the key scan code
Scancode = Mapvirtualkey (virtualkey, 0)
Dim secondbyte as String ' lparam parameter of 16-23 bits, i.e. virtual key scan code
Secondbyte = Right ("XX" & Hex (Scancode), 2)
s = firstbyte & secondbyte & "0001" ' 0001 is the 0-15 bits of the lparam parameter, that is, the number of sends and other extended information
Makekeylparam = Val ("&h" & S)
End Function
This function is called like this, such as pressing the A key, then Lparam=makekeylparam (Vk_a,wm_keydown), very simple. It is important to note that even if you set the value of the lparam parameter when you send the message, the system may still be able to reset the parameter according to the current situation when the message is delivered, then the value of lparam in the message received by the target program may be different than when you sent it. So, if you are lazy, or directly set it to 0, for most programs will not have an impact, hehe.
Well, after doing the above, we can now send the keyboard message to the target program. First get the handle of the control that the target program accepts this message, such as the target handle is 12345, then we can press and release the A key to the target simulation, like this: (for the sake of simplicity, lparam This parameter is not constructed, directly pass 0)
PostMessage 12345,wm_keydown,vk_a,0& ' Press the A key
PostMessage 12345,wm_up,vk_a,0& ' Release A key
OK, once the button is done. Now you can wait to open the Notepad to do the experiment, first use FindWindowEx such API function to find the handle of Notepad program, and then send it keyboard message, expect the Notepad can be strange automatically appear characters. But you are immediately disappointed, eh, how little reaction? You cheat feelings ah ~~~~~~~~~~55555555555555 not oh, then look down.
The general target program will contain multiple controls, and not every control will react to the keyboard message, and only the keyboard message sent to the control that accepts it receives the desired response. That Notepad, its edit box is actually an edit class, only this control to respond to keyboard events, if you just send the message to the form of Notepad, it is useless. Now that you find the handle to the edit box for Notepad, say 54321, write the following code:
PostMessage 54321,wm_keydown,vk_f1,0& ' Press the F1 key
PostMessage 54321,wm_up,vk_f1,0& ' Release F1 key
What, did you open the help message for Notepad? This means the target program has already received your message, is it good? ~~~~~~~~
Can immediately new problems come, you want to simulate to Notepad press a This key, in Notepad automatically input characters, but, no response! What's the matter?
Originally, if you want to send characters to the target program, just rely on Wm_keydown and wm_up these two events do not work, but also need an event: WM_CHAR, this message represents a character, the program depends on it appears to accept the input characters. Generally only a,b,c and other such keys have WM_CHAR message, other keys (such as the arrow keys and function keys) is not the message, WM_CHAR message generally occurs after the WM_KEYDOWN message. The lparam parameter of the WM_CHAR message has the same meaning as other keyboard messages, and its wparam represents the ASCII encoding of the corresponding character (which can be entered in Chinese, oh ^_^), and now you can write a complete program that automatically writes characters to the Notepad, and here's an example and the specific values of these Message constants are attached:
Declare Function PostMessage Lib "user32" Alias "Postmessagea" (ByVal hwnd as Long, ByVal wmsg as Long, ByVal WParam as Lo Ng, LParam as any) as Long
Declare Function mapvirtualkey Lib "user32" Alias "Mapvirtualkeya" (ByVal Wcode as Long, ByVal Wmaptype as long) as long
Public Const WM_KEYDOWN = &h100
Public Const WM_KEYUP = &h101
Public Const WM_CHAR = &h102
Public Const vk_a = &H41
Function Makekeylparam (ByVal virtualkey as Long, ByVal flag as long) as Long
Dim s as String
& nbsp; Dim firstbyte as string ' lparam parameter 24-31-bit
If flag = Wm_keydown Then ' If the key is pressed
firstbyte = ' xx '
Else
firstbyte = "C0" "If it is the release key
End If
Dim scancode as Long
' get key scan code
Scancode = Mapvirtualkey (virtualkey, 0)
Dim secondbyte as string ' lparam parameter of 16-23 bits, Virtual key Scan Code
secondbyte = right ("XX" & Hex (Scancode), 2)
s = firstbyte & S Econdbyte & "0001" ' 0001 is the 0-15 bits of the lparam parameter, that is, the number of sends and other extended information
Makekeylparam = Val ("&h" & s)
End Function
Private Sub Form_Load ()
Dim hwnd As Long
hwnd = XXXXXX ' xxxxx represents the handle to the Notepad edit box
PostMessage Hwnd,wm_keydown,vk_a,makekeylparam (Vk_a,wm_keydown) ' Press the A key
PostMessage HWND,WM_CHAR,ASC ("a"), Makekeylparam (vk_a,wm_keydown) ' Input character A
PostMessage Hwnd,wm_up,vk_a,makekeylparam (vk_a,wm_up) ' Release A key
End Sub
This is the use of local keyboard messages to simulate keystrokes. One of the great benefits of this approach is that it can implement a background button, which means that he has no effect on your foreground operation. For example, you can use this method to do a program in the game to simulate the key to continue to perform some repetitive operation, while you are drinking tea and QQ on the MM on the hot chat, it will not affect your foreground operation. Regardless of whether the target program is not affected by the focus, this is the principle of background simulation button ~ ~ ~
2. Global level Simulation
You will find that using the above method to simulate the button is not valid for all programs, some programs Ah, you sent a lot of news to it, but it did not respond at all. What's going on here? This depends on the specific situation, some programs (especially some games) for some reason, it will prohibit users to use the Simulation button program, how to implement it? For example, you can check the program, if you find that you are not the active window, you do not accept keyboard messages. Or carefully check the received keyboard message, you will find that the real button and the simulation of the key message there are always some small differences, from these small differences, the target program can be judged: this is false! It's a forgery!! Therefore, if you use PostMessage to send local message simulation keys are unsuccessful, you can try a global-level keyboard message to see if you can cheat the target program.
The following are some of the common ways to emulate global keyboard messages:
(1) Using the API function keybd_event, this function can be used to simulate a keyboard event, its VB declaration is:
Declare Sub keybd_event Lib "user32" (ByVal bvk as Byte, ByVal bscan as Byte, ByVal dwFlags as Long, ByVal dwExtraInfo as Long)
The parameter BVK represents the virtual code of the key to be simulated, bscan indicates the scan code of the key (generally can pass 0), dwflags indicates whether to press the key or release the key (press the key is 0, the release key is 2), dwExtraInfo is the extension flag, generally no use. For example, to simulate pressing the A key, you can:
Const Keyeventf_keyup = &h2
Keybd_event vk_a, 0, 0, 0 ' Press the A key
Keybd_event vk_a, 0, keyeventf_keyup, 0 ' release A key
Note that sometimes the speed of the key is not too fast, otherwise there will be problems, you can use the API function sleep to delay, declared as follows:
Declare Sub Sleep Lib "kernel32" (ByVal dwmilliseconds as Long)
The parameter dwmilliseconds indicates the time of the delay, in milliseconds.
So what do you do if you want to simulate the press function key? For example, to press CTRL + C to copy this function, you can:
Keybd_event Vk_ctrl, 0, 0, 0 ' hold down the Ctrl key
Keybd_event Vk_c, 0, 0, 0 ' Press the C key
Sleep 500 ' delay 500 ms
Keybd_event Vk_c, 0, keyeventf_keyup, 0 ' release C key
Keybd_event Vk_ctrl, 0, keyeventf_keyup, 0 ' release the Ctrl key
OK, now you can try to be able to cheat the target program, this function for most of the window program is valid, but still have a part of the game on the keyboard event it is not blind, at this time, you need to use bscan this parameter. In general, Bscan are 0, but if the target program is some DirectX game, then you need to use this parameter to pass the scan code correctly, it can produce the correct hardware event message to be recognized by the game. In this case, it can be written like this:
Keybd_event Vk_a, Mapvirtualkey (vk_a, 0), 0, 0 ' Press the A key
Keybd_event Vk_a, Mapvirtualkey (vk_a, 0), Keyeventf_keyup, 0 ' release A key
The above is to use the keybd_event function to simulate keyboard events. In addition to this function, the SendInput function can also simulate global keyboard events. SendInput can directly insert a message into the message queue, which is considered to be the bottom line. Its VB statement is as follows:
Declare Function SendInput Lib "user32.dll" (ByVal ninputs as Long, pinputs as Generalinput, ByVal cbsize as long) as long
Parameters:
Nlnprts: Defines the number of structures that the plnputs points to.
Plnputs: A pointer to an array of input structures. Each structure represents an event inserted into the keyboard or mouse input stream.
Cbsize: Defines the size of the input structure. If cbsize is not the size of the input structure, the function call fails.
Return value: The function returns the number of events in the input stream that were successfully inserted into the human keyboard or mouse. To get more error information, you can call the GetLastError function.
Note: The Sendlnput function inserts events from the input structure into the input stream of the keyboard or mouse in a sequential manner. These events are incompatible with the input stream inserted by the user (either with a mouse or keyboard) or by calling Keybd_event,mouse_event, or another sendlnput plug-in keyboard or mouse.
Well, the function is quite complicated, because its parameters are all things of a pointer type. To use it to simulate keyboard input, first construct a set of data structures, load the keyboard message you want to simulate, and then pass it on. For the sake of convenience, it is done in a process, the use of the time to directly invoke it, the code is as follows:
Declare Function SendInput Lib "user32.dll" (ByVal ninputs as Long, pinputs as Generalinput, ByVal cbsize as long) as long
Declare Sub copymemory Lib "kernel32" Alias "RtlMoveMemory" (pDst as any, pSrc as any, ByVal Bytelen as Long)
Type Generalinput
Dwtype as Long
XI (0 to +) as Byte
End Type
Type keybdinput
WVK As Integer
Wscan as Integer
DwFlags as Long
Time as Long
dwExtraInfo as Long
End Type
Const Input_keyboard = 1
The
Sub Mysendkey (bkey as Long)
' parameter bkey the virtual code to simulate the key to simulate pressing the specified key
Dim ginput (0 to 1) as Generalinput
Dim kinput As keybdinput
Kinput. Wvk = bkey ' The key you want to simulate
Kinput.dwflags = 0 ' Press the key flag
Ginput (0). dwtype = Input_keyboard
CopyMemory Ginput (0). Xi (0), Kinput, Len (kinput) ' This function is used to copy kinput data in memory to Ginput
Kinput. Wvk = bkey
Kinput.dwflags = keyeventf_keyup ' release key
Ginput (1). dwtype = Input_keyboard ' indicates that the message is Keyboard Messages
CopyMemory ginput (1). Xi (0), Kinput, Len (kinput)
' above work press key and release key A total of 2 keyboard messages are added to the GINPUT data structure
SendInput 2, Ginput (0), Len (ginput (0)) ' Insert messages stored in Ginput into message queue
End Sub
In addition to these, the global hooks can also be used to simulate keyboard messages. If you are familiar with the use of message hooks in Windows, you can simulate keyboard messages by setting a global hook, for example, you can use the Wh_journalplayback hook to simulate keys. Wh_journalplayback is a system-level global hook, which is relative to the Wh_journalrecord function and is commonly used to record and replay keyboard and mouse actions. Wh_journalrecord hooks are used to faithfully record the operation of the keyboard and mouse, the recorded information can be saved to the file, and Wh_journalplayback can reproduce the operation. Of course, you can also use wh_journalplayback alone to simulate keyboard operation. You need to first declare the SETWINDOWSHOOKEX function, which can be used to install message hooks:
Declare Function SetWindowsHookEx Lib "user32" Alias "Setwindowshookexa" (ByVal Idhook as Long,byval lpfn as Long, ByVal H MoD as Long, ByVal dwThreadID as long) as long
Install wh_journalplayback This hook first, then you need to write a hook function, when the system calls it, the event you want to simulate to the hook parameter lparam point to the Eventmsg area, you can achieve the effect of the simulation button. But a side effect of using this hook to simulate a keyboard event is that it locks the real mouse keyboard, but it's a good idea to use it if you just want to be able to simulate without being disturbed by the actual keyboard operation.
3. Drive-Level simulation
If the above method you have tried, but you found that the target program is still stubborn do not accept your simulation of the news, cold ~~~~~~~~~ good, I still have the last move, this is the drive-level simulation: directly read and write keyboard hardware port!
There are some game programs that use DirectX interfaces that bypass the Windows message mechanism while reading keyboard operations, and use DirectInput. This is because some games require a higher level of real-time control, such as racing games, which require the fastest response to keyboard input. In the case of Windows messages, which are queued, the message is passed with a lot of delay, and sometimes 1 seconds passes more than 10 messages, which does not reach the requirements of the game. While DirectInput bypasses Windows messages and directly deals with keyboard drivers, the efficiency certainly increases a lot. As a result, there is no response to such programs either with PostMessage or keybd_event, because these functions are at a higher level. For such a program, you have to use a direct read and write keyboard port method to simulate hardware events. To use this method to simulate the keyboard, you need to first understand the keyboard programming related knowledge.
In the DOS era, when a user presses or releases a key, a keyboard interrupt is generated (if the keyboard interrupt is allowed), and the program jumps to the keyboard interrupt handler in the BIOS to execute. Open Windows Device Manager and you can see that the keyboard controller is controlled by two ports. Where &H60 is the data port, can read out the keyboard data, and &H64 is the control port, used to emit a control signal. That is, from the &H60 port can read the key information of this keyboard, when reading a byte from this port, the lower 7 bits of the byte is the key scan code, and the high 1-bit indicates whether the key is pressed or released. When the key is pressed, the highest bit is 0, called the Pass code, when the key is released, the highest bit is 1, called the code breaker. Since the key information can be obtained from reading the data from this port, writing the data to this port can simulate the button! Friends who used QbASIC4.5 may know that there is an out command in QB that can write data to a specified port, and the INP function can read data from a specified port. Let's see if we can write the code with QB:
If you want to simulate pressing a key, the scan code for this key is &H50, that's it.
Out &H64,&HD2 ' sends the data &HD2 to the &H64 port. This is a KBC instruction that will write data to the keyboard
The out &h60,&h50 ' sends the scan code &H50 to the &H60 port, which means that the key that simulates pressing the scan code to &H50
What about releasing the key? Like this, send the key to the broken code:
Out &H64,&HD2 ' sends the data &HD2 to the &H64 port. This is a KBC instruction that will write data to the keyboard
Out &h60, (&h50 or &h80) ' Scan code &h50 with the data &h80 to carry out or operation, you can put it high position 1, to get a broken code, indicating the release of this key
OK, now the question is how to write data to the port in VB. Because in Windows, the normal application is not authorized to operate the port, so we need a driver to help us implement. Here we can use a component Winio to complete the read-write port operation. What is Winio? Winio is an all-free, non-registered, WINDOWS2000 port Operation driver component with source program (can be downloaded to http://www.internals.com/). It can not only operate the port, but also can operate the memory, not only in VB, but also in Delphi, VC and other environments, performance is particularly excellent. Download the component, after decompression can see a few folders, where the release folder under the 3 files is what we need, these 3 files are Winio.sys (for the driver under Win XP), Winio. VXD (for drivers under Win 98), WinIo.dll (dynamic-link library for encapsulating functions), we only need to invoke the function in WinIo.dll, and WinIo.dll will install and invoke the driver to complete the corresponding function. It is worth mentioning that this component is completely green and does not need to be installed, you just need to copy the 3 files into the same folder as your program to use. The usage is very simple, first installs the driver with the inside Initializewinio function, then can use the Getportval to read the port or writes the port with the Setportval. OK, let's do a drive-level keyboard simulation. First copy the Winio 3 files to your program's folder, and then create a new project in VB, add a module, adding the following Winio function declaration in the module:
Declare Function mapphystolin Lib "WinIo.dll" (ByVal physaddr as Long, ByVal physsize as Long, ByRef physmemhandle) as Lon G
Declare Function unmapphysicalmemory Lib "WinIo.dll" (ByVal physmemhandle, ByVal linaddr) as Boolean
Declare Function getphyslong Lib "WinIo.dll" (ByVal physaddr as Long, ByRef Physval as Long) as Boolean
Declare Function setphyslong Lib "WinIo.dll" (ByVal physaddr as Long, ByVal Physval as Long) as Boolean
Declare Function getportval Lib "WinIo.dll" (ByVal portaddr as Integer, ByRef Portval as Long, ByVal bsize as Byte) as Boo Lean
Declare Function setportval Lib "WinIo.dll" (ByVal portaddr as Integer, ByVal Portval as Long, ByVal bsize as Byte) as Boo Lean
Declare Function Initializewinio Lib "WinIo.dll" () as Boolean
Declare Function Shutdownwinio Lib "WinIo.dll" () as Boolean
Declare Function installwiniodriver Lib "WinIo.dll" (ByVal DriverPath as String, ByVal Mode as Integer) as Boolean
Declare Function removewiniodriver Lib "WinIo.dll" () as Boolean
'------------------------------------above is the Winio function declaration-------------------------------------------
Declare Function mapvirtualkey Lib "user32" Alias "Mapvirtualkeya" (ByVal Wcode as Long, ByVal Wmaptype as long) as long
'-----------------------------------above is the WIN32 API function declaration-----------------------------------------
Then add the following procedure:
Sub kbcwait4ibe () ' Wait for the keyboard buffer to be empty
Dim Dwval as Long
Do
Getportval &h64, Dwval, 1
' This means reading a byte from the &h64 port and putting the read data into the variable Dwval
The use of the ' Getportval function is the getportval port number, which holds the variable that reads the data, the length of the read-in
Loop while (Dwval and &H2)
End Sub
Above is a process according to the KBC specification, its role is to wait for a period of time before writing data to the keyboard port, which will be used later.
Then add the following procedure, which is used to simulate the keys in 2 steps:
Public Const kbc_key_cmd = &h64 ' keyboard command port
Public Const Kbc_key_data = &h60 ' Keyboard Data port
Sub Mykeydown (ByVal vkeycoad as Long)
' This is used to simulate pressing the key, parameter vkeycoad the virtual code of the incoming key
Dim Btscancode as Long
Btscancode = Mapvirtualkey (vkeycoad, 0)
Kbcwait4ibe ' should wait for the keyboard buffer to be empty before sending data
Setportval Kbc_key_cmd, &HD2, 1 ' send keyboard write command
The ' Setportval function is used to write data to the port, its usage is the Setportval port number, the data to be written, the length of the write data
Kbcwait4ibe
Setportval Kbc_key_data, Btscancode, 1 ' write key information, press the key
End Sub
Analog mouse keyboard operation, including hardware simulation technology [reprint]