请问如何使用DllCall的方式模拟键盘按键?

Post a reply


In an effort to prevent automatic submissions, we require that you complete the following challenge.
Smilies
:D :) ;) :( :o :shock: :? 8-) :lol: :x :P :oops: :cry: :evil: :twisted: :roll: :!: :?: :idea: :| :mrgreen: :geek: :ugeek: :arrow: :angel: :clap: :crazy: :eh: :lolno: :problem: :shh: :shifty: :sick: :silent: :think: :thumbup: :thumbdown: :salute: :wave: :wtf: :yawn: :facepalm: :bravo: :dance: :beard: :morebeard: :xmas: :HeHe: :trollface: :cookie: :rainbow: :monkeysee: :monkeysay: :happybday: :headwall: :offtopic: :superhappy: :terms: :beer:
View more smilies

BBCode is ON
[img] is OFF
[flash] is OFF
[url] is ON
Smilies are ON

Topic review
   

Expand view Topic review: 请问如何使用DllCall的方式模拟键盘按键?

Re: 请问如何使用DllCall的方式模拟键盘按键?

Post by miozus » 08 Sep 2021, 23:08

:think:

你调用 DllCall 的时候,已经超过大部分 AHK 玩家了。

追求超低延迟,并保证多线程;

这听起来,不如用 C / Java 语言实现算法提供接口,最后 AHK 粘合调用它?

Re: 请问如何使用DllCall的方式模拟键盘按键?

Post by killmatt01 » 04 Aug 2021, 20:09

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;    -> 8
         HARDWAREINPUT hi;
        };
  WORD wVk;                -> 8
  WORD wScan;              -> 16
  DWORD dwFlags;           -> 24
  DWORD time;              -> 28
  ULONG_PTR dwExtraInfo;   -> 36
*/
;==================================================================================
;convertions
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
}
tooltip将展示0
ps:
如果函数返回零,则输入已被另一个线程阻塞。
请问有什么方式解决吗?

请问如何使用DllCall的方式模拟键盘按键?

Post by killmatt01 » 29 Jul 2021, 20:31

目前已经测试成功一种方式:

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)
但由于这个函数(keybd_event)已经被取代了,我想尝试最新的SendInput函数但遇到了问题
尝试如下:

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, A_PtrSize, "UShort")
    NumPut(ScanCode, Key_Down, A_PtrSize+4, "UShort")

    NumPut(INPUT_KEYBOARD, Key_Up, "UInt")
    NumPut(VirtualKey, Key_Up, A_PtrSize, "UShort")
    NumPut(ScanCode, Key_Up, A_PtrSize+4, "UShort")

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

    NumPut(KEYEVENTF_KEYUP, Key_Up, 2*A_PtrSize+4*3, "UInt")
    DllCall("SendInput", "UInt", 1, "Ptr", &Key_Down, "Int", 40)
    sleep, 100
    VarSetCapacity(Key_Up, 0)
}
至于尝试DllCall方式的缘由:我当然知道可以直接用

Code: Select all

key := "Space" ;等等等等
Send, {%key% Down}
Send, {%key% Up}
来模拟,但这种方式在非管理员权限的窗口里有些慢,在我电脑上send函数每行需要40ms,哪怕

Code: Select all

SetBatchLines, -1
SetKeyDelay, -1, -1
因为在此寻求帮助,提前感谢!

Top