Search code examples
pythoninputpyautoguipynputgamepad

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


In Short : any suggestion on how to listen to Xbox guide button ? or any suggestion on how to make "inputs" more optimized and faster for low-end PCs ?

hey. I had been looking for a way to make screenshots on windows easier. for now the only built-in function is win+prtsc , which is hard to press during a game when using a controller. I also happen to be good at programming, but i'm not familiar with input libraries on python...

so I used "pyautogui" library to simulate pressing win+prtSc , and used "pynput" library to listen to the button "/" on keyboard to do a screenshot ( well, a cheating screenshot. windows is taking screenshot and im just simulating the pressing of "win+prtSc" , so I named my script "screenshit" ).

so far so good.

it's not very hard to press "/" button for every screenshot. but to extend it, I wanted to use my controller to take the screenshot. but problem is pynput does not support gamepad controllers ! so I used another library called "inputs". this one does support a gamepad controller. however it uses at least 30% of CPU usage for working... which is BAD! here's the code to detect START ( the usual Map button ) with "inputs" library :

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

I'm guessing 'get_gamepad()' is not optimized enough... but if im wrong or using it wrong, please guide me!

So , another thing that I would like to use would be the center/guide/xbox button. this button : xbox center button

but neither "inputs" nor "pynput" libraries seem to be listen to this button...

any suggestion on how to listen to this button ?

or

any suggestion on how to make "inputs" more optimized and faster for low-end PCs ?


Solution

  • solution :

    I googled for some hours and finally found a solution to use Xbox360's guide button to take screenshot by virtually pressing win+PrtSc together. then also playing a little capture.wav sound to play whenever taking it.

    so the code is :

    // 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);
        
        
    }
    

    to work, it needs a "capture.wav" sound in the same directory as this script.

    thanks to : link1 link2 link3 link4 link5