Advertisement

Using Direct Input to get input.

Started by February 25, 2000 04:38 PM
5 comments, last by Snowman 24 years, 6 months ago
Hi- Despite the topic, this question isn''t as easy as it seems. (At least as far as I can tell anyway). Here''s the problem: I created a wrapper for Direct Input, and it works great. It''s clean, re-usable code. Everythings good there. The only problem that I run into is when I need to get input from the user in a situation other than the actual game. For example, let''s say they need to enter the players name, or they need to specify the IP address to connect to, or they need to type a message to a frined (during multiplayer) or they need to move the cursor up and down the screen to select different menus......the list goes on and on. If I have a loop like this: GetInput(); ProcessInput(); ClearInput(); Repeat It goes to fast, and trying to select a menu, or hit a letter once is very difficult. So, I changed it to look like this: if( timePassed > 100ms ) GetInput(); ProcessInput(); ClearInput(); Repeat Now the problem with this is that sometimes keys are "sticky" You press them down but nothing comes out. This can cause many headaches as you can imagine. Plus, it''s just plain not the right solution for the problem. So, my question is, how do I do it so that the input doesn''t go toooo fast or tooo slow. I could work at it to get a "perfect time", but I assume that that changes for everyone, based on their particular typing styles. The only thing I can think is to take out the ClearInput() and have a "timer" for every key, so that it repeats like in Windows. When the key is first pressed down, it startsthe timer, and after a certain amount of time it repeats that key. Every time that key is lifted the timer is reset. Is that really the best way? Seems like a lot of extra code/work....... Thanks in advance for any help! -Snowman
i had the same problem what u have to do is to use buffered data which keeps a list of all keys pressed between the times you check for keyboard input, for example:

check for keyboard input every 100 ms

check #1 - No keys pressed
user presses Ctrl
user presses Tab
check #2 - Nothing New, handle key presses between two checks

(of course keys could be pressed when the keyboard is checked and they would be handled immediatly)

At check #2 you would have your code respond to the Ctrl and Tab keys.

Check out the docs and microsoft''s source code
Advertisement
just thought i might help you out with some source code

first u have to do a set property on the device(keyboard)
Do this when setting up direct input.

DIPROPDWORD dipdw;
dipdw.diph.dwSize = sizeof(DIPROPDWORD);
dipdw.diph.dwHeaderSize = sizeof(DIPROPHEADER);
dipdw.diph.dwObj = 0;
dipdw.diph.dwHow = DIPH_DEVICE;
g_lpDIDEVICE->SetProperty(DIPROP_BUFFERSIZE, &dipdw.diph);


here is my code to check the keyboard input

void Get_KB_Input(void)
{
DWORD dwElements;
HRESULT hr;

dwElements = BUFFER_SIZE;
g_lpDIDEVICE->GetDeviceData( sizeof(DIDEVICEOBJECTDATA),
didod,
&dwElements,
0 );


#define KEYDOWN(key) (didod.dwOfs == key && didod.dwData & 0x80)<br><br><br>for (i = 0; i < dwElements; i++) <br>{<br><br>if(KEYDOWN(DIK_GRAVE))<br>{<br> if (showing_console==TRUE)<br> showing_console=FALSE;<br> else<br> showing_console=TRUE;<br>} // End If<br><br><br>}// End For<br><br><br>also do #define BUFFER_SIZE X<br>X is the number of elements to buffer, for example if the time between when you check for keyboard input is very long your would put a high number, not long small number. I use 10 and check for input every 10ms.<br><br>also here are two globals needed <br><br>DWORD i;<br>DIDEVICEOBJECTDATA didod[ BUFFER_SIZE ]; // Receives buffered data <br><br>that's all there is to it just remember to set the time when to check for input in your WinMain message loop.<br>To specify a key use can use my macro and do <br><br>if(KEYDOWN(DIK_*))<br><br><br>Edited by - +AA_970+ on 2/25/00 8:57:40 PM
I''ve run into the same problem myself, and went about solving it in a different manner. Essentially what I did was set up some 1 shot logic. You want to process the key ONCE when it''s pressed, and not process it again until it''s been released and pressed again. I just had to set up a few keys like this myself and this is what I did to take care of those instances...

BYTE keystate[256]; //Store GetDeviceState information
BYTE oneshot[256]; //Used for oneshot logic below

Zero out oneshot and keystate (though keystate will get zero''d by the call to GetDeviceState then to check for a keypress, this is what I did (leaving out the macros)

if (keystate[DIK_F11] & 0x80 && keystate[DIK_F11] ^ oneshot[DIK_F11])
{
//Set oneshot = to keystate
//This section of code will only be run once
oneshot[DIK_F11] = keystate[DIK_F11];
//Do processing for F11 key
}
else if(keystate[DIK_F11] == 0)
oneshot[DIK_F11] = 0; //Key released, clear out oneshot.


This code will only process the F11 key once when it''s pressed. It may or may not be better, but it''s what I use at this time to keep keyboard response instantaneous and avoid repeated processing of a keypress.
Just one note. oneshot has to be a static variable. Either declared as such, in a static function, or in a class. You''re using classes, Snowman, so you wouldn''t have a problem with it. I''m not using classes at this time (waiting till I have a much stronger grasp of everything DirectX), but my main game function is static since there were so many variables in it that I wan''t to be static.
theRaskell:
I posted a similar question a while back about this problem so I was glad to see your suggestion. I just added the code you suggested and it works like a charm. Nice work!

Arrow
Advertisement
Thanks guys, works great! =)

-Snowman

PS I could''ve swore the docs said I was doing buffered input before............

This topic is closed to new replies.

Advertisement