views:

440

answers:

1

I'm writing a tool for validation engineers to log session interaction when attempting to reproduce failure. It creates a video of the desktop, and I'm hooking the keyboard and mouse in C#, to record their interaction with the OS. The events are serialized out to a file to be read in at a later time. I use SendInput to replay the mouse and keyboard events.

Every thing works great, except replaying cut and paste interactions. CTRL-Insert SHIFT-Insert

Anyone know what I'm doing wrong?

My Hook code:

   // if it's a keyboard event
{

   Keys keyData = (Keys)MyKeyboardHookStruct.vkCode;
   KeyEventArgs e = new KeyEventArgs(keyData);                    
   MyKeyEventArgs akea = new MyKeyEventArgs();
   akea.ExtraInfo = GetMessageExtraInfo();
   akea.Code = wParam;
   akea.KeyArgs = e;
   KeyDown(this, akea); // call to my event handler
}

My SendInput code

    // if it's a keyboard event
    {
     case KeyBoardHook.WM_KEYUP:
        tssKeyPress.Text = hec.KeyCode.ToString() + " Up";
        mi.mkhi.mi.dwExtraInfo = hec.ExtraInfo;
        k.mkhi.ki.dwFlags = KEYEVENTF_KEYUP;
        if (
            ((int)hec.KeyCode >= (int)VK.VK_PRIOR && (int)hec.KeyCode <= (int)VK.VK_DELETE) ||
            ((int)hec.KeyCode >= (int)VK.VK_LWIN && (int)hec.KeyCode <= (int)VK.VK_APPS) ||
            ((int)hec.KeyCode >= (int)VK.VK_SPACE && (int)hec.KeyCode <= (int)VK.VK_HELP) ||
            ((int)hec.KeyCode >= (int)VK.VK_SHIFT && (int)hec.KeyCode <= (int)VK.VK_MENU)
           )
        {
            k.mkhi.ki.dwFlags += KEYEVENTF_EXTENDEDKEY;
        }
        k.mkhi.ki.wVk = (ushort)hec.KeyCode;
        k.mkhi.ki.wScan = 0;
        //k.mkhi.mi.wScan = (short)hec.KeyData;
        k.mkhi.mi.time = 0;
        SendInput(1, ref k, Marshal.SizeOf(k));
        break;
    case KeyBoardHook.WM_KEYDOWN:
        tssKeyPress.Text = hec.KeyCode.ToString() + " Down";

        k.mkhi.ki.time = 0;
        k.mkhi.ki.dwExtraInfo = IntPtr.Zero;
        if (
            ((int)hec.KeyCode >= (int)VK.VK_PRIOR && (int)hec.KeyCode <= (int)VK.VK_DELETE ) ||
            ((int)hec.KeyCode >= (int)VK.VK_LWIN && (int)hec.KeyCode <= (int)VK.VK_APPS) ||
            ((int)hec.KeyCode >= (int)VK.VK_SPACE && (int)hec.KeyCode <= (int)VK.VK_HELP) ||
            ((int)hec.KeyCode >= (int)VK.VK_SHIFT && (int)hec.KeyCode <= (int)VK.VK_MENU)
           )
        {
            k.mkhi.ki.dwFlags += KEYEVENTF_EXTENDEDKEY;
        }
        k.mkhi.ki.dwFlags = 0;
        k.mkhi.ki.wVk = (ushort)hec.KeyCode;
        k.mkhi.ki.wScan = 0;
        //k.mkhi.mi.wScan = (short)hec.KeyData;
        SendInput(1, ref k, Marshal.SizeOf(k));
        break;
}
A: 

Here is my working solution to replay the keyboard:

case KeyBoardHook.WM_KEYUP:
    tssKeyPress.Text = hec.KeyCode.ToString() + " Up";
    k.mkhi.mi.dwExtraInfo = hec.ExtraInfo;
    k.mkhi.ki.dwFlags = KEYEVENTF_KEYUP;
    SetExtendedFlag( hec.KeyCode, ref k );
    k.mkhi.ki.wScan = 0;
    k.mkhi.mi.time = 0;
    SendInput(1, ref k, Marshal.SizeOf(k));
    break;
case KeyBoardHook.WM_KEYDOWN:
    tssKeyPress.Text = hec.KeyCode.ToString() + " Down";
    k.mkhi.mi.dwExtraInfo = hec.ExtraInfo;
    k.mkhi.ki.time = 0;
    k.mkhi.ki.dwFlags = 0;
    SetExtendedFlag( hec.KeyCode, ref k );
    k.mkhi.ki.wScan = 0;
    SendInput(1, ref k, Marshal.SizeOf(k));
    break;

private void SetExtendedFlag(Keys keys, ref INPUT k )
{
    k.mkhi.ki.wVk = (ushort)keys;
    if (((int)keys == (int)VK.VK_LSHIFT && (int)keys == (int)VK.VK_RSHIFT))
    {
        k.mkhi.ki.wVk = (ushort)VK.VK_SHIFT;
    }
    if (((int)keys == (int)VK.VK_LCONTROL && (int)keys == (int)VK.VK_RCONTROL))
    {
        k.mkhi.ki.wVk = (ushort)VK.VK_CONTROL;
    }
    if (((int)keys == (int)VK.VK_LMENU && (int)keys == (int)VK.VK_RMENU))
    {
        k.mkhi.ki.wVk = (ushort)VK.VK_MENU;
    }
    switch ((int)keys)
    {
        case((int) VK.VK_RMENU):
        case ((int)VK.VK_RCONTROL):                
        case ((int)VK.VK_INSERT):
        case ((int)VK.VK_DELETE):
        case ((int)VK.VK_LEFT):
        case ((int)VK.VK_HOME):
        case ((int)VK.VK_END):
        case ((int)VK.VK_UP):
        case ((int)VK.VK_DOWN):
        case ((int)VK.VK_PRIOR):
        case ((int)VK.VK_NEXT):
        case ((int)VK.VK_RIGHT):
        case ((int)VK.VK_LWIN):
        case ((int)VK.VK_RWIN):
        case ((int)VK.VK_APPS):
        case ((int)VK.VK_SLEEP):
            k.mkhi.ki.dwFlags |= KEYEVENTF_EXTENDEDKEY;
            break;
    }
}

I can now successfully replay copy, and cut and past using CTRL-INSERT, and SHIFT-INSERT.