Introduction

CKeystrokeEngine was originally written to allow users of my product,
Macro Angel, to send keystrokes to the
active or to a selected window. Its functionality is similar to VB's SendKeys's functionality, but it allows more complex operations. In addition
to sending keystrokes to the active window, by the help of CWindowEngine
(which was also written for Macro Angel),
it can send keystrokes to only a specified window.

SetPause (bool bPause, int nPause)<br>
Adjusts how much time CKeystrokeEngine should wait in-between
each key-press when sending keystrokes. On some faster machines, CKeystrokeEngine
may type the keys too quickly, flooding the keyboard buffer and causing unpredictable
results. Increasing this setting will prevent this from occurring.

SetSendToWnd (bool bSendToWnd)<br>
If bSendToWnd is true, then CKeystrokeEnginesends all
keystrokes to a specified window. By this way, sending keystrokes to wrong windows
is prevented.

If bSendToWnd is set to false, then active window gets all keystrokes.

SetWndTitle (LPCSTR lpszTitle)<br>
Sets the window title, to which the keystrokes will be sent. If lpszTitle
is set to NULL, then CKeystrokeEngine does not searh for a window
title. Note that this is effective only if SetSendToWnd (true)
is used.

SetWndClass (LPCSTR lpszClass)<br>
Sets the window class, to which the keystrokes will be sent. If lpszClass
is set to NULL, then CKeystrokeEngine does not search for a window
class. Note that this is effective only if SetSendToWnd (true)
is used.

SetExactMatch (bool bExact)<br>
Specified whether the Windows title entered is a partial title match
or must match exactly. When set to false,CKeystrokeEngine will
search for window titles that contain that text. Note that this is effective
only if SetSendToWnd (true) is used.

SetCaseSensitive (bool bCaseSensitive)<br>
If enabled, Window Title/Window Class and Text searches would be
case sensitive. Note that this is effective only if SetSendToWnd (true)
is used.

SetReActivate (bool bReActivate, int nMiliseconds)<br>
If bReActivate is set to true, then CKeystrokeEngine
automatically re-activates the window whenever it looses focus. If 0 seconds
is entered, then the window is immediately activated when it looses focus. Otherwise,
CKeystrokeEngine waits for the specified amount of time and then
re-activates the window.

Adding a delay before re-activating windows prevents collisions between applications
that are trying to send keystrokes at the same time.

Note that this is effective only if SetSendToWnd (true)is used.
Also, if bReActivate is set to false, and specified window looses focus, then
SendKeys () function returns false.

bool SendKeys ()<br>
Finally, this functions sends the keys with the specifed options.
Use this function setting all attributes of CSendKeystrokes.

To get more information about the supported keywords, please use the sample
application...

Some points that you should keep in mind

To use CKeystrokeEngine in your applications, copy KeystrokeEngine.cpp,
KeystrokeEngine.h, WindowEngine.cpp and WindowEngine.h into your project and
include KeystrokeEngine.h in your cpp file.

This class uses its own syntax, instead of using VBs SendKeys () syntax.
Please don't want me to change the syntax. My customers are really happy with
this syntax :)

This class is not used in the current version of Macro
Angel. It will be used in the next version. Current version uses the same
syntax, but the implementation is not as good as this. But this is class is
not tested yet and may include some bugs. Please send me the bugs, so that
I can fix them. If you find a bug, please send me the String that causes is
not working properly. Also, please send me the real output and the expected
output.

The article was not actually updated. I put my e-mail adresses into all my articles and my stupidity paid of well by hundreds of spam e-mails every day.

So, I contacted to the CodeProject and told them that I want to remove my e-mail address. They did it in a few hours (thanks ) but the articles showed as updated. I am sorry for the confusion.

Actually, I have another Keystroke Engine that is based on an MSDN articles code - this new engine works fine on Windows Xp/2000/NT but does not support win9x/me. It also works with different locales and it can send any unicode characaters. I think I will send another article with that engine

PS: If you send me an e-mail via Codeproject's e-mail options, I can send it to you...

Mustafa Demirhanhttp://www.macroangel.com<font color=#757575>"What we do in life echoes in eternity" - GladiatorIt's not that I'm lazy, it's just that I just don't care

I´m facing the same issue JessicaLampe highlighted, I cannot send <alt> keys. I use Windows XP sp1 with all the updates from Windows Update and my keyboard layout it´s set to portuguese(ABNT2) did you find what is going on?

And the last one...Are you still developing MacroAngel? Or even CKestrokeEngine?

I actually developped a completely different Keystroke engine, but I did not send it to the code project yet

The new code was based on an MSDN article's sample code. I modified it and added my own features. It seems to be working perfectly, but I dont know whether I should post that too or not - I first need to consult the author of the MSDN article and see if I have the rights to re-distribute a modified version of it.

I am still developping Macro Angel but I couldnt spend as much time as I should spend on it

Mustafa Demirhanhttp://www.macroangel.com<font color=#757575>"What we do in life echoes in eternity" - GladiatorIt's not that I'm lazy, it's just that I just don't care

Does it send other keys? The reason that I am asking this question is that latetly, one of WinXP patches caused some problems with sending ALT key. I dont know what the problem is exactly, but even some popular automation programs are affected by this (like Automate).

Mustafa Demirhanhttp://www.macroangel.com<font color=#757575>"What we do in life echoes in eternity" - GladiatorIt's not that I'm lazy, it's just that I just don't care

I dont know if it is a problem with WinXP or not. But I installed some patches, and the code couldnt sent ALT key after that. After a few weeks, I installed more updates and the code started to work correctly again.Then I read from some forums that other people had the same problem.

That is all I know :(

If the code above works correctly, then my SendKeys function should also work, because it does essentially the same thing. Could you please try to add a delay before sendkeys (something like "[DELAY 1000][ALT][F4]"). May be my code sends the key before the window is fully focused and adding a delay may solve the problem.

Upps, I just realized one thing: In my code, I use

keybd_event(VK_MENU, MapVirtualKey(VK_MENU, 0 ), KEYEVENTF_EXTENDEDKEY | 0, 0);However, in your code, you dont have KEYEVENTF_EXTENDEDKEY there. So, could you please change the code on line 281 as follows:

Ok, now I surely believe that this problem is because of a WinXP patche. In some forums, people wrote that when they replace VK_MENU with VK_LMENU, the problem is solved. Here are two quotes that I found on the Internet.

Windows XP Home 5.1.2600 SP1 Intell 2,4mhz IE 6.0.2800.1106.xpsp2.030422-1633. This morning I had a screen note from Microsoft that an update was ready. I answered yes. All seemed to go as usual but...Finally did run some Autom5.5 tasks and noticed that usual IE commands like sendkey 'alt+f' etc etc did not work at all. The only way I escaped was to use the 'windows update' cancel function in order to return the system to the state few days before. Anyone with same kind of problems? What to do in order to avoid such. The update files were: 814078, KB824141, KB823182, KB825119, KB828035. I did inform MS about this.

After thorough testing, I come to the following conclusion :

One recent windows update out of KB824141, 823182, 825119, 828035 (I don't know exactly which one, and don't have time to search) is causing Automate Send Key action to mis-interpret the {ALT} key as the {RIGHTALT} key, which is the 'Alt Gr' Key. Therefore the tasks do no longer work as expected.

When specifying {LEFTALT} instead of {ALT} the step works nicely. This is the workaround that Automate users may/must use until Unisyn has released a fix.

Jean Delfosse

So, my suggestion is to replace all VK_MENU s with VK_LMENU within my code and try it again. And please tell me if it works or not. I hope it works this time

Mustafa Demirhanhttp://www.macroangel.com<font color=#757575>"What we do in life echoes in eternity" - GladiatorIt's not that I'm lazy, it's just that I just don't care

Oh no...I found these article also and had replace all VK_MENUs with VK_LMENUs within your code. Now no ALT or ALT-Gr is send to the window.Are you sure, that all VK_MENUs should be replaced?

I search in the internet to solve the problem. I found the following article:

1.: ALT keys

Left AltLeft Alt on the PC layout corresponds to the Alt Function on the VT layout.Depressing the left Alt key performs the following functions (unless re-programmed):

- Left Alt/Space acts as the compose key in VT Style. - On the North American PC layout, left Alt is the same as Alt Gr when pressed and held in combination with keys from the numeric keypad. This feature keeps the two Alt keys equivalent to each other.

Right AltThe right Alt key appears on the North American, Hebrew, and Greek PC layouts. Onother country layouts, the right Alt key appears as Alt Gr. Depressing the right Altkey performs the following functions (unless re-programmed):

- Right Alt/Space acts as the compose key in VT Style. This feature keeps the two Alt keys equivalent. - Right Alt key is the same as the Alt Gr key when pressed and held in combination with keys from the numeric keypad. - The right Alt key is the same as the Right Alt function on the VT layout with the exceptions listed previously.

Alt GrThe right Alt key is marked as Alt Gr on some Enhanced PC layouts. The words Alt Grare short for alternate graphic and corresponds roughly to the function of the composekey.

- Alt Gr in combination with graphic character keys generate the character corresponding to the right side of the keyboard. - Alt Gr is used for numeric keypad compose.

Oh no...I found this article also and had replace all VK_MENUs with VK_LMENUs within your code. Now no ALT or ALT-Gr is send to the window.Are you sure, that all VK_MENUs should be replaced?

I search in the internet to solve the problem. I found the following article:

1.: ALT keys

Left AltLeft Alt on the PC layout corresponds to the Alt Function on the VT layout.Depressing the left Alt key performs the following functions (unless re-programmed):

- Left Alt/Space acts as the compose key in VT Style. - On the North American PC layout, left Alt is the same as Alt Gr when pressed and held in combination with keys from the numeric keypad. This feature keeps the two Alt keys equivalent to each other.

Right AltThe right Alt key appears on the North American, Hebrew, and Greek PC layouts. Onother country layouts, the right Alt key appears as Alt Gr. Depressing the right Altkey performs the following functions (unless re-programmed):

- Right Alt/Space acts as the compose key in VT Style. This feature keeps the two Alt keys equivalent. - Right Alt key is the same as the Alt Gr key when pressed and held in combination with keys from the numeric keypad. - The right Alt key is the same as the Right Alt function on the VT layout with the exceptions listed previously.

Alt GrThe right Alt key is marked as Alt Gr on some Enhanced PC layouts. The words Alt Grare short for alternate graphic and corresponds roughly to the function of the composekey.

- Alt Gr in combination with graphic character keys generate the character corresponding to the right side of the keyboard. - Alt Gr is used for numeric keypad compose.

If I change the regional options for a window (for example Notepad) to English the "Alt"-key is send correctly.

Ok, I have to send a message like:ActivateKeyboardLayout(LoadKeyboardLayout("00000809", KLF_ACTIVATE), 0); // for Englisch-Keyboard

to the window. Could you help me, how it's functioned? (Perhaps in the Focus section of "WindowEngine"?)

An other fact from the WinUser.h:

* VK_L* & VK_R* - left and right Alt, Ctrl and Shift virtual keys.* Used only as parameters to GetAsyncKeyState() and GetKeyState().* No other API or message will distinguish left and right keys in this way.*/#define VK_LSHIFT 0xA0#define VK_RSHIFT 0xA1#define VK_LCONTROL 0xA2#define VK_RCONTROL 0xA3#define VK_LMENU 0xA4#define VK_RMENU 0xA5

What does it means? Is it possible to send these key in your code instead of VK_MENU for example?

hi,first thanks for writing this code. It works fine , but I found a little bug :Each call to SendKeys() creates, but never destroyes a CWindowEngine object.Because of the lots of returns this bug is not fixed in a minute...As a first hack I did it at the 2 "return true" exits, so there are no morememory leaks as long as no error occured.May be it's better first to give SendKeys() a better structure with only onereturn...

ThoRa wrote:Each call to SendKeys() creates, but never destroyes a CWindowEngine object.

You are wrong. There are no memory leaks in the code and there cannot be. I never allocated any memory on the heap. Thus I never need to do the deallocation.

And in the SendKeys () method, I again create an object on the stack, not on the heap. Here is the source fragment from the SendKeys function. Can you please tell me how this code can generate a memory leak?

- a SetKey( ) to change key on the fly while maintaining settings (I've done in few seconds but I think is interesting for all)- a <WAIT xxxx> to allow only after some keystroke (think about a menu item accelerator key that execute some operation) to sleep macro execution - an Execute function to launch program if not still in memory (it's simple to implement also externally - like I do - but we have to double code to FindWindow)

hi, first i wanted to thank you for writing this piece of code, I've spent at least 6 hours just searching for a .dll or activex plugin that will simply let vc++ 6 hit keys for me...

basically i am wondering if you have a minimal code that would just emulate key presses in whatever window the user is in (this will be used with an ir remote control to run shortcuts, fastforward etc.)

thanks again, i'm sure i'll figure it out (by decomposing ur program) if u dont have time to help....

I dont exactly understand what you mean by "minimal code". If you mean without windows support, you can remove a few lines from the code and you will get the minimal part of the code.

I am sorry that I don't have any other code for now :(

Also, I am planning to post a new version of this code. I am now using some mix of my code and John Robbins' code. Check out March '02 Bugslayer Code from MSDN magazine. That piece of code is also great.

I opened a new project and added WindowEngline.cpp, WindowEngine.h, KeystrokeEngine.cpp and KeystrokeEngine.h with #include "KeystrokeEngine.h" in Ready.cpp. When I compile the project without making any other changes I get these errors:

how can to run several keyboard senders each of which control/automate a separate window application.The senders are independent and not synchronized, so with this solution they will compete each other to make their own controlled windows foreground. So, there is no guarantee that a key sequence will reach a proper window, since sequences are really directed to a currently active window but not to a specific window by given handle.

Yes, but you can set the option to send a window and re-activate the window automatically. By this way, the keys will always be sent to the correct window and that window will be automatically reactivated if it looses the focus...

Looks like it will only work if you have a single a keyboard sender (controller)Unfortunately, my case is more complicated. I need to run several keyboard senders each of which control/automate a separate window application.The senders are independent and not synchronized, so with this solution they will compete each other to make their own controlled windows foreground. So, there is no guarantee that a key sequence will reach a proper window, since sequences are really directed to a currently active window but not to a specific window by given handle.

Thanks a lot for the notifications. I used VS.NET for a while and because of the lack of Class Wizard, I returned back to VS6. Since i dont have VS.NET right now, i am unable to test it, but these changes will help to the .NET users. Thank you very much.

PS: I think these changes are just for the demo application. If you just want to use the base source, you dont need any changes. Right?

Your article is good. In one of my application, i use MSDataGrid. Just like MS-Access(while deleting one or some rows, it will ask 'are you sure to delete 5 rows?') I want to do in my application. For that, i have to check whether the control is focussed on the datagrid and one or some rows are selected and check whether the user pressed 'Delete' button. I want to do this in a simple message handler function. Thanks in advance.

I got my XP yesterday and tested the program. As you said, it just activates Notepad and then stops. I think some window functions are changed in XP. IMHO, SetForegroundWindow () is not synchronous anymore. Because, the program class calls SetForegroundWindow and assumes that it is the foreground window after this call. However, this is not the case in XP. I dont know what , but I will have a look at this issue.

Mustafa Demirhan wrote:IMHO, SetForegroundWindow () is not synchronous anymore. Because, the program class calls SetForegroundWindow and assumes that it is the foreground window after this call.

Yes, I use another automation tool (AutoIt), and read the corresponding mailing list. I saw that the AutoIt author had some problems with XP (and perhaps Win2000) because these systems may forbid to make a window foreground.

I believe that's because users (like me) were upset to navigate the Start menu (or any other menu) and loose the focus and the menu because another window goes foremost...

That's a good thing, except when the users want the window to go foreground, eg. when activating a window instance (check if already open) or in automation projects.

The AutoIt author had to use 5 or 6 different methods (one by one) to be sure to get the desired window foremost. He didn't gave the algorithm But I believe he used every method in the book, testing each time if it was effective...