6

I am working on a project where it is necessary to simulate key-presses to cause specific behaviours in a different application.

All is running well and fine, using the keybd_event function that is being imported (there might be better ways, but it is working fine).

Now I want to add specific support for all of the numpad.

Looking e. g. here http://msdn.microsoft.com/en-us/library/dd375731(v=VS.85).aspx or in the System.Windows.Input.Key namespace, I can easily find keys for Num0..Num9, as well as for NumLock. But.. I cannot find anything for Num/, Num+, NumEnter etc.

I wrote a quick froms app to catch the keydown event, outputting the event paramters, and got some interesting results:

e.KeyCode NumLock e.KeyData NumLock e.KeyValue 144 e.Modifiers None  
e.KeyCode Divide e.KeyData Divide e.KeyValue 111 e.Modifiers None  
e.KeyCode Multiply e.KeyData Multiply e.KeyValue 106 e.Modifiers None  
e.KeyCode Subtract e.KeyData Subtract e.KeyValue 109 e.Modifiers None  
e.KeyCode Add e.KeyData Add e.KeyValue 107 e.Modifiers None  
e.KeyCode NumLock e.KeyData NumLock e.KeyValue 144 e.Modifiers None  
e.KeyCode NumLock e.KeyData NumLock e.KeyValue 144 e.Modifiers None  
e.KeyCode Divide e.KeyData Divide e.KeyValue 111 e.Modifiers None  
e.KeyCode Multiply e.KeyData Multiply e.KeyValue 106 e.Modifiers None  
e.KeyCode Subtract e.KeyData Subtract e.KeyValue 109 e.Modifiers None  
e.KeyCode Add e.KeyData Add e.KeyValue 107 e.Modifiers None  
e.KeyCode Return e.KeyData Return e.KeyValue 13 e.Modifiers None

The Num+ Key (and so on) seem to be keys that Windows calls function keys (like F18 for the Num+ key). So.. that is strange, but ok.

But.. I cannot distinguish the Enter-Key from the NumEnter Key. Those are different for my application, so I have to send specific key-codes for both.

And that is my question: how can I send an ordinary enter-key and how can I send a NumEnter key?

(I don't know whether it makes any difference, I am on a German keyboard layout.)

Thx for any ideas!

abatishchev
  • 98,240
  • 88
  • 296
  • 433
Andreas Reiff
  • 7,961
  • 10
  • 50
  • 104
  • 1
    not very helpful, but I can confirm: we have an application tracking user input and right now it produces the same keycode for NumEnter from Enter so I couldn't distinguish. – Cilvic May 13 '11 at 08:46

3 Answers3

3

I found this here works for me !

protected override void WndProc(ref Message m)
{
     if (m.Msg == 256 && m.WParam.ToInt32() == 13)
     {   // WM_KEYDOWN == 256, Enter == 13
         if ((m.LParam.ToInt32() >> 24) == 0)
         {
             MessageBox.Show("main enter pressed!");
         }
         else
         {
             MessageBox.Show("numpad enter pressed!");
         }
      }
      else
      {
         base.WndProc(ref m);
      }
}
V4Vendetta
  • 37,194
  • 9
  • 78
  • 82
  • Thx a lot, that was really helpful. Though it is the other way round to what I am looking for :) it has all the information to solve my problem. I will write an answer straight away.. – Andreas Reiff May 13 '11 at 09:24
  • Thx a lot to your answers! Especially for yor idea, Vendetta! Since you are talking about a the-other-way-round solution, detecting the event, and I want to raise it, I don't even have to override the WndProc. I can simply send my own messages. From your solution, I had a look at SendMessage, and then WM_KEYDOWN and WM_KEYUP. The documentation actually gives you the info (if you look really really hard). http://msdn.microsoft.com/en-us/library/ms646280(v=vs.85).aspx http://msdn.microsoft.com/en-us/library/ms646281(v=vs.85).aspx – Andreas Reiff May 13 '11 at 09:34
  • So my solution (compiles but not tested) is like this: enter bool keyDown; // true = down, false = up const uint WM_KEYDOWN = 0x0100; const uint WM_KEYUP = 0x0101; const int VK_RETURN = 0x0D; // Obtain the handle of the active window. IntPtr handle = GetForegroundWindow(); int lParam = 1 << 24; // this specifies NumPad key (extended key) lParam |= (keyDown) ? 0 : (1 << 30 | 1 << 31); // mark key as pressed if we use keyup message PostMessage(handle, (keyDown) ? WM_KEYDOWN : WM_KEYUP, VK_RETURN, lParam); – Andreas Reiff May 13 '11 at 09:35
  • Only problem: it goes to the active window, not the active control (like textedit). It is not (really) a problem for me - I hope. Hope it is useful to someone else as well. And.. if you do have a better solution, please say so! (sorry for the many comments - cannot answer my own questions the next 8h..) – Andreas Reiff May 13 '11 at 09:35
  • well i will surely try .. meanwhile you can accomodate the above comments in your questions itself .. later on you can choose to add as answer – V4Vendetta May 13 '11 at 09:48
1

thanks to andreas for providing the beginning of a solution. here's a more complete version:

[DllImport("user32.dll")]
private static extern IntPtr PostMessage(IntPtr hWnd, uint Msg, IntPtr wParam, IntPtr lParam);
[DllImport("user32.dll")]
private static extern IntPtr GetForegroundWindow();
[DllImport("user32.dll")]
private static extern uint GetWindowThreadProcessId(IntPtr hWnd, out uint lpdwProcessId);
[DllImport("user32.dll")]
private static extern bool GetGUIThreadInfo(uint idThread, out GUITHREADINFO lpgui);

public struct GUITHREADINFO
{
    public int cbSize;
    public int flags;
    public int hwndActive;
    public int hwndFocus;
    public int hwndCapture;
    public int hwndMenuOwner;
    public int hwndMoveSize;
    public int hwndCaret;
    public System.Drawing.Rectangle rcCaret;
}

private void sendNumpadEnter()
{
    bool keyDown = true; // true = down, false = up
    const uint WM_KEYDOWN = 0x0100;
    const uint WM_KEYUP = 0x0101;
    const int VK_RETURN = 0x0D;

    IntPtr handle = IntPtr.Zero;
    // Obtain the handle of the foreground window (active window and focus window are only relative to our own thread!!)
    IntPtr foreGroundWindow = GetForegroundWindow();
    // now get process id of foreground window
    uint processID;
    uint threadID = GetWindowThreadProcessId(foreGroundWindow, out processID);
    if (processID != 0)
    {
        // now get element with (keyboard) focus from process
        GUITHREADINFO threadInfo = new GUITHREADINFO();
        threadInfo.cbSize = Marshal.SizeOf(threadInfo);
        GetGUIThreadInfo(threadID, out threadInfo);
        handle = (IntPtr)threadInfo.hwndFocus;
    }

    int lParam = 1 << 24; // this specifies NumPad key (extended key)
    lParam |= (keyDown) ? 0 : (1 << 30 | 1 << 31); // mark key as pressed if we use keyup message

    PostMessage(handle, (keyDown) ? WM_KEYDOWN : WM_KEYUP, VK_RETURN, lParam); // send enter
}
Ben H
  • 3,855
  • 1
  • 26
  • 33
0

Since you are talking about a the-other-way-round solution, detecting the event, and I want to raise it, I don't even have to override the WndProc. I can simply send my own messages.

From your solution, I had a look at SendMessage/PostMessage, and then WM_KEYDOWN and WM_KEYUP. The documentation actually gives you the info (if you look really really hard).

http://msdn.microsoft.com/en-us/library/ms646280(v=vs.85).aspx
http://msdn.microsoft.com/en-us/library/ms646281(v=vs.85).aspx

So my solution (compiles and now with finding the right window (where to enter the text)) is like this:

 bool keyDown = true; // true = down, false = up
 const uint WM_KEYDOWN = 0x0100;
 const uint WM_KEYUP = 0x0101;
 const int VK_RETURN = 0x0D;

 IntPtr handle = IntPtr.Zero;
 // Obtain the handle of the foreground window (active window and focus window are only relative to our own thread!!)
 IntPtr foreGroundWindow = GetForegroundWindow();
 // now get process id of foreground window
 uint processID;
 uint threadID = GetWindowThreadProcessId(foreGroundWindow, out processID);
 if (processID != 0)
 {
 // now get element with (keyboard) focus from process
 GUITHREADINFO threadInfo = new GUITHREADINFO();
 threadInfo.cbSize = Marshal.SizeOf(threadInfo);
 GetGUIThreadInfo(threadID, out threadInfo);
 handle = (IntPtr)threadInfo.hwndFocus;
 }

 int lParam = 1 << 24; // this specifies NumPad key (extended key)
 lParam |= (keyDown) ? 0 : (1 << 30 | 1 << 31); // mark key as pressed if we use keyup message
 PostMessage(handle, (keyDown) ? WM_KEYDOWN : WM_KEYUP, VK_RETURN, lParam); // send enter

Hope it is useful to someone else as well. As was Vendetta's tip to me.

And.. if you do have a better solution, please say so!

Andreas Reiff
  • 7,961
  • 10
  • 50
  • 104