1

First thing I'll say is SSH'ing through C#/a C# plugin etc. is NOT an option in this case.

Also, it needs to be assumed that putty is already running, I am NOT planning to execute putty though the C# program. The first thing I want to test is a simple 'Exit' button that will grab the current instance of putty, and write 'exit' to the window.

1 Answer 1

1

You most likely have a few options. The code below shows how to simulate keystrokes and send them to a window (SendInput). You may be able to use SendKeys, which may be a better solution, but SendInput should work with just about anything - although users can interfere with the keystrokes if they start hitting their keyboard in the middle of the automation. I don't have a SendKeys example on-hand at the moment ...

This crude example should get the window handle for the Putty window, bring the window forward/focus on the window, and then simulate keystrokes. Sorry, not the cleanest but it should do what you need.

// Register Win32 API stuff
const int INPUT_KEYBOARD = 1;

[DllImport("user32.dll", SetLastError = true)]
private static extern uint SendInput(uint nInputs, INPUT[] pInputs, int cbSize);

[DllImport("user32.dll", SetLastError = true)]
private static extern uint SendInput(uint nInputs, ref INPUT pInputs, int cbSize);

[DllImport("user32.dll")]
private static extern IntPtr FindWindow(string lpClassName, string lpWindowName);

[DllImport("user32.dll")]
private static extern int SetForegroundWindow(IntPtr hWnd);

[DllImport("user32.dll")]
private static extern IntPtr SetFocus(IntPtr hWnd);

[StructLayout(LayoutKind.Sequential)]
struct KEYBDINPUT
{
    public ushort wVk;
    public ushort wScan;
    public uint dwFlags;
    public uint time;
    public IntPtr dwExtraInfo;
}

[StructLayout(LayoutKind.Sequential)]
struct HARDWAREINPUT
{
    public uint uMsg;
    public ushort wParamL;
    public ushort wParamH;
}

[StructLayout(LayoutKind.Explicit)]
struct INPUT
{
    [FieldOffset(0)]
    public int type;
    [FieldOffset(4)]
    public MOUSEINPUT mi;
    [FieldOffset(4)]
    public KEYBDINPUT ki;
    [FieldOffset(4)]
    public HARDWAREINPUT hi;
}

public enum VirtualKeys : ushort
{
    SHIFT = 0x10,
    CONTROL = 0x11,
    MENU = 0x12,
    ESCAPE = 0x1B,
    BACK = 0x08,
    TAB = 0x09,
    RETURN = 0x0D,
    PRIOR = 0x21,
    NEXT = 0x22,
    END = 0x23,
    HOME = 0x24,
    LEFT = 0x25,
    UP = 0x26,
    RIGHT = 0x27,
    DOWN = 0x28,
    SELECT = 0x29,
    PRINT = 0x2A,
    EXECUTE = 0x2B,
    SNAPSHOT = 0x2C,
    INSERT = 0x2D,
    DELETE = 0x2E,
    HELP = 0x2F,
    NUMPAD0 = 0x60,
    NUMPAD1 = 0x61,
    NUMPAD2 = 0x62,
    NUMPAD3 = 0x63,
    NUMPAD4 = 0x64,
    NUMPAD5 = 0x65,
    NUMPAD6 = 0x66,
    NUMPAD7 = 0x67,
    NUMPAD8 = 0x68,
    NUMPAD9 = 0x69,
    MULTIPLY = 0x6A,
    ADD = 0x6B,
    SEPARATOR = 0x6C,
    SUBTRACT = 0x6D,
    DECIMAL = 0x6E,
    DIVIDE = 0x6F,
    F1 = 0x70,
    F2 = 0x71,
    F3 = 0x72,
    F4 = 0x73,
    F5 = 0x74,
    F6 = 0x75,
    F7 = 0x76,
    F8 = 0x77,
    F9 = 0x78,
    F10 = 0x79,
    F11 = 0x7A,
    F12 = 0x7B,
    OEM_1 = 0xBA, // ',:' for US
    OEM_PLUS = 0xBB, // '+' any country
    OEM_COMMA = 0xBC, // ',' any country
    OEM_MINUS = 0xBD, // '-' any country
    OEM_PERIOD = 0xBE, // '.' any country
    OEM_2 = 0xBF, // '/?' for US
    OEM_3 = 0xC0, // '`~' for US
    MEDIA_NEXT_TRACK = 0xB0,
    MEDIA_PREV_TRACK = 0xB1,
    MEDIA_STOP = 0xB2,
    MEDIA_PLAY_PAUSE = 0xB3,
    LWIN = 0x5B,
    RWIN = 0x5C
}

private KEYBDINPUT CreateKeyboardInput(short wVK, uint flag)
{
    KEYBDINPUT i = new KEYBDINPUT();

    i.wVk = (ushort)wVK;
    i.wScan = (ushort)MapVirtualKey((uint)wVK, 0);
    i.time = 0;
    i.dwExtraInfo = IntPtr.Zero;
    i.dwFlags = flag;

    return i;
}

public static short GetCharacterValue(char c)
{
    //http://msdn.microsoft.com/en-us/library/dd375731(v=VS.85).aspx
    if (c >= 'a' && c <= 'z') return (short)(c - 'a' + 0x41);
    else if (c >= '0' && c <= '9') return (short)(c - '0' + 0x30);
    else if (c == '-') return 0x6D; // Note it's NOT 0x2D as in ASCII code!
    else if (c == ' ') return 0x20;
    else return 0; // default
}

...

// Get window handle
var windowHandle = FindWindow(null, "Putty Window Title");

// Bring window forward and focus
ShowWindow(windowHandle, SW_RESTORE);
SetFocus(windowHandle);
SetForegroundWindow(windowHandle);

...

// Create list of keystrokes and send them to the window
List<INPUT> inputList = new List<INPUT>();

// This will type "HI".  One is a downward keystroke and then the upward (that's why there's 4)
INPUT kbInput;

kbInput = new INPUT();
kbInput.type = INPUT_KEYBOARD;
kbInput.ki = CreateKeyboardInput(GetCharacterValue('H'), 0);
inputList.Add(kbInput);

kbInput = new INPUT();
kbInput.type = INPUT_KEYBOARD;
kbInput.ki = CreateKeyboardInput(GetCharacterValue('H'), KEYEVENTF_KEYUP);
inputList.Add(kbInput);

kbInput = new INPUT();
kbInput.type = INPUT_KEYBOARD;
kbInput.ki = CreateKeyboardInput(GetCharacterValue('I'), 0);
inputList.Add(kbInput);

kbInput = new INPUT();
kbInput.type = INPUT_KEYBOARD;
kbInput.ki = CreateKeyboardInput(GetCharacterValue('I'), KEYEVENTF_KEYUP);
inputList.Add(kbInput);

INPUT[] inp = inputList.ToArray();
SendInput((uint)inp.Length, inp, Marshal.SizeOf(new INPUT()));
Sign up to request clarification or add additional context in comments.

1 Comment

Thanks I'll look into using this

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.