Keyboard is a very important input device for us to use computers. Even today, manyProgramThe keyboard is still inseparable. But sometimes, some repetitive and tedious keyboard operations are always exhausting, so there is a way to replace people's buttons with programs, in this way, a lot of repetitive keyboard operations can be handed over to the program for simulation, saving a lot of effort, and the keyboard pushing wizard is such a software. So how can we use VB to write a program to achieve a function similar to that of the press Key genie? Let's take a look at the keyboard Event Response Mechanism in windows.
When you press a key on the keyboard, the chip in the keyboard will detect this action and send this signal to the computer. What is the difference between which key is pressed? All the buttons on the keyboard are encoded as a scan code. When you press a key, the scan code of this key is passed to the system. Scan codes are related to specific hardware. The scan codes on different keyboards may be different for the same key. The keyboard controller sends the scan code to the computer and then to the keyboard driver. The keyboard driver completes the work and converts the scan code to a keyboard virtual code. What is a virtual code? Because the scan code is related to hardware and is not universal, the concept of virtual code is proposed to unify the encoding of all keys on the keyboard. No matter what keyboard, the virtual code of the same button is always the same, so that the program can recognize it. To put it simply, virtual codes are constants such as vk_a and vk_ B that we often see. For example, if the virtual code of key A is 65, it is written in hexadecimal notation & H41. Note, people often use hexadecimal notation to represent virtual code. After the keyboard driver converts a scan code to a virtual code, the scan code and other information for this keyboard operation are transmitted to the operating system. The operating system then encapsulates the information in a message and inserts the keyboard message into the message queue. Finally, if there is no accident, the keyboard message will be sent to the current activity window. After the application of the activity window receives the message, you will know which key on the keyboard is pressed, and you will be able to decide what response should be made to the user. This process can be expressed as follows:
Press the button ----- the keyboard driver sends the event to the operating system ----- the operating system inserts the keyboard event into the Message Queue ----- the keyboard message is sent to the current activity window
After understanding this process, we can program and implement a link in it to simulate keyboard operations. In VB, there are multiple methods for keyboard simulation. We will introduce several typical methods.
1. Local Simulation
From the above process, we can see that the keyboard event is finally sent to the activity window, and then the target program responds. The most direct simulation method is: directly forge a Keyboard Message and send it to the target program. Haha, this is really simple. Windows provides several such API functions to send messages directly to the target program. Commonly Used functions include sendmessage and postmessage, the difference between them is that the postmessage function does not care whether the message is directly sent to the target program, and after sendmessage sends the message, it will wait for the target program to return something. Note that you must use the postmessage function to simulate a keyboard message. It is incorrect to use sendmessage (because simulating a keyboard message does not require a return value, otherwise 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 long, lparam as any) as long
The hwnd parameter is the handle of a control in the target program where you want to send a message. The wmsg parameter is the message type, indicating what kind of message you want to send, the wparam and lparam parameters are appended with the message. The specific content is determined by the message.
Let's take a look at the wmsg parameter, which is the only option to simulate the button. Keyboard messages are commonly used as follows:
Wm_keydown indicates that a common key is pressed
Wm_keyup indicates that a common key is released.
Wm_syskeydown indicates that a system key is pressed, for example, alt.
Wm_syskeyup indicates that a system key is released, such as the Alt key.
If you are sure you want to send the preceding keyboard messages, let's take a look at how to determine the wparam and lparam parameters in the keyboard messages. In a keyboard message, the wparam parameter has a simple meaning. It indicates the key-press virtual code of the keyboard event you want to send. For example, you want to simulate pressing the key on the target program, the value of the wparam parameter is set to vk_a. As for the lparam parameter, it is complicated because it contains multiple pieces of information and can be set to 0, however, if you want your simulation to be more realistic, you are advised to set this parameter. Let's take a closer look at lparam. Lparam is a long parameter, which occupies 4 bytes in the memory and is written as binary 00000000 00000000 00000000 00000000 is a total of 32 bits. We start from right to left, assume that the rightmost person is 0th bits (Note that the number starts from 0 rather than 1), and the leftmost person is 31st bits, the 0-15 bits of this parameter indicate the number of key sends and other extended information. The 16-23 bits indicate the scan code of the key, and the 24-31 bits indicate whether to press or release the key. Generally, we are used to writing in hexadecimal notation. It should be & H00 00 00, and the 0-15 bits are generally & h0001. If you press the key, the 24-31 bits are & H00, if the release key is & hc0, how can we get a 16-23-bit scan code? This requires an API function mapvirtualkey, which can convert a virtual code to a scan code or a scan code to a virtual code, you can also convert the virtual code to the ASCII code of the corresponding character. Its VB declaration is as follows:
Declare function mapvirtualkey lib "USER32" alias "mapvirtualkeya" (byval wcode as long, byval wmaptype as long) as long
The wcode parameter indicates the code to be converted. The wmaptype parameter indicates the conversion from what to why. If it is a virtual code to a scan code, the wmaptype is set to 0. If it is a virtual scan code to a virtual code, then, wmaptype is set to 1. If it is a virtual code to ASCII code, wmaptype is set to 2. with this, we can construct the lparam parameter of the keyboard event. The following is a function for constructing 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
The 'parameter virtualkey indicates the key virtual code, and the flag indicates whether to press or release the key, which is expressed by the two constants wm_keydown and wm_keyup.
Dim s as string
24-31 digits of the dim firstbyte as string 'lparam Parameter
If flag = wm_keydown then'
Firstbyte = "00"
Else
Firstbyte = "C0" 'if it is a release key
End if
Dim scancode as long
'Get the key scan code
Scancode = mapvirtualkey (virtualkey, 0)
The 16-23 bits of the dim secondbyte as string 'lparam parameter, that is, the virtual key scan code.
Secondbyte = right ("00" & hex (scancode), 2)
S = firstbyte & secondbyte & "0001" '0001 is the 0-15 bits of the lparam parameter, that is, the number of sent messages and other extended information.
Makekeylparam = Val ("& H" & S)
End Function
This function is called like this. For example, if you press the key, then lparam = makekeylparam (vk_a, wm_keydown) is very simple. It is worth noting that even if you set the value of the lparam parameter when sending a message, the system may reset this parameter according to the current situation when passing the message, the value of lparam in the message received by the target program may be different from the value you sent. Therefore, if you are very lazy, set it to 0 directly without affecting most programs.
Now we can send a Keyboard Message to the target program. First, obtain the handle of the control that the target program receives the message. For example, if the target handle is 12345, We will simulate pressing and releasing the key for the target, as shown in the following figure: (for simplicity, the parameter lparam is not constructed and 0 is directly passed)
Postmessage 12345, wm_keydown, vk_a, 0 & 'press Key
Postmessage 12345, wm_up, vk_a, 0 & 'release key
All right, one button is complete. Now you can try to open notepad and try again. First, use the findwindowex API functions to find the handle of the Notepad program, and then send a Keyboard Message to it, hoping that the notepad will automatically display strange characters.
But you are immediately disappointed. Sorry, why didn't you respond at all? You cheat your feelings ~~~~~~~~~~ 55555555555555 is not. Let's look down.
Generally, the target program contains multiple controls. Not every control responds to the keyboard message. Only the control that sends the Keyboard Message to the control that accepts the message will receive the expected response. For notepad, its editing box is actually an edit class. Only this control can respond to keyboard events. It is useless to send messages to the notepad form. Now you can find the handle of the edit box in the notepad, for example, 54321.Code:
Postmessage 54321, wm_keydown, vk_f1, 0 & 'Press F1
Postmessage 54321, wm_up, vk_f1, 0 & 'release the F1 key
How about it? Did you open the "help" Information in notepad? This indicates that the target program has received the message you sent ~~~~~~~~
Now you can try again. You want to press the key on notepad. Fortunately, the notepad will automatically enter characters. However, there is no response! What is this?
It turns out that if you want to send characters to the target program, the wm_keydown and wm_up events alone will not work yet. You also need an event: wm_char, which indicates a character, the program needs to accept the input characters according to it. Generally, only buttons A, B, and C have wm_char messages. Other keys (such as direction keys and function keys) do not have this message. wm_char messages generally occur after wm_keydown messages. The lparam parameter of the wm_char message has the same meaning as that of other keyboard messages, and its wparam parameter represents the ASCII code of the corresponding characters (which can be entered in Chinese ), now you can write a complete program that automatically writes characters to the notepad. The following is an example with the specific values of these message constants:
Declare function postmessage lib "USER32" alias "postmessagea" (byval hwnd as long, byval wmsg as long, byval wparam as long, 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
24-31 digits of the dim firstbyte as string 'lparam Parameter
If flag = wm_keydown then'
Firstbyte = "00"
Else
Firstbyte = "C0" 'if it is a release key
End if
Dim scancode as long
'Get the key scan code
Scancode = mapvirtualkey (virtualkey, 0)
The 16-23 bits of the dim secondbyte as string 'lparam parameter, that is, the virtual key scan code.
Secondbyte = right ("00" & hex (scancode), 2)
S = firstbyte & secondbyte & "0001" '0001 is the 0-15 bits of the lparam parameter, that is, the number of sent messages and other extended information.
Makekeylparam = Val ("& H" & S)
End Function
Private sub form_load ()
Dim hwnd as long
Hwnd = xxxxxx 'xxxxx indicates the handle of the notepad editing box.
Postmessage hwnd, wm_keydown, vk_a, makekeylparam (vk_a, wm_keydown) 'press Key
Postmessage hwnd, wm_char, ASC ("A"), makekeylparam (vk_a, wm_keydown )'
Postmessage hwnd, wm_up, vk_a, makekeylparam (vk_a, wm_up) 'release key
End sub
This is to simulate the button through a local Keyboard Message. This method has a major benefit: it can implement background buttons, that is, it will not affect your foreground operations. For example, you can use this method to create a program to simulate keys in the game to constantly execute some repeated operations. While drinking tea, you can chat with the MMS on QQ, it will not affect your front-end operations at all. No matter whether the target program gets the focus or not, this is the principle of simulating the buttons in the background ~~~~
2. Global Simulation
You will find that using the above method to simulate keys is not effective for all programs. Some programs, you send a lot of messages to it, but it does not respond at all. What's going on? This depends on the specific situation. For some reasons, some programs (especially some games) will prohibit users from using the simulated key program. How can this be achieved? For example, you can check in the program. If you find that you are not an activity window, you will not accept the Keyboard Message. You can also carefully check the received Keyboard Message and you will find that there are always some minor differences between the real button and the simulated button message. From these differences, the target program can determine: this is false! It's forged !! Therefore, if the simulated button for sending a local message with postmessage fails, you can try the global Keyboard Message to see if the target program can be cheated.
You can use the following methods to simulate global keyboard messages:
(1) Use 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 bvk parameter indicates the virtual code of the key to be simulated, and bscan indicates the scan code of the key (generally 0). dwflags indicates whether to press the key or release the key (press the key to 0, the release key is 2), and dwextrainfo is an extension identifier, which is generally useless. For example, to simulate pressing the key, you can do this:
Const keyeventf_keyup = & H2
Keybd_event vk_a, 0, 0, 0' press Key
Keybd_event vk_a, 0, keyeventf_keyup, 0' release key
Note that sometimes the key speed should not be too fast, otherwise there may be problems, you can use the API function sleep for latency, the Declaration is as follows:
Declare sub sleep lib "Kernel32" (byval dwmilliseconds as long)
The dwmilliseconds parameter indicates the delay time in milliseconds.
How can I simulate pressing the function key? For example, if you want to press Ctrl + C to copy the file, you can:
Keybd_event vk_ctrl, 0, 0, 0' press Ctrl
Keybd_event vk_c, 0, 0, 0' press C
Sleep 500 'latency 500 milliseconds
Keybd_event vk_c, 0, keyeventf_keyup, 0' release C key
Keybd_event vk_ctrl, 0, keyeventf_keyup, 0' release ctrl key
Now, you can try to cheat the target program. This function is effective for most window programs, but some games still ignore the keyboard events it generates. At this time, you need to use the bscan parameter. Generally, bscan transmits 0 messages. However, if the target program is a DirectX game, you need to use this parameter to pass in the scan code correctly and use it to generate correct hardware event messages, to be recognized by the game. In this way, you can write it as follows:
Keybd_event vk_a, mapvirtualkey (vk_a, 0), 0, 0' press Key
Keybd_event vk_a, mapvirtualkey (vk_a, 0), keyeventf_keyup, 0' release key
The above uses 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 relatively low-level. Its VB declaration 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 to which plnputs points.
Plnputs: pointer to the input structure array. Each structure represents an event in the keyboard or mouse input stream.
Cbsize: defines the size of the input structure. If the cbsize is not the size of the input structure, the function call fails.
Return Value: the number of events that are successfully inserted into the keyboard or mouse input stream. To obtain more error information, call the getlasterror function.
Note: The sendlnput function inserts events in the input structure into the input stream of the keyboard or mouse sequentially. These events are not compatible with the input stream of the keybd_event, mouse_event, or other sendlnput plug-in or mouse.
Well, this function is quite complicated to use, because its parameters are pointer-like. To use it to simulate keyboard input, you must first construct a data structure, load the keyboard message you want to simulate, and then pass it to it. For convenience, you can call it directly in a process. 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 23) 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
Sub mysendkey (bkey as long)
'Parameter bkey: Enter the virtual code of the key to be simulated to simulate pressing the specified key.
Dim ginput (0 to 1) as generalinput
Dim kinput as keybdinput
Kinput. wvk = bkey 'the button you want to simulate
Kinput. dwflags = 0' press the key flag
Giinput (0). dwtype = input_keyboard
Copymemory ginput (0). XI (0), kinput, Len (kinput) 'is used to copy the kinput data in the memory to ginput
Kinput. wvk = bkey
Kinput. dwflags = keyeventf_keyup 'release button
Ginput (1). dwtype = input_keyboard 'indicates that the message is a Keyboard Message.
Copymemory ginput (1). XI (0), kinput, Len (kinput)
'The above work adds two keyboard messages to the ginput data structure by pressing the key and releasing the key.
Sendinput 2, ginput (0), Len (ginput (0) 'insert messages stored in ginput to message queue
End sub
In addition to the above, you can use global hooks to simulate keyboard messages. If you have some knowledge about the usage of message hooks in Windows, you can set a global hook to simulate keyboard messages. For example, you can use the wh_journalplayback hook to simulate buttons. Wh_journalplayback is a system-level global hook, which is opposite to the wh_journalrecord function and is often used to record and play back keyboard and mouse operations. The wh_journalrecord hook is used to faithfully record keyboard and mouse operations. Recorded information can be saved to a file, while wh_journalplayback can reproduce these operations. You can also use wh_journalplayback to simulate keyboard operations. You must first declare the setwindowshookex function, which can be used to install the message HOOK:
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
Install the wh_journalplayback hook first, and then you need to write a hook function by yourself. When the system calls it, pass the event you want to simulate to the eventmsg area pointed to by the hook parameter lparam, the simulated button effect can be achieved. However, a side effect of simulating a keyboard event with this hook is that it locks the real mouse and keyboard. However, if you just want to avoid being disturbed by real keyboard operations during the simulation, it is a good idea to use it.
3. Driver-level simulation
If you have tried the above methods, but you find that the target program is still stubborn and does not accept the messages you have simulated ~~~~~~~~~ Fortunately, I still have the last trick, which is driver-level simulation: Directly Reading and Writing the hardware port of the keyboard!
There are some game programs that use the DirectX interface. They bypass the Windows message mechanism when reading the keyboard operation, and use directinput. this is because some games have high requirements on real-time control. For example, racing games require the fastest response to keyboard input. Because Windows messages are in the form of queues, there will be a lot of delay in message transmission, and sometimes more than a dozen messages will be delivered in one second, this speed does not meet the requirements of the game. Directinput bypasses Windows messages and directly deals with keyboard drivers, which of course improves the efficiency. Therefore, no response is made to such a program, whether using postmessage or keybd_event, because these functions are at a higher level. For such a program, you have to use the method of Directly Reading and Writing the keyboard port to simulate hardware events. To use this method to simulate the keyboard, You need to first understand the knowledge of keyboard programming.
In the DOS era, when a user presses or releases a key, a keyboard interruption occurs (if the keyboard interruption is allowed ), in this way, the program will jump to the keyboard interrupt handler in the BIOS for execution. Open the windows Device Manager and you can see that the keyboard controller is controlled by two ports. & H60 is the data port, which can read the keyboard data, and & h64 is the control port used to send control signals. That is, the key information of this keyboard can be read from Port & h60. When a byte is read from this port, the low 7 bits of this byte are the scan code of the key, if the value is 1, the key is pressed or released. When the key is pressed, the highest bit is 0, which is called a code. when the key is released, the highest bit is 1, which is called a code disconnection. Since data can be read from this port to obtain the key information, writing data to this port can simulate the key! A friend who has used qbasic4.5 may know that QB has an out command that can write data to a specified port, while the Gini function can read data from the specified port. Let's first look at how to write code with QB:
If you want to simulate pressing a key and the scan code for this key is & h50, then
Out & h64, & hd2' sends data & hd2 to the & h64 port. This is a KBC command to write data to the keyboard.
Out & h60, & h50' sends the scan code & h50 to Port & h60, which indicates simulating the press of this key with the scan code & h50
What about releasing this key? As shown in the following code, the code for sending the key is:
Out & h64, & hd2' sends data & hd2 to the & h64 port. This is a KBC command to write data to the keyboard.
Out & h60, (& h50 or & h80) 'performs or operations on the scan code & h50 and Data & h80. You can locate 1 in the upper part of the scan code to get a broken code, indicating that the key is released.
Now the question is how to write data to the port in VB. In Windows, normal applications do not have the right to operate ports, so we need a driver to help us implement it. Here we can use a component winio to perform read/write port operations. What is winio? Winio is a free, unregistered, and source program-included Windows2000 port operating driver component (you can download it at http://www.internals.com ). It not only supports port operations, but also memory operations. It can be used not only in VB, but also in Delphi, Vc, and other environments, with excellent performance. Download this component. After decompression, You can see several folders. The three files in the release folder are what we need, and these three files are winio. sys (driver for Windows XP), winio. vxD (used for the driver under WIN 98), winio. DLL (encapsulation function Dynamic Link Library), we only need to call winio. DLL, and then winio. the dll will install and call the driver to complete the corresponding functions. It is worth mentioning that this component is completely green without installation. You only need to copy the three files to the same folder as your program. The usage is very simple. first use the initializewinio function to install the driver, and then you can use getportval to read the port or use setportval to write the port. Well, let's make a driver-level keyboard simulation. Copy the three winio files to the folder of your program, create a new project in VB, add a module, and add the following winio function declaration to the module:
Declare function mapphystolin lib "winio. dll" (byval physaddr as long, byval physsize as long, byref physmemhandle) as long
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 Boolean
Declare function setportval lib "winio. dll" (byval portaddr as integer, byval portval as long, byval bsize as byte) as Boolean
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
'------------------------------------ The above is the winio function declaration -------------------------------------------
Declare function mapvirtualkey lib "USER32" alias "mapvirtualkeya" (byval wcode as long, byval wmaptype as long) as long
'----------------------------------- The preceding is the Win32 API function declaration -----------------------------------------
Add the following process:
Sub kbcwait4ibe () 'Wait for the keyboard buffer to be empty
Dim dwval as long
Do
Getportval & h64, dwval, 1
'Indicates reading a byte from Port & h64 and putting the read data into the variable dwval.
'Getportval is used as the getportval port number to store the read data variable and the read length.
Loop while (dwval and & H2)
End sub
The above is a write process according to the kbc specification. Its function is to wait for a period of time before writing data to the keyboard port, which will be used later.
Then add the following process to simulate the buttons:
Public const kbc_key_cmd = & h64' Keyboard Command Port
Public const kbc_key_data = & h60' keyboard data port
Sub mykeydown (byval vkeycoad as long)
'The simulated press Key, vkeycoad parameter passed in the virtual code of the key
Dim btscancode as long
Btscancode = mapvirtualkey (vkeycoad, 0)
Before sending data, kbcwait4ibe should wait for the keyboard buffer to be empty.
Setportval kbc_key_cmd, & hd2, 1 'send the 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, and the length of the data to be written.
Kbcwait4ibe
Setportval kbc_key_data, btscancode, 1 'write key information, press the key
End sub