How to simulate keystroke using SendInput via dllcall? Topic is solved

Get help with using AutoHotkey (v1.1 and older) and its commands and hotkeys
killmatt01
Posts: 20
Joined: 25 Mar 2021, 00:12
Contact:

How to simulate keystroke using SendInput via dllcall?

Post by killmatt01 » 29 Jul 2021, 15:24

Since SendInput {Key Down} and SendInput {Key Up} is a bit slow in some cases (even if i used SetBatchLines, -1 and SetKeyDelay, -1, -1), I am now looking for a method which can do the same job faster (ahk SendInput could use up to 40ms on my laptop).
I found one way to do so is using

Code: Select all

DllCall("keybd_event", "Int", VirtualKey, "Int", ScanCode, "Int", 1, "Int", 0)
DllCall("keybd_event", "Int", VirtualKey, "Int", ScanCode, "Int", 2, "Int", 0)
Since that function(keybd_event) "has been superseded", I am now trying to use SendInput function via dllcall

I tried this:

Code: Select all

~*1::
    press_key("Space")
Return
press_key(key_name)
{
    VarSetCapacity(Key_Down, 40)
    VarSetCapacity(Key_Up, 40)
    static INPUT_KEYBOARD := 1, KEYEVENTF_EXTENDEDKEY := 0x0001, KEYEVENTF_KEYUP := 0x0002

    VirtualKey := GetKeyVK(key_name)
    ScanCode := GetKeySC(key_name)
    NumPut(INPUT_KEYBOARD, Key_Down, "UInt")
    NumPut(VirtualKey, Key_Down, 2*A_PtrSize, "UShort")
    NumPut(ScanCode, Key_Down, 2*A_PtrSize, "UShort")

    NumPut(INPUT_KEYBOARD, Key_Up, "UInt")
    NumPut(VirtualKey, Key_Up, 2*A_PtrSize, "UShort")
    NumPut(ScanCode, Key_Up, 2*A_PtrSize, "UShort")

    Suspend, On

    NumPut(KEYEVENTF_EXTENDEDKEY, Key_Down, A_PtrSize, "UInt")
    DllCall("SendInput", "UInt", 1, "Ptr", &Key_Down, "Int", 40)
    sleep, 100
    VarSetCapacity(Key_Down, 0)

    NumPut(KEYEVENTF_KEYUP, Key_Up, A_PtrSize, "UInt")
    DllCall("SendInput", "UInt", 1, "Ptr", &Key_Down, "Int", 40)

    Suspend, Off
    sleep, 100
    VarSetCapacity(Key_Up, 0)
}
However that doesn't work. There are problems in my function but i don't know where they are. Could someone help me on fixing my function? Thanks so much!
killmatt01
Posts: 20
Joined: 25 Mar 2021, 00:12
Contact:

Re: How to simulate keystroke using SendInput via dllcall?

Post by killmatt01 » 04 Aug 2021, 20:06

Code: Select all

singleSpace()
{
    VarSetCapacity(Key1_Down, A_PtrSize*5+4, 0)
    static INPUT_KEYBOARD := 1, KEYEVENTF_EXTENDEDKEY := 0x0001, KEYEVENTF_KEYUP := 0x0002
    VirtualKey := int2hex(GetKeyVK("Space"))
    ScanCode := int2hex(GetKeySC("Space"))
    NumPut(INPUT_KEYBOARD, Key1_Down, "UInt") ;4 bit
    NumPut(VirtualKey, Key1_Down, A_PtrSize, "UShort")
    NumPut(ScanCode, Key1_Down, A_PtrSize*2, "UShort")
    NumPut(KEYEVENTF_EXTENDEDKEY, Key1_Down, A_PtrSize*3, "UInt")
    able := DllCall("SendInput", "UInt", 1, "Ptr", &Key1_Down, "Int", A_PtrSize*5+4)
    Tooltip, % able
}
/*
DWORD type;              -> 0
  union {
         MOUSEINPUT mi; 
         KEYBDINPUT ki;    -> 4
         HARDWAREINPUT hi;
        };
  WORD wVk;                -> 8
  WORD wScan;              -> 16
  DWORD dwFlags;           -> 24
  DWORD time;              -> 28
  ULONG_PTR dwExtraInfo;   -> 36
*/
;convertions, collected from forum
int2hex(int)
{
    HEX_INT := 2, h := ""
    while (HEX_INT--)
    {
        n := (int >> (HEX_INT * 4)) & 0xf
        h .= n > 9 ? chr(0x37 + n) : n
        if (HEX_INT == 0 && HEX_INT//2 == 0)
            h .= ""
    }
    return "0x" h
}
Which will show a "0" in the tooltip. Any ideas??????
ps:
If the function returns zero, the input was already blocked by another thread.
Last edited by killmatt01 on 05 Aug 2021, 08:59, edited 1 time in total.
swagfag
Posts: 6222
Joined: 11 Jan 2017, 17:59

Re: How to simulate keystroke using SendInput via dllcall?

Post by swagfag » 05 Aug 2021, 01:52

those struct offsets look super wrong. two adjacent words in the same struct padded out to a pointer is a dead giveaway something's not right. ure filling the struct with garbage uve put in random places, so the DllCall returning 0 is probably not indicative of "the input being already blocked by another thread" but is a generic error. ud know if u checked A_LastError(like the docs said u should)

anyhow, dllcalling SendInput has been done to death, so search the forums and either find the right offsets or copy someone else's correct implementation

also these hex conversions are pointless
killmatt01
Posts: 20
Joined: 25 Mar 2021, 00:12
Contact:

Re: How to simulate keystroke using SendInput via dllcall?

Post by killmatt01 » 05 Aug 2021, 09:04

swagfag wrote:
05 Aug 2021, 01:52
those struct offsets look super wrong. two adjacent words in the same struct padded out to a pointer is a dead giveaway something's not right. ure filling the struct with garbage uve put in random places, so the DllCall returning 0 is probably not indicative of "the input being already blocked by another thread" but is a generic error. ud know if u checked A_LastError(like the docs said u should)

anyhow, dllcalling SendInput has been done to death, so search the forums and either find the right offsets or copy someone else's correct implementation

also these hex conversions are pointless
Thanks for answering. I edited the offsets a bit. Well that worked for mouse input

Code: Select all

MouseDown(key_name := "LButton")
{
    If !Instr(key_name, "Button")
        Return False
    StructSize := A_PtrSize + 4*4 + A_PtrSize*2
    WhichDown := Instr(key_name, "L") ? 0x0002 : 0x0008
    ;MOUSEEVENTF_LEFTDOWN := 0x0002, MOUSEEVENTF_RIGHTDOWN := 0x0008
    VarSetCapacity(Key_Down, StructSize)
    NumPut(0, Key_Down, "UInt") ;4 bit
    NumPut(0, Key_Down, A_PtrSize, "UInt")
    NumPut(0, Key_Down, A_PtrSize + 4, "UInt")
    NumPut(WhichDown, Key_Down, A_PtrSize + 4*3, "UInt")
    DllCall("SendInput", "UInt", 1, "Ptr", &Key_Down, "Int", StructSize)
    VarSetCapacity(Key_Down, 0)
}
so i took a try on keyboard input. Plus I cannot find the right offset for this in this forum.
teadrinker
Posts: 4295
Joined: 29 Mar 2015, 09:41
Contact:

Re: How to simulate keystroke using SendInput via dllcall?  Topic is solved

Post by teadrinker » 05 Aug 2021, 10:01

An example:

Code: Select all

KeyArray := [{sc: 0x23, event: "Down"}, {sc: 0x23, event: "Up"}, {sc: 0x17, event: "Down"}, {sc: 0x17, event: "Up"}]

InputKeyboardEvents(KeyArray)

InputKeyboardEvents(KeyArray)
{
   static INPUT_KEYBOARD := 1, KEYEVENTF_KEYUP := 2, KEYEVENTF_SCANCODE := 8, InputSize := 16 + A_PtrSize*3
   VarSetCapacity(INPUTS, InputSize * KeyArray.MaxIndex(), 0)
   addr := &INPUTS
   for k, v in KeyArray
      addr := NumPut( (v.event = "Up" ? KEYEVENTF_KEYUP : 0) | KEYEVENTF_SCANCODE | (v.sc >> 8)
            , NumPut(v.sc & 0xFF
            , NumPut(INPUT_KEYBOARD, addr + 0) + 2, "UShort"), "UInt" ) + 8 + A_PtrSize*2

   DllCall("SendInput", "UInt", KeyArray.MaxIndex(), "Ptr", &INPUTS, "Int", InputSize)
}
killmatt01
Posts: 20
Joined: 25 Mar 2021, 00:12
Contact:

Re: How to simulate keystroke using SendInput via dllcall?

Post by killmatt01 » 10 Aug 2021, 17:20

teadrinker wrote:
05 Aug 2021, 10:01
An example:

Code: Select all

KeyArray := [{sc: 0x23, event: "Down"}, {sc: 0x23, event: "Up"}, {sc: 0x17, event: "Down"}, {sc: 0x17, event: "Up"}]

InputKeyboardEvents(KeyArray)

InputKeyboardEvents(KeyArray)
{
   static INPUT_KEYBOARD := 1, KEYEVENTF_KEYUP := 2, KEYEVENTF_SCANCODE := 8, InputSize := 16 + A_PtrSize*3
   VarSetCapacity(INPUTS, InputSize * KeyArray.MaxIndex(), 0)
   addr := &INPUTS
   for k, v in KeyArray
      addr := NumPut( (v.event = "Up" ? KEYEVENTF_KEYUP : 0) | KEYEVENTF_SCANCODE | (v.sc >> 8)
            , NumPut(v.sc & 0xFF
            , NumPut(INPUT_KEYBOARD, addr + 0) + 2, "UShort"), "UInt" ) + 8 + A_PtrSize*2

   DllCall("SendInput", "UInt", KeyArray.MaxIndex(), "Ptr", &INPUTS, "Int", InputSize)
}
Many thanks!
Post Reply

Return to “Ask for Help (v1)”