• Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 3844
  • Last Modified:

c# keybd_event Problem

Hi gang,

I have trawled the forums for an answer to this problem without success so here goes.

I have an application written in c# that must monitor and control 2 other application. In short I need to be able to send either a CTRL or ALT message to one of the applications. I have tried several approaches the most successful being the Keybd_event & PostMessage Combination set out below. The problem is that while the code below works fine on my development machine, it seems that the Keybd_event function fails 1 in 3 times on some machines in the production environment. What I need a is something that will guarantee delivery of the message.

Also note that the application to recieve the keystrokes may or may not always have focus.

public static void PostMacro(IntPtr hWnd, int nFunctionKey)
            {
                  ulong lKeyStatus;
                  //Sends a predifined Macro
                  lKeyStatus = 0x1C << 16 | 0x1;
                  bool bOk = false;
                  int i = 0; // Ensure the function keybd_event does not iterate forever and lock the ctrl key
                  do
                  {
                        bOk = Win32API.keybd_event( (byte)Keys.VK_CONTROL, 0x45, KEYEVENTF_EXTENDEDKEY, UIntPtr.Zero );
                        bOk = false;
                        i++;
                  }
                  while(!bOk && i < 1000);
                  Win32API.PostMessage(hWnd, (uint) Keys.WM_KEYDOWN, nFunctionKey, lKeyStatus);
                  lKeyStatus ^= 0x80000000;
                  Win32API.PostMessage(hWnd, (uint) Keys.WM_KEYUP, nFunctionKey, lKeyStatus);
                  i = 0;
                  do
                  {
                        bOk = Win32API.keybd_event( (byte)Keys.VK_CONTROL, 0x45, KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, UIntPtr.Zero );
                        i++;
                  }
                  while(!bOk && i < 1000);
            }

Any suggestions greatly appreciated.

Due to the amount of time I have aready wasted exploring alternatives time has become critical so I'm offering 500 points.
JC
0
JesusHatesMe
Asked:
JesusHatesMe
  • 4
  • 3
1 Solution
 
Mike TomlinsonMiddle School Assistant TeacherCommented:
You should be able to depress/release the control using code like this:

        [DllImport("user32.dll", CharSet = CharSet.Auto, ExactSpelling = true, CallingConvention = CallingConvention.Winapi)]
        public static extern void keybd_event(byte bVk, byte bScan, int dwFlags, int extraInfo);

        [DllImport("user32.dll")]
        static extern short MapVirtualKey(int wCode, int wMapType);

        private void button1_Click(object sender, EventArgs e)
        {
            // Ctrl-V (paste) example
            keybd_event((int)Keys.ControlKey, (byte)MapVirtualKey((int)Keys.ControlKey, 0), 0, 0); // Control Down
           
            keybd_event((int)Keys.V, (byte)MapVirtualKey((int)Keys.V, 0), 0, 0); // V Down
            keybd_event((int)Keys.V, (byte)MapVirtualKey((int)Keys.V, 0), 2, 0); // V Up

            keybd_event((int)Keys.ControlKey, (byte)MapVirtualKey((int)Keys.ControlKey, 0), 2, 0); // Control Up                
        }
0
 
JesusHatesMeAuthor Commented:
Thanks for the response and this approach does work however the application receiving the keystrokes must have focus. I was hoping to find a solution where by I could send the ctrl modifier key without the application having to be activated or have focus. The original code I posted does do this but seems to run into problems in our live environment. I guess what I need is something that will guarantee the delivery to a given handle such as PostMessage, however as I understand the PostMessage API function it is not possible to post modifier keys to an application.

The approach you have suggested here requires that the application have focus. Now approach would be fine however, I have run into problems trying to activate the application window to have focus. I have used SetActiveWindow, SetForgroundWindow and SetFocus all of which do work fine on my developement machine. However, once again in the live environment these API calls often fail and only cause the application window to flash in the task bar rather than actually activate and give focus to the application to recive the keystrokes, hence the keybd_event call fails to deliver the keystrokes.
0
 
Mike TomlinsonMiddle School Assistant TeacherCommented:
"only cause the application window to flash in the task bar rather than actually activate and give focus to the application to recive the keystrokes,"

The behaviour you are describing is a feature of windows that "prevents applications from stealing focus".  Instead of apps taking the focus, they instead blink either indefinitely or for a configured number of times in the taskbar.  These setttings are stored in the registry.  The easiest way to change these settings are through Microsofts Tweak UI utility.

Download the Tweak UI tools from Microsoft:
http://www.microsoft.com/windowsxp/downloads/powertoys/xppowertoys.mspx

Here are the releveant registry values:
http://www.microsoft.com/resources/documentation/Windows/2000/server/reskit/en-us/Default.asp?url=/resources/documentation/Windows/2000/server/reskit/en-us/regentry/55199.asp
http://www.microsoft.com/resources/documentation/Windows/2000/server/reskit/en-us/Default.asp?url=/resources/documentation/Windows/2000/server/reskit/en-us/regentry/55200.asp

~IM
0
Concerto Cloud for Software Providers & ISVs

Can Concerto Cloud Services help you focus on evolving your application offerings, while delivering the best cloud experience to your customers? From DevOps to revenue models and customer support, the answer is yes!

Learn how Concerto can help you.

 
JesusHatesMeAuthor Commented:
Thanks for the response IM, I didn't realise that those registry setting existed.... well that explains the reason for the SetActiveWindow problem, sadly though QA are not happy for me to go around changing the registry setting for all user in production so I'm back to square one...

If I could work out how to set the ALT modifier key with a letter key with PostMessage then the need for focus problem could be avoided.
It seems the AnzioWin terminal app processes messages differently to other apps such as IE when I check the messages sent via spy++
0
 
Mike TomlinsonMiddle School Assistant TeacherCommented:
I'll see what I can find...
0
 
JesusHatesMeAuthor Commented:
Hi IM,  I've finally worked out how to send a key with the alt modifier:

            public static void PostMacro(IntPtr hWnd, int nFunctionKey)
            {
                  ulong lKeyStatus;
                  lKeyStatus = 536870912; //2^29 ALT Flag
                  Win32API.PostMessage(hWnd,(int)Keys.WM_SYSKEYDOWN, nFunctionKey, lKeyStatus );
            }

Just like to thank you for your help and for enlightening me on a few things I didn't already know.

Please Take 200 points for trying...

Kind Regards
JC
0
 
Mike TomlinsonMiddle School Assistant TeacherCommented:
Glad you figured it out!
0
 
GranModCommented:
Closed, 500 points refunded.
GranMod
The Experts Exchange
Community Support Moderator of all Ages
0

Featured Post

Technology Partners: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

  • 4
  • 3
Tackle projects and never again get stuck behind a technical roadblock.
Join Now