2

I started working on a small bot project as a fun way to dive into the win32 api (among other things). In particular, SendInput is only behaving as expected in some instances.

As a proof of concept I set up a loop to send the 's' key just to make sure things are working. If I set the window I want to activate as Notepad, text appears just fine. But if I set the window to Ikaruga, the window pops up but the menu doesn't change (game uses WASD for menu navigation, so it should just continually go down).

I have read in multiple places that games have some (not very reliable) options for blocking external input. To check if that was the case, I found a project where someone built a key sender. The particular project I used is here enter link description here . His code sent 's' keys to Ikaruga as expected.

He included his source code. I've spent a fair bit of time reading over it. While a lot of the functions he is using have been superseded, the overall code flow is similar.

Hopefully, someone can provide me some guidance on what I'm doing wrong.

#ifdef _MSC_VER
#define _CRT_SECURE_NO_WARNINGS
#define _CRT_NONSTDC_NO_DEPRECATE
#endif

#define WINVER 0x0500
#include <windows.h>
#include <stdio.h>
#include <tchar.h>

void AppActivate(LPCTSTR windowTitle){

    // Get first window on desktop
    HWND firstwindow = FindWindowEx(NULL, NULL, NULL, NULL);
    HWND window = firstwindow;
    TCHAR windowtext[MAX_PATH];

    // Guard against search word matching current console title
    TCHAR consoletitle[MAX_PATH];
    GetConsoleTitle(consoletitle, MAX_PATH);

    while (1){
        // Check window title for a match
        GetWindowText(window, windowtext, MAX_PATH);
        if (strstr(windowtext, windowTitle) != NULL && strcmp(windowtext, consoletitle) != 0){
            break;
        }

        // Get next window
        window = FindWindowEx(NULL, window, NULL, NULL);
        if (window == NULL || window == firstwindow){
            fprintf(stderr, "Window not found\n");
        }
    }
    fprintf(stderr, "Window found: %s\n", windowtext);

    // Bring specified window into focus
    AllowSetForegroundWindow(true);
    ShowWindow(window, SW_RESTORE);
    SetForegroundWindow(window);
    SetFocus(window);
}

int main(int argc, char* argv[]){
    AppActivate("Ikaruga");

    Sleep(2000);

    // Create a generic keyboard event structure
    INPUT ip;
    ip.type = INPUT_KEYBOARD;
    ip.ki.wVk = 0; // scan code for 's'
    ip.ki.time = 0;
    ip.ki.dwExtraInfo = 0;


    while (1){
        // Press the "S" key
        ip.ki.wScan = 0x1F; // 0x1F 's'
        ip.ki.dwFlags = 0; // 0 for key press
        SendInput(1, &ip, sizeof(INPUT));

        // Release the "S" key
        ip.ki.wScan = 0x1F;
        ip.ki.dwFlags = KEYEVENTF_KEYUP;
        SendInput(1, &ip, sizeof(INPUT));

        char msgbuf[200];
        sprintf(msgbuf, "Pressing S\n");
        OutputDebugString(msgbuf);

        Sleep(2000);
    }

    return 0;
}

Edit: I forgot to mention that I've tried setting the code on both wVK/wScan and 's' vs 0x53.

JR Smith
  • 1,186
  • 15
  • 20
  • Well if it's working for notepad it should work fine for other things. Though you might want to check how the game scans its inputs. Some use the character value and some use the position value (and badly coded ones use more or less both wit bugs). – meneldal Jun 04 '15 at 04:05
  • As for games that want to block external input to avoid bots or the like, usually the best solution to go through the anti-cheat things is to change the keyboard driver code. – meneldal Jun 04 '15 at 04:08
  • So noted with regard to anti-cheating techniques. However, the external program I tried out does not appear to be altering the keyboard driver code. Instead, it grabs a string from a message box with user input and converts each character to a BYTE and passes it along. At this point, my assumption is that I'm missing some crucial piece. – JR Smith Jun 04 '15 at 04:12
  • 1
    One difference between your code and the code you linked is that it calls SetFocus when activating the window. – Ross Ridge Jun 04 '15 at 04:14
  • So you confirm it finds the game window just fine right? – meneldal Jun 04 '15 at 04:14
  • @RossRidge why is it working with notepad then? It doesn't make much sense. – meneldal Jun 04 '15 at 04:15
  • @RossRidge I did miss that, thought I thought the SW_RESTORE flag also set focus (probably a misreading on my part) I'll change the OP to include it though. – JR Smith Jun 04 '15 at 04:16
  • @meneldal I can confirm it pulls Ikaruga up from a minimized position and makes it an active window. – JR Smith Jun 04 '15 at 04:17
  • `SW_RESTORE` doesn't activate keyboard focus but `SetForegroundWindow` should https://msdn.microsoft.com/en-us/library/windows/desktop/ms633539%28v=vs.85%29.aspx Try to check the return value – meneldal Jun 04 '15 at 04:18
  • @meneldal SetForegroundWindow returns a 1. – JR Smith Jun 04 '15 at 04:28
  • Well seems to be a problem in the API then. Might be because the game graphic library that fails to do as the API requests. – meneldal Jun 04 '15 at 04:31
  • Many (most?) games use the DirectInput API. It is my understanding that SendInput doesn't affect DirectInput. – Harry Johnston Jun 04 '15 at 04:36
  • I'm not a direct input exert, but checking from another SO question, it appears that DirectInput will accept scan codes but not virtual key codes. http://stackoverflow.com/questions/7320424/c-win32-simulate-keypress-with-directinput – JR Smith Jun 04 '15 at 04:40
  • Well you can put this as an answer so you can accept it and remove it from the list of unanswered questions. – meneldal Jun 04 '15 at 04:48
  • I altered the OP to show using scan codes (I had gone back and forth in my experimenting), so I'm not sure that anything discussed above answered the question. It looks like DirectInput games accept scan codes (assuming Ikaruga uses DI), but it still leaves unanswered why the game isn't responding to it. Unless I missed something? – JR Smith Jun 04 '15 at 04:55

0 Answers0