【问题标题】:How to keep pynput and ctypes from clashing?如何防止 pynput 和 ctypes 发生冲突?
【发布时间】:2019-05-07 16:05:00
【问题描述】:

我在这个网站的某个地方使用这个 gem。

import ctypes
import pynput


SendInput = ctypes.windll.user32.SendInput

W = 0x11
A = 0x1E
S = 0x1F
D = 0x20

# C struct redefinitions 
PUL = ctypes.POINTER(ctypes.c_ulong)
class KeyBdInput(ctypes.Structure):
    _fields_ = [("wVk", ctypes.c_ushort),
                ("wScan", ctypes.c_ushort),
                ("dwFlags", ctypes.c_ulong),
                ("time", ctypes.c_ulong),
                ("dwExtraInfo", PUL)]

class HardwareInput(ctypes.Structure):
    _fields_ = [("uMsg", ctypes.c_ulong),
                ("wParamL", ctypes.c_short),
                ("wParamH", ctypes.c_ushort)]

class MouseInput(ctypes.Structure):
    _fields_ = [("dx", ctypes.c_long),
                ("dy", ctypes.c_long),
                ("mouseData", ctypes.c_ulong),
                ("dwFlags", ctypes.c_ulong),
                ("time",ctypes.c_ulong),
                ("dwExtraInfo", PUL)]

class Input_I(ctypes.Union):
    _fields_ = [("ki", KeyBdInput),
                 ("mi", MouseInput),
                 ("hi", HardwareInput)]

class Input(ctypes.Structure):
    _fields_ = [("type", ctypes.c_ulong),
                ("ii", Input_I)]

# Actuals Functions

def PressKey(hexKeyCode):
    extra = ctypes.c_ulong(0)
    ii_ = Input_I()
    ii_.ki = KeyBdInput( 0, hexKeyCode, 0x0008, 0, ctypes.pointer(extra) )
    x = Input( ctypes.c_ulong(1), ii_ )
    ctypes.windll.user32.SendInput(1, ctypes.pointer(x), ctypes.sizeof(x))

def ReleaseKey(hexKeyCode):
    extra = ctypes.c_ulong(0)
    ii_ = Input_I()
    ii_.ki = KeyBdInput( 0, hexKeyCode, 0x0008 | 0x0002, 0, ctypes.pointer(extra) )
    x = Input( ctypes.c_ulong(1), ii_ )
    ctypes.windll.user32.SendInput(1, ctypes.pointer(x), ctypes.sizeof(x))


# directx scan codes http://www.gamespp.com/directx/directInputKeyboardScanCodes.html
# ganna need to rework pynput for this to work
import time


def asdf():
    while True:
        PressKey(0x11)
        time.sleep(1)
        ReleaseKey(0x11)
        time.sleep(1)

asdf()

但是仅仅导入了pynput,就会返回这个错误。

ctypes.ArgumentError: 参数 2: : 预期 LP_INPUT 实例而不是 LP_Input

这个小的 ctypes 脚本确实可以独立运行,但我真的很想尝试将这些机制整合到我的程序的其余部分中。我不想废弃我的代码的 pynput 部分。它变得相当大。

有什么方法可以阻止他们尝试相互合作吗?因为我认为这是因为 pynput 更像是一个包装器,并且在某种程度上增加了它提取的数据。具体不太清楚,还在学习中。

我需要 ctypes 的原因是因为它是我发现的唯一输出直接输入的解决方案。(适用于游戏和任何使用 directx 的东西。) 抱歉,如果这不是足够的信息,或者我以丑陋的方式发布了这个。愿意通过建议来解决这个问题。

更新:

去学习c。

这是错误的其余部分。

Traceback(最近一次调用最后一次):文件 “C:/Users/bbdan/PycharmProjects/Playground/directkeys.py”,第 72 行,在 asdf() 文件“C:/Users/bbdan/PycharmProjects/Playground/directkeys.py”,第 67 行,在 自卫队 PressKey(0x11) 文件“C:/Users/bbdan/PycharmProjects/Playground/directkeys.py”,第 50 行,在 按键 ctypes.windll.user32.SendInput(1, ctypes.pointer(x), ctypes.sizeof(x)) ctypes.ArgumentError: argument 2: : 预期 LP_INPUT 实例而不是 LP_Input

【问题讨论】:

  • 哪行代码触发了上述错误?您将 pynput 导入放在哪里(以及它的外观如何)?
  • 好吧,如果我在最后调用 asdf 函数,并且在顶部导入了 pynput,就在导入 ctypes 的正下方,则会在 PressKey(0x11) 的 asdf 函数上触发错误) 在 asdf 中,接着是 ctypes.windll.user32.SendInput(1, ctypes.pointer(x), ctypes.sizeof(x))。我将快速编辑代码以显示复制错误的外观。
  • 我猜 pynput 也定义了这些结构,但名称略有不同(区分大小写不同)。然后我还猜测它还将ctypes.windll.user32.SendInputargtypesrestype 设置为它自己的结构。如果我的猜测是正确的,那么您在函数中本地为它设置 argtypesrestype 到您的结构中,应该可以解决问题。无论如何,您应该在调用任何函数之前始终为它设置它们stackoverflow.com/questions/52268294/….
  • 出于好奇,在SendInput = ctypes.windll.user32.SendInput 之后添加print(ctypes.windll.user32.SendInput.argtypes, ctypes.windll.user32.SendInput.restype)
  • (, , ) 是的,你说得对。 pynput 确实搞砸了。我将如何继续设置 argtypes 和 restypes?

标签: python-3.x directx ctypes directinput pynput


【解决方案1】:

这个问题是从here 链接的,让我意识到了这个问题。

对于仍然遇到此问题的任何人,pynputmaster 分支已更新为在 argtypes 调用中不使用内部类型,而是使用通用 @987654323 @,它应该与您传递的任何内容兼容。

【讨论】:

  • 感谢您修复这个摩西!
【解决方案2】:

pip install input,玩了一下。我的猜测是正确的,Pynput 定义了这些结构,但名称略有不同,并将 ctypes.windll.user32.SendInputargtypes(和 restype)设置为其自己的定义。
这就是为什么当您尝试提供结构实例时,它会看到它抱怨类型不匹配。

有许多解决方案可以解决此问题。无论如何,最简单的一种是简单地用 Pynput 替换你的结构(你不再需要它们)。

注意:这只是一个愚蠢的替换,事情可以组织得更好,我确信 Pynput 有自己的机制来实现这一点,以免用户编写此代码。

PressKeyReleaseKey的2个修改版本:

def PressKeyPynput(hexKeyCode):
    extra = ctypes.c_ulong(0)
    ii_ = pynput._util.win32.INPUT_union()
    ii_.ki = pynput._util.win32.KEYBDINPUT(0, hexKeyCode, 0x0008, 0, ctypes.cast(ctypes.pointer(extra), ctypes.c_void_p))
    x = pynput._util.win32.INPUT(ctypes.c_ulong(1), ii_)
    SendInput(1, ctypes.pointer(x), ctypes.sizeof(x))

def ReleaseKeyPynput(hexKeyCode):
    extra = ctypes.c_ulong(0)
    ii_ = pynput._util.win32.INPUT_union()
    ii_.ki = pynput._util.win32.KEYBDINPUT(0, hexKeyCode, 0x0008 | 0x0002, 0, ctypes.cast(ctypes.pointer(extra), ctypes.c_void_p))
    x = pynput._util.win32.INPUT(ctypes.c_ulong(1), ii_)
    SendInput(1, ctypes.pointer(x), ctypes.sizeof(x))

注意:此处遇到的(更复杂的)变体:[SO]: ctypes.ArgumentError when using kivy with pywinauto

【讨论】:

  • 哇!太感谢了。我想我有点浪费时间学习 C++。不过,将 python 和它进行比较并不难,所以看起来我可能会毫不犹豫地接受它。甚至花了很多时间试图弄清楚 ctypes 是如何工作的。再次,非常感谢。
  • 获取知识绝不是浪费时间(因为它以后可能会派上用场)。不客气!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-04-19
  • 2012-12-02
  • 1970-01-01
  • 1970-01-01
  • 2018-10-22
  • 1970-01-01
相关资源
最近更新 更多