python 对 windows 的输入进行了优化? (和 xbox 指南按钮可以检测到吗?)

python inputs on windows optimized ? ( and xbox guide button possible to detect ? )

简而言之: 关于如何收听 Xbox 指南按钮的任何建议? 要么 关于如何使低端 PC 的“输入”更优化和更快的任何建议?

哎。我一直在寻找一种方法来简化 windows 上的屏幕截图。目前唯一的内置功能是 win+prtsc ,在使用控制器进行游戏时很难按下。我也恰好擅长编程,但我不熟悉 python...

上的输入库

所以我使用“pyautogui”库来模拟按下 win+prtSc ,并使用“pynput”库来监听键盘上的按钮“/”来做截图(好吧,作弊截图。windows 正在截图,我只是模拟按下“win+prtSc”,所以我将我的脚本命名为“screenshit”)。

到目前为止一切顺利。

每个屏幕截图都按“/”按钮并不难。但为了扩展它,我想使用我的控制器来截取屏幕截图。但问题是 pynput 不支持游戏手柄控制器!所以我使用了另一个名为“输入”的库。这个确实支持游戏手柄控制器。然而,它至少使用了 CPU 的 30% 用于工作……这很糟糕! 这是使用“输入”库检测 START(通常的地图按钮)的代码:

while 1:
    events = get_gamepad()
    if events:
        print(events[0].code)
        if events[0].code == 'START' :
            ScreenShot()

我猜 'get_gamepad()' 优化不够...但如果我错了或使用不当,请指导我!

所以,我想使用的另一件事是 center/guide/xbox 按钮。这个按钮: xbox center button

但是“inputs”和“pynput”库似乎都没有听这个按钮...

关于如何听这个按钮有什么建议吗?

关于如何使低端 PC 的“输入”更优化和更快的建议?

您是否尝试过在 while 循环中休眠(一毫秒左右)?也许 returns 功能立即生效,这就是您 CPU 使用率高的原因?

例如在我当前使用的库(Java、LWJGL + GLFW)中,没有控制器输入事件。相反,您可以随时请求它们。这会导致同样的问题。

关于 XBox 按钮:我的库也没有它的事件。该按钮可在 Windows 10 上打开 XBox 菜单。可能它 100% 专用于该菜单,否则无法使用。 (因此检测不到)

Python 的 inputs 库使用 XInput API 作为 Windows 上的游戏手柄输入,这有一些内置限制。在 XInput 中,应用程序使用 XInputGetState 方法访问当前游戏手柄状态:

https://docs.microsoft.com/en-us/windows/win32/api/xinput/nf-xinput-xinputgetstate

按钮和轴状态在 XINPUT_GAMEPAD 结构中返回,它甚至无法表示 Xbox 按钮。某些应用程序通过调用替代(未记录)方法来解决此问题,该方法具有与 XInputGetState 相同的签名和与 XINPUT_GAMEPAD 相同格式的 returns 数据,但包含 Xbox 按钮的额外位状态。

https://www.google.com/search?q=%22XInputGetStateEx%22

即使您使用未记录的 API 方法,您 仍然 不会获得 Xbox 按钮输入,除非您禁用启动 Xbox 的 Windows 设置当您按下 Xbox 按钮时,Xbox Game Bar。启用此设置后,将禁止所有其他应用程序使用 Xbox 按钮。

另请注意,XInput 没有任何类型的输入事件。每次调用 XInputGetState 时,它只是根据最近的输入返回游戏手柄的当前状态。调用它快于 250Hz 是不必要的,因为这是 Xbox 控制器可以发送新输入的最快速度。对于您的屏幕截图应用程序,60Hz 应该足够了。这意味着在 get_gamepad.

调用之间增加约 16 毫秒的睡眠时间

解决方案:

我在谷歌上搜索了几个小时,终于找到了一个解决方案,即通过虚拟同时按下 win+PrtSc 来使用 Xbox360 的引导按钮截取屏幕截图。然后也播放一点 capture.wav 声音来播放它。

所以代码是:

// compile using :
// g++ prtScX.cpp -lwinmm
    
    
#define WIN32_LEAN_AND_MEAN
#include <iostream>
#include <stdio.h>
#include <windows.h>
#include <mmsystem.h>
#pragma comment(lib, "winmm.lib")

static const int guide_button_value = 0x0400;

/* the secret function outputs a different struct than the official GetState. */
typedef struct
{
    unsigned long eventCount;
    WORD wButtons;
    BYTE bLeftTrigger;
    BYTE bRightTrigger;
    SHORT sThumbLX;
    SHORT sThumbLY;
    SHORT sThumbRX;
    SHORT sThumbRY;
} XINPUT_GAMEPAD_SECRET;

// returns 0 on success, 1167 on not connected. Might be others.
int(__stdcall *secret_get_gamepad)(int, XINPUT_GAMEPAD_SECRET *); // function pointer to secret (guide compatible) getstate */
void Screenshot();

int main(int argc, char **argv)
{
    TCHAR xinput_dll_path[MAX_PATH];
    GetSystemDirectory(xinput_dll_path, sizeof(xinput_dll_path));
    strcat(xinput_dll_path, "\xinput1_3.dll");
    HINSTANCE xinput_dll = LoadLibrary(xinput_dll_path);
    secret_get_gamepad = (int(__stdcall *)(int, XINPUT_GAMEPAD_SECRET *))GetProcAddress(xinput_dll, (LPCSTR)100); // load ordinal 100

    XINPUT_GAMEPAD_SECRET pad1;
        
    printf("listening to keys now...\n");

    if (secret_get_gamepad(0, &pad1) != 0)
    {
        printf("Error, make sure your player 1 pad is connected.\n");
        return -1;
    }

    for (;;) // forever
    {
        secret_get_gamepad(0, &pad1);
        if (pad1.wButtons & guide_button_value)
        {
            printf("Guide button is down.\n");
            Screenshot();
            Sleep(500);
        }
        Sleep(33);
    }

    // you should probably clean up by unloading the DLL.
    return 0;
}

void Screenshot()
{
    // WIN KEY
    
    // ...
    INPUT win_in;
    // ...
    // Set up a generic keyboard event.
    win_in.type = INPUT_KEYBOARD;
    win_in.ki.wScan = 0; // hardware scan code for key
    win_in.ki.time = 0;
    win_in.ki.dwExtraInfo = 0;

    // Press the "A" key
    win_in.ki.wVk = VK_LWIN;  // virtual-key code for the "win" key
    
    // PRTSC KEY
    
    INPUT prtcs_in;
    
    // Set up a generic keyboard event.
    prtcs_in.type = INPUT_KEYBOARD;
    prtcs_in.ki.wScan = 0; // hardware scan code for key
    prtcs_in.ki.time = 0;
    prtcs_in.ki.dwExtraInfo = 0;

    // Press the "A" key
    prtcs_in.ki.wVk = VK_SNAPSHOT;  // virtual-key code for the "PrtSc" key
    
    
    
    // actually hitting 
    
    win_in.ki.dwFlags = WM_KEYDOWN; // key press down
    SendInput(1, &win_in, sizeof(INPUT));
    
    prtcs_in.ki.dwFlags = 0; // key press down
    SendInput(1, &prtcs_in, sizeof(INPUT));
    
    win_in.ki.dwFlags = WM_KEYUP; // key press up
    SendInput(1, &win_in, sizeof(INPUT));
    
    PlaySound(TEXT("capture.wav"), NULL, SND_FILENAME | SND_ASYNC);
    
    
}

要工作,它需要在与此脚本相同的目录中发出“capture.wav”声音。

感谢:link1 link2 link3 link4 link5