2

I'm getting use to the basics of game programming and design. I'm currently trying to practice with using the command line to render images for a platformer by looping the screen output. I just want to make a few simple projects, e.g clock, tetris, cellular automata(looking forward to Game of Life ¯\_(ツ)_/¯ ), etc before using any advanced libraries or going into something like Unity®.

I used the GetAsyncKeyState(VK_key) function I found from various online resources to control the player with the arrow keys. This works, in fact a little too well. It has the unintended effect of controlling the player even when the program is in the background/ not in focus/ inactive.

So how do I CONSTANTLY get keyboard button states/input ONLY while program is in focus?

I've looked for various solutions, one of which was the first answer here.
It required me knowing the process id of the program, to which I tried variants of (I only used one at a time):

#define _CRT_SECURE_NO_DEPRECATE
#include <stdio.h>
#include <stdbool.h>

#ifdef _WIN32
    #include <Windows.h>
    #define SLEEP(x) Sleep(x) // takes milliseconds(ms)
#else
    #include <unistd.h>
    #define SLEEP(x) usleep(x * 1000) // takes microseconds(μs)
#endif

void printInColour(char str[], unsigned short colour) {
    HANDLE hcon = GetStdHandle(STD_OUTPUT_HANDLE);
    SetConsoleTextAttribute(hcon, colour);
    printf("%s", str);
    SetConsoleTextAttribute(hcon, 7); // Set back to default.
}

bool key_pressed(int key) {
    return (GetAsyncKeyState(key) != 0);
}

bool IsForegroundProcess()
{
    HWND hwnd = GetForegroundWindow();
    if (hwnd == NULL) return false;

    DWORD foregroundPid;
    if (GetWindowThreadProcessId(hwnd, &foregroundPid) == 0) return false;

    //return true;
    //return (foregroundPid == GetProcessId( GetStdHandle(STD_OUTPUT_HANDLE)));
    //return ( foregroundPid == getpid() );
    //return (foregroundPid == GetCurrentProcessId());
    //return (foregroundPid == GetProcessIdOfThread(GetStdHandle(STD_OUTPUT_HANDLE) ));
    return (foregroundPid == GetThreadId( GetStdHandle(STD_OUTPUT_HANDLE)));
}

void main() {
    // ...
    while(isRunning) {
    //...
        if (IsForegroundProcess())
            printInConsole(">> Currently Active\n", 10); // Debug in green
        else
            printInConsole(">> Return to focus\n", 12); // ...and red

        if (key_pressed(VK_UP) != 0) {/*...*/} // jump, etc

        SLEEP(1000);
    }
}

I edited the code to remove the actual game. The fix I tried constantly fails saying it's out of focus. I'm open to any suggestions of how to get key pressed info(but only when program is in focus/active). Also, any tips for a newcomer into this daunting world of creating games will be vastly appreciated.

j08691
  • 204,283
  • 31
  • 260
  • 272
J. Doe
  • 41
  • 3
  • I personally believe that using a boolean variable and using the event processing function for the window would be the cleanest implementation. See here: https://stackoverflow.com/a/7301529/1988708 – Liam Potter Dec 17 '17 at 22:00
  • If would probably be useful to [edit] your question to include more of a [mcve], where you show handling a key press, the function call to `isMyProcessActive` and the relevant code you used to retrieve `foregroundPid`. I assume you are simply using `IsForegroundProcess` from the other answer, where only your `return` statement differs – Tas Dec 17 '17 at 22:01
  • Your windows get told by a message when it becomes active and stops being active see: https://msdn.microsoft.com/en-us/library/windows/desktop/ms646274(v=vs.85).aspx So all you have to do is to ignore input when you are not the active window. – Richard Critten Dec 17 '17 at 22:14
  • Your window will get messages when a key is first pressed and released, and this already plays nicely on a per-window basis. You can always use that information directly instead of [using global state to manage a local problem](https://blogs.msdn.microsoft.com/oldnewthing/20081211-00/?p=19873). – chris Dec 17 '17 at 22:16
  • Cool, I've tried my best to filter out that part of the code. But what's this `isProcessActive` all about? – J. Doe Dec 17 '17 at 23:18
  • @Liam and @Richard, could you pls help me apply that concept into my code, I am confused at to how to use things like `WndProc()` .. (is that supposed to be a switchstatement or what?) and `WM_ACTIVATE`, etc despite reading msdn docs(I generally don't follow them properly, I work better with in-code examples). Thx for the feedback – J. Doe Dec 17 '17 at 23:24
  • If you're using a console window instead of a typical window, then you can use [`ReadConsoleInput`](https://learn.microsoft.com/en-us/windows/console/readconsoleinput) to read the events instead of using typical window messages. Of course it's also possible to disable echoing etc. Still no need to elevate this to finding which window is active. – chris Dec 17 '17 at 23:40
  • How do I use it? I tried using it in place of `GetAsyncKeyState` but it didn't work. And will it be able to get all keys and mouse input? Could you please help me post an answer implementing it in my code – J. Doe Dec 18 '17 at 00:29
  • Pls, if anyone sees this, I could really use help in applying one of the methods above to my code, or anything they feel can help me with my problem – J. Doe Dec 18 '17 at 15:55

1 Answers1

0

Use FindWindow() in combination with GetForegroundWindow() or GetFocus()

HWND hMyWindow = FindWindow(NULL, L"MyWindowName");
HWND hFocusWindow = GetForegroundWindow();

//May also use:
//HWND hFocusWindow = GetFocus();

if (hMyWindow == hFocusWindow)
{
    //do stuff
}
GuidedHacking
  • 3,628
  • 1
  • 9
  • 59