Link to home
Start Free TrialLog in
Avatar of techsuppoprt
techsuppoprt

asked on

Recording keyboard key strokes

Hi Experts.

I'm a bit stuck here so I would really appreciate some help.

I'm working on a macro program that will forward certain keyboard key strokes to other keys. So let's say if I press "T" I want "U" to be returned instead.
My GUI has a text box that users can click in and specify which button will that "T" key press be forwarded to. Key press event :

        private void txtTrigger_KeyPress(object sender, KeyPressEventArgs e)
        {
              txtTrigger.Text = e.KeyChar.ToString();
        }
Then I save that Textbox's INT ascii value to the XML file as [112] and next time a program user hits "T" - 112 gets converted back to a string and sent back:

ConfigFile.Trigger = Char.ConvertToUtf32(txtTrigger.Text,0);

SendKeys.SendWait(SpellToTrigger);

Awesome, works great with LETTERS ONLY.
 
I can't figuire out how to record and return other keys such as F1-12, CTRL, ALT, TAB, Backpsace...etc. They don't seem to trigger TextBox KeyPress events at all. Do I really have to go though every single Function and other keys on my keyboard wtih if (e.KeyCode == Keys.F9) individually ?

I tried using the KeyDown instead of KeyPress event and Function key presses do get picked up but KeyValues returned back to a user are incorrect:

            int pressedKey = e.KeyValue;
            txtTrigger.Text = char.ConvertFromUtf32(pressedKey);

I press F8 and W appears in that txtTrigger. F5 shows up as letter T.
Shift, Control and some other keys appear as .

Any help ? All I want to do is setup something like you might have seen in computer games when you setup your input bindings where you specify what key your action is forwared to.

Thank you in advance.
Avatar of mac-will
mac-will
Flag of Canada image

You could use a lower level keyboard hook.

http://blogs.msdn.com/b/toub/archive/2006/05/03/589423.aspx
Avatar of Brad Brett
If you want to record the keystrokes even if your program is not active on the screen, you need to use GetAsyncKeyState API to frequently check each key state:
http://msdn.microsoft.com/en-us/library/ms646293(v=vs.85).aspx
Avatar of techsuppoprt
techsuppoprt

ASKER

Thanks.
I don't think you guys read my question at all though or was it a bit confusing possibly ?

Let me try to rephrase it.
What's the best way to store captured key strokes in the XML file ?

Right now I'm saving the INT keyvalues and doing so won't let me properly capture Function keys and other buttons such as Backspase, Delete, Shift, ALT, Caps Lock .. etc.

I want to be able to capture and record ( in the XML config file ) any key on my keyboard to later that key press be simulated back to the user with something like
SendKeys.SendWait().
This still is not clear to me.

Do you want to capture the keypress event of a textbox or key presses in general from the application?  Obviously pressing shift does not do anything in the keypress event of a textbox since you cannot display a <shift> for example.

Perhaps you could simply use the keyDown or KeyUp events? As these events are triggered even for control keys.

From MSDN:

"The KeyPress event is not raised by noncharacter keys; however, the noncharacter keys do raise the KeyDown and KeyUp events."

http://msdn.microsoft.com/en-us/library/system.windows.forms.control.keypress.aspx

If it helps try adding this handler to see what king of info is printed when you press a key.

        private void txtTrigger_KeyDown(object sender, KeyEventArgs e)
        {
            Console.WriteLine("KeyCode : " + e.KeyCode.ToString() + "    Modifiers : " + e.Modifiers.ToString());
        }

Open in new window


And as for storing the info in an xml file why not just store the keycode (as a string)

Here is the back and forth from string to keycode:

Keys mySavedValue = (Keys)Enum.Parse(typeof(Keys), "Alt");

String myValueToSave = e.KeyCode.ToString();

Open in new window

What I want:
- I have a form with a button and a text box;
- User activates a form text box;
- Once the textbox is active - user presses F6
- "F6" shows up in the textbox control and something gets saves to the XML file
- User presses the button - "F6" key press is simulated.

Does it make sense ?

My problem is not HOW to capture. I know how to do it through Keypress/KeyDown events... it's WHAT to capture. What can I record to the XML file to easily re-play any button on the keyboard, inluding Function, extra keys and key combination ?

I want my program to read the XML file and recognize what key press actions to send back to the user.

I will assume that the "User presses the button ..." simulation is for the textbox.


So just like my example above but combining both steps:

        private void txtTrigger_KeyDown(object sender, KeyEventArgs e)
        {
             if( check if its a printable keycode)
             {
                  txtTrigger.Text += e.KeyCode.ToString();
             }
            MySaveToXMLFunction(e.KeyCode.ToString());
        }

Open in new window



To Send a key you could use the SendKeys class or if you need more control use the Windows API:

  private void btnSend_Click(object sender, EventArgs e)
        {
            txtTrigger.Select();
            SendKeys.Send("{" + Keys.F6.ToString() + "}");
       }

Open in new window


Obviously the Keys.F6.ToString() would be whatever you retrieved from you xml file....



Would you say it's safe to go based on this chart:

http://msdn.microsoft.com/en-us/library/system.windows.forms.sendkeys.send.aspx

and simply throw all my saved KeyCode values in SendKey.Send( { SavedKeyCode } ) whenever I need to send that saved key back to the user ?

I assume I'll check for SHIFT/ALT/CTR pressed and modify my saved XML KeyCode with + % or ^ accordingly ?
Going to try it...Let me know if it sounds wrong.
That sounds right.  

That is what this class (SendKeys) was made for.  If this meets your needs in terms of what control is receiveing the keys etc. than definitely go this way.  

If for example you want to send keys to the desktop or receive keys when your application does not have focus you would probably want to go with a keyboard hook.
Errr...Doesn't really work as some KeyCode string values don't match with the actual keys. ( NumPad5 , D6 .. etc). SendKeys.SendWait("NumPad8") actually returns "NumPad8" instead of simulating number 8 being pressed on the NumPad.

Is there  a way to cast/convert KeyEventArgs.KeyCode back to Keys enum and send a keypress event that way ?

Thank you in advance.
ps. I added points.
Ok so no, not really.  there is no magic you either have to map the Keys enum to the table in the link above or more easily use the Windows API.

(Are you familiar with PInvoke?)

Here is the all the code you need:
(using System.Runtime.InteropServices;)

        [DllImport("user32.dll")]
        static extern void keybd_event(byte bVk, byte bScan, uint dwFlags, int dwExtraInfo);

        void PressKey(byte keyCode)
        {
            const int KEYEVENTF_EXTENDEDKEY = 0x1;
            const int KEYEVENTF_KEYUP = 0x2;
            keybd_event(keyCode, 0x45, KEYEVENTF_EXTENDEDKEY, 0);
            keybd_event(keyCode, 0x45, KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, 0);
        }

Open in new window


But this time you save the KeyValue in the press event and send that to the PressKey function.

I think this should work for most keys anyway.
I'm not familiar but I will make myself now :)
Thank you for your help. I need a few final pushes if you don't mind.

But this time you save the KeyValue in the press event and send that to the PressKey function
There is no KeyValue property on the keypress event though... Did you mean KeyChar ?

Will it also recognize/replay ALT/SHIFT/CTR-key cobos ?

Thank you.
        private void txtTrigger_KeyPress(object sender, KeyPressEventArgs e)
        {
          PressKey((byte)e.KeyChar);
         }

        [DllImport("user32.dll")]
        static extern void keybd_event(byte bVk, byte bScan, uint dwFlags, int dwExtraInfo);

        void PressKey(byte keyCode)
        {
            const int KEYEVENTF_EXTENDEDKEY = 0x1;
            const int KEYEVENTF_KEYUP = 0x2;
            keybd_event(keyCode, 0x45, KEYEVENTF_EXTENDEDKEY, 0);
            keybd_event(keyCode, 0x45, KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, 0);
        }

Open in new window


^ Doesn't work. it returns some bizarre stuff. Pressing "P" triggers F1. Pressing "E" triggers number 4 ...etc.
ASKER CERTIFIED SOLUTION
Avatar of mac-will
mac-will
Flag of Canada image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Sorry for a delay but I'm still having problems with this that I can't seem to figure out. Everything seems right yet....

So what I'm storing in my XML file are e.KeyValue values returned from a control's key down event. And then use them to simulate key presses. So basically it's this:

        private void txTrigger_KeyDown(object sender, KeyEventArgs e)
        {

            KeyboardSimulator.SendKeyDown((byte)e.KeyValue);
        }

        private void txtTrigger_KeyUp(object sender, KeyEventArgs e)
        {
            KeyboardSimulator.SendKeyUp((byte)e.KeyValue);
        }

Open in new window


Rest of the code is what you've posted above. I didn't make any changes to the KeybardSimulator class at all. Using it exactly as you posted.

Yet what happens is when txtTrigger key click is triggered it gets stuck in unlimited KeyDown loop. So if I press "K" for example I get KKKKKKKKKKKKKKKKKKKKKKKKKKKK...etc.

I can't figure out why and what's different in my code from what you wrote.
Hi,

If you are sending a keydown event from the keydown handler you will of course get a loop.

Basically you are saying when 'K' is pressed press it again.

Is this a macro recorder of some sort?

Basically you need to record the various key down and key up events than save this sequence to your xml file and replay the sequence when you need to.

Try getting the example I posted to work without any modifications I think it will explain a lot.

btw the reason for saving both the key down and up events is for modifier keys.

for example this sequence:

shift down
k down
k up
shift up

will yield 'K'
if instead you just recorded key presses (down - up event) for the same sequence you would have recorded k press than shift press which would yield 'k' and not 'K' as intended.
Account expired at the worst time.
This is not abandoned.
@techsuppoprt: You need to interact with the experts to solve the question, you have left the question since the last expert comment at 03/30/11 therefore the question was classified as abandoned.
Mac, thanks for your help.
I'm about to close this one.
I have one last question i you don't mind.

My key strokes are being forwarded/replayed back to the interface just fine , lets say if I use notepad.
But then I have some programs where it doesn't work.

What could be blocking keys in an application from being sent to its interface ? Any clue ?
I would guess it might have something to do with the control that has focus?  Perhaps these application do not propagate key presses as normal to child controls?

Just a guess.
Alright. Well thank you :)