Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does SendKey.Send() only work once in a while?

I'm making a Windows application that captures keyboard input globally. When a user uses the CTRL + ALT + G shortcut combo the application uses

SendKey.Send(Guid.NewGuid().ToString());

to type a generaged GUID into whatever text field is in focus. And it should do this regardless of the application taking the input.

It works exactly as I intended the first time you type CTRL + ALT + G but subsequent attempts result in nothing, or just very infrequent successes.

I mean, it all should be very simple and consistent. I have a working global keyboard hook which works all the time, I've tested it, but the SendKey.Send() method doesn't work every time.

I've looked all over Google at anything related to my issue but nothing has worked so far.

Anyone have any insight?

EDIT 1: I've tried using SendKey.SendWait() as well, does the same thing. I really want a more responsive way to generate new GUID using this keyboard shortcut approach.

EDIT 2:

Below is the essential parts of the code:

/* Initialization Code Here */
// register the event that is fired after the key press.
hook.KeyPressed += new EventHandler<KeyPressedEventArgs>(hook_KeyPressed);
// register the control + alt + F12 combination as hot key.
hook.RegisterHotKey((uint)(HotkeyModifiers.Control | HotkeyModifiers.Alt), Keys.G);

The event code is quite simple:

void hook_KeyPressed(object sender, KeyPressedEventArgs e)
{
    SendKeys.SendWait(Guid.NewGuid().ToString());
}

Everything else in my project is just fluff.

Update 1:

I do have more questions about this subject, but I am out of time to continue working on this for today. I have implemented Jon Raynor's suggestion of using the app.config approach to some degree of success. Once I isolate my new problems I'll post an edit and possibly close this question if I get my application functioning as intended.

like image 461
LamdaComplex Avatar asked Sep 14 '11 19:09

LamdaComplex


2 Answers

You may be running into timing issues. According to the MSDN documentation:

The SendKeys class has been updated for the .NET Framework 3.0 to enable its use in applications that run on Windows Vista. The enhanced security of Windows Vista (known as User Account Control or UAC) prevents the previous implementation from working as expected.

The SendKeys class is susceptible to timing issues, which some developers have had to work around. The updated implementation is still susceptible to timing issues, but is slightly faster and may require changes to the workarounds. The SendKeys class tries to use the previous implementation first, and if that fails, uses the new implementation. As a result, the SendKeys class may behave differently on different operating systems. Additionally, when the SendKeys class uses the new implementation, the SendWait method will not wait for messages to be processed when they are sent to another process.

If your application relies on consistent behavior regardless of the operating system, you can force the SendKeys class to use the new implementation by adding the following application setting to your app.config file.

<appSettings> 

<add key="SendKeys" value="SendInput"/> 

</appSettings> 

To force the SendKeys class to use the previous implementation, use the value "JournalHook" instead.

like image 200
Jon Raynor Avatar answered Nov 10 '22 19:11

Jon Raynor


This won't address your exact issue, but is an alternative approach. I've experimented with global key hooks in managed code before. It's a pain. As hokey and primitive as it sounds, I love AutoHotKey. You can do some really powerful things with it.

Here's a sample that achieves your requirement of globally hooking Ctrl+Alt+G and typing a guid. The best part is it compiles inline C# so you can still use System.Guid.NewGuid(). Once you have a working script, you can compile it to an exe so someone without AutoHotKey installed can run it.

#NoEnv
#SingleInstance
#Include CLR.ahk
#Include COM.ahk

;minimize delay between key presses
SetKeyDelay, -1

;create c# code
CLR_Start()
_g := CLR_CompileC#("class c{public string GetNewGuid(){return System.Guid.NewGuid().ToString();}}", "System.dll").CreateInstance("c")

;hook keyboard ctrl+alt+g
^!g::InsertGuid()

;generate a guid and type it
InsertGuid() {
    global
    local guid := _g.GetNewGuid()
    Send,%guid%
}

If you want to try it out, install AutoHotKey_L then download two extra scripts here and here.

like image 1
codeConcussion Avatar answered Nov 10 '22 18:11

codeConcussion