Skip to main content
gamedev.net
🔒 Locked 🎮 Unity

keyboard input

Started by Holland 6 replies 1k views
Original Post
Holland
Holland
Right now my input class looks roughly like this:

class CInput
{
private:
    // singleton junk
    CInput();
    CInput(const CInput&);
    CInput & operator=(const CInput&);
    static CInput * m_pSingleton;

    // SetKeyUp and SetKeyDown interface with this
    UCHAR m_keyPoll[32];

    // this is what we use to get if a key is down or up
    UCHAR m_keyState[32];

    // used for buffered input, keyState gets set to this each Update()
    UCHAR m_keyPrevState[32];
public:
    // singleton access
    static CInput * GetSingleton();

    void SetKeyDown(UCHAR _vkCode);
    void SetKeyUp(UCHAR _vkCode);
    
    // this returns a bool for XInput
    // otherwise it just swaps around the keyPoll, keyState, and keyPrevState
    bool Update(void);

    // returns true if (m_keyState & (1 << _vkCode))
    bool GetKey(UCHAR _vkCode);

    // returns true if (m_keyState & (1 << _vkCode))
    // && !(m_keyPrevState & (1 << _vkCode))
    bool GetBufferedKey(UCHAR _vkCode);

    // used for keybinding purposes, works mostly like _getch()
    UCHAR GetPressedKey(void);


SetKeyDown() and SetKeyUp() interface with the WndProc messages WM_KEYDOWN and WM_KEYUP. I tried having SetKeyDown/Up interface directly with m_keyState but got issues with buffered input due to the fact that WM_KEYDOWN/UP can be caught pretty much any time. But I figured, atleast each state is 32 bytes each instead of 256 bytes (array of bools). I have made a WinMain.cpp that has WinMain, sets up the window (this is for a game), and sets up my own WndProc to handle window messages. In WinMain.cpp I just put code in the WM_KEYDOWN and WM_KEYUP messages to call SetKeyDown(wParam) or SetKeyUp(wParam), respectively. The Update function is very very simple...looks like so:
memcpy(m_keyPrevState, m_keyState, 32);
memcpy(m_keyState, m_keyPoll, 32);

It has some XInput stuff too but that's it for keyboard input. So now, finally, on to the questions about this. 1) Is there a way to make my class independent of WndProc. Meaning...can I have my module self contained and not need to reach out for help? 2) In debug, or other low FPS situations, the input is very very delayed. It almost feels as if the windows messages are queueing up and taking a while to dispatch. Is there a way around this? 3) Is the way I'm doing this a good way of going about it? Using the UCHAR[32] setup is very nice. The code for getting to the correct bit is very simple and easily done with bitwise operations. If this isn't the best way, what is? I'm trying to stay away from using DirectInput or SDL. Thanks so much gamedev!
aeroz
aeroz
1) You could ask for keyboard states instead of listening to events: GetKeyState (http://msdn.microsoft.com/en-us/library/ms646301(VS.85).aspx)
Your class could call this function when Update() is called.
You have to choose whether you want to read the state each frame or whether you want to wait for events in the WinProc. (depends a bit on the type of game)

3) The way you do works nicely and is simple, just stay with it.

I can't help you much with 2... Debug mode shouldn't slow down your program so much. Which debugger do you use? Do you have a special configuration? Maybe too much hit count breakpoints, logging or something like that?

Regards
Holland
Holland
Quote:
Original post by aeroz
I can't help you much with 2... Debug mode shouldn't slow down your program so much. Which debugger do you use? Do you have a special configuration? Maybe too much hit count breakpoints, logging or something like that?


I do have a logger going, I didn't think about that. It keeps an ofstream open during the entirety of the program when in debug. I'm using visual studio 2005 with all of the default debug options.

Also, I thought about using GetKeyState and GetAsyncKeyState, or there is GetKeyboardState, but none of those options seemed to work as well with the bits and such. And for buffered input, I'd have to check al 256 keys each update to see what has and has not been pressed which seemed even slower. Unless there is something strange about the WndProc I don't know about.
Kippesoep
Kippesoep
Just a gut feeling, but have you checked your message loop? People usually execute their message loop once per frame, like this:

for (bool done = false; !done;){    render_frame ();    if (PeekMessage (&msg, NULL, 0, 0, PM_REMOVE))    {        if (msg.message == WM_QUIT) done = true;        TranslateMessage(&msg);        DispatchMessage(&msg);    }}


That isn't really a "message loop", but more of a "frame loop" with a "message check". One of the most noticeable results is that response to input slows down as more messages pile up in the queue. Instead, it should be something like:

for (bool done = false; !done;){    render_frame ();    while (PeekMessage (&msg, NULL, 0, 0, PM_REMOVE))    {        if (msg.message == WM_QUIT)        {            done = true;            break;        }        TranslateMessage(&msg);        DispatchMessage(&msg);    }}


Of course, I'm not psychic, so while I've experienced trouble with this, it may be unrelated to your problem.
Kippesoep
Wan
Wan
Quote:
Original post by Holland
1) Is there a way to make my class independent of WndProc. Meaning...can I have my module self contained and not need to reach out for help?

Not really if you handling window messages. I wouldn't consider it a problem for this dependency to exist, it makes sense on Windows. It's how the API works.

You could look at Get[Async]KeyState, but it comes with its own set of difficulties, exactly because it's not tied to a window. It could still 'receive' events even if the window is out of focus. And for reliable text input, you'll need to use window messages pretty much anyway.

Quote:
2) In debug, or other low FPS situations, the input is very very delayed. It almost feels as if the windows messages are queueing up and taking a while to dispatch. Is there a way around this?

Debug mode is always going to be slower of course. But I suspect the same Kippesoep. You may want to check that out first.

Quote:
3) Is the way I'm doing this a good way of going about it? Using the UCHAR[32] setup is very nice. The code for getting to the correct bit is very simple and easily done with bitwise operations. If this isn't the best way, what is? I'm trying to stay away from using DirectInput or SDL.

Personally I would just stick with bools, I don't see any reason why you would want to save a couple of bytes in a class that probably will only have one instance in the entire application. I would keep it as easy and straightforward as possible. But it's up to you.
Holland
Holland
EDIT: nevermind. in my WndProc I had a case for WM_DRAW, but it was a blank case. It was still validating it, and so PeekMessage always had a WM_DRAW message sitting in it, if nothing else. :/ Silly me...it works great now! Thank you so much.


that is exactly what the problem is! i tried to make it while instead of if, but now i'm running into a problem where it never leaves. as if there are messages non stop or something. any fix for this?

Here is the code as it stands currently:
	// Enter main event loop	while(bGameOn)	{		gStopwatch->Update();		fDeltaTime = gStopwatch->GetDeltaTime();		fTotalTime += fDeltaTime;		while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))		{ 			if (msg.message == WM_QUIT)			{				bGameOn = false;				break;			}			TranslateMessage(&msg);			DispatchMessage(&msg);		}		//	if Update returns false, game is done		if (!pGame->Update(fDeltaTime))			bGameOn = false;		pGame->Render();	}	pGame->GameShutdown();


pGame is a pointer to the game logic. gStopwatch is a timer. It uses QueryPerformanceFrequency/Counter and has some FPS functionality and stuff for debugging. I just tried this out, with the while loop, and it just got stuck in there and never went on to update and render.
Kippesoep
Kippesoep
Hehe. Maybe I am psychic :D
Kippesoep
Holland
Holland
In that case, what will the Florida Lotto numbers be this week? ...and next week.

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.