Archived

This topic is now archived and is closed to further replies.

Advanced DirectInput keyboard input?

This topic is 5370 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

How could I write an DirectInput keyboard interface wich allows US-Style keyboards and EU-Style keyboards without the key-positions getting changed? I also want to be able to get the input as an string, because I want to write an console window using DirectInput. Could anybody point me to the ultimate DirectInput tutorial/code/whatever wich covers all I need?

Share this post


Link to post
Share on other sites
I noticed that directInput doesen''t allow you to specify the type of keyboard, but I didn''t know the mapping is different!

Do you have a list of the key codes as they appear on the actual keys?



www.cppnow.com

Share this post


Link to post
Share on other sites
Guest Anonymous Poster
to get strings with directinput, you have to store the character equivalents of each key and buffer them when you need a string. its really a pain in the arse...at least thats the way i did it...if there''s an easier way let me know. also, you have to handle things like the repeat rate for keys being held down, since directinput doesn''t do that for you, and for each press you will probably get multiple letters, like getting "hhhhhhhhheeeeeeeeellllllllllllllllloooooooo" when pressing the keys H E L L O...to get the repeat rates through the windows api i did this:


// determine keyboard repeat rate for text entry mode
int winKeyDelay;
SystemParametersInfo(
SPI_GETKEYBOARDDELAY,
0,
&winKeyDelay,
0
);
// windows stores the key delay as an int with the range
// 0 - 3; 0 being ~250ms, and 3 being ~1000ms so we have to
// convert it into a millisecond ammount
s_keyRepeatDelay = (winKeyDelay + 1) * 250;

DWORD winKeySpeed;
SystemParametersInfo(
SPI_GETKEYBOARDSPEED,
0,
&winKeySpeed,
0
);
// windows stores the key repeat speed as a DWORD ranging
// from 0 to 31; 0 being ~2.5 repeats per second, and 31
// being ~30 repeats per second; this means that for each
// 1 that the windows value goes up, the number of
// milliseconds between repeats goes down by ~11.5, starting
// at 400 for a windows value of 0
s_keyRepeatRate = 400 - (WORD)(((float)(winKeySpeed)) * 11.5f);

to store the keys with their character equivalents i used an array of these structs:


struct IKey {
bool isPrintable;
char printUpper;
char printLower;
bool isPressed;
bool justPressed;
DWORD timePressed;
DWORD lastRepeat;
bool wasPressed;
};

to populate the struct i had this function:


/***********************************************************
** IInitializeKeystate()
************************************************************/
void IInitializeKeystate () {
// this is gonna be nice and long...
// give appropriate printing characters to the
// keys that require them
for (WORD x = 0; x < NUM_KEYS; x++) {
s_lastKeystate[x].isPrintable = true;
s_lastKeystate[x].isPressed = false;
s_lastKeystate[x].timePressed = 0;
s_lastKeystate[x].lastRepeat = 0;
s_lastKeystate[x].wasPressed = false;

if (x == KEY_1) {
s_lastKeystate[x].printLower = ''1'';
s_lastKeystate[x].printUpper = ''!'';
}
else if (x == KEY_2) {
s_lastKeystate[x].printLower = ''2'';
s_lastKeystate[x].printUpper = ''@'';
}
else if (x == KEY_3) {
s_lastKeystate[x].printLower = ''3'';
s_lastKeystate[x].printUpper = ''#'';
}
else if (x == KEY_4) {
s_lastKeystate[x].printLower = ''4'';
s_lastKeystate[x].printUpper = ''$'';
}
...

note i redefined the DIK_ key names, since this particular implementation is intended to be somewhat portable...

anyway, i don''t know if any of that helps, but thats what i got...

Share this post


Link to post
Share on other sites
also, in that previous post, s_keyRepeatDelay is the time in milliseconds before a key starts repeating, and s_keyRepeatRate is the time in milliseconds between repeasts.

and to test if a key should be repeated, my code looks like this:


// go through the keystates and send text messages as
// needed
for (WORD x = 0; x < NUM_KEYS; x++) {
IKey * key = &s_lastKeystate[x];

// deterime if key should be sent or repeated at all
if (!key->isPressed)
continue;
if (!key->wasPressed) {
// first press; send it
}
else {
if (key->lastRepeat == 0) {
// no repeats yet, see if we should
if (!((TimeGetTicks() - key->timePressed) > s_keyRepeatDelay))
continue; // no repeat yet
else
key->lastRepeat = TimeGetTicks(); // repeat
}
else {
// repeats have happened, see if we should again
if (!((TimeGetTicks() - key->lastRepeat) > s_keyRepeatRate))
continue; // no repeat yet
else
key->lastRepeat = TimeGetTicks(); // repeat
}
}

note: TimeGetTicks() is equivalent to GetTickCount() just redefined to help with portability

Share this post


Link to post
Share on other sites
Just a general rule:

don''t use the

if()
else if()
else if()
else if()

style of programming.

Use a switch statement. Its much faster.

switch(key)
{
case ''a'':
// do stuff
break;
case ''b'':
// do stuff
break;
}

Share this post


Link to post
Share on other sites
Guest Anonymous Poster
Switch is not necessarily faster. If you have case 1 , 2 , 3 etc.. then yes.If you have case 23, 56, 78 then it is slower. Case also only allows integers where if statements allow for any kind of argument. This kind of , don''t do this, don''t do that statements should be done away with. You have no idea what the purpose of that if statement is, or if it will change later. Let him code the way he wants. Also switch statements does have a limit on how many cases you can have. As do if else. It all comes down to planning.

Share this post


Link to post
Share on other sites
AP, I personally don''t care which way he does thing. I just remember reading in my Ansi C book that switch is much faster because the CPU has 1 compare then a jump, instead of doing a compare for each if statement.

Just trying to give some advice, but...

Share this post


Link to post
Share on other sites
btw, if you want a simpler way to store text, you could handle WM_CHAR messages in your winproc...it will give you the correct case of the character and i believe it automatically handles repeating keys correctly


Share this post


Link to post
Share on other sites
quote:
Original post by meniond
gotta love how it took all my code spacing out...how do i get it to appear in a text box thing inside the message?


You have to use source and /source within square brackets to get formating.

Share this post


Link to post
Share on other sites
Also, I've done the code for repeat delay but just make it a standard repeat rate. My code looks like this:


    
// I know GetTickCount doesn't have the greatest granularity

// but it is suitable for keyboard purposes


// m_dwLastKeyTime holds the last time a particular key

// was returned from this function


// m_cLastKeySent holds the index into the buffer used by

// the keyboard input device thus matching the DIK_xxx values


// my CKeyboard class provides a TranslateKey method

// to translate the pChar and pModifierKey into a human readable

// format.

if(m_dwLastKeyTime == 0)
{
// get the time

m_dwLastKeyTime = GetTickCount();
hRet = GetKey(pChar, pModifierKey);
if(hRet == S_OK)
{
m_cLastKeySent = *pChar;
}
} else {
hRet = GetKey(pChar, pModifierKey);
if(hRet == S_OK)
{
if(m_cLastKeySent == *pChar)
{
// check for repeat time

DWORD m_dwNewTick = GetTickCount();
if(m_dwNewTick - m_dwLastKeyTime > m_dwRepeatTime)
{
m_dwLastKeyTime = m_dwNewTick;
} else {
hRet = S_FALSE;
}
} else {
m_dwLastKeyTime = GetTickCount();
m_cLastKeySent = *pChar;
}
}
}


The GetKey method does NOT return multiple keys. It loops through the key state array and returns the first one encountered as the currently pressed key. This is fine for typing.

For key presses that I need to know about I provide an IsKeyDown and AreKeysDown for multiple key presses at the same time. I could call IsKeyDown multiple times for the keys I'm interested in but that has an overhead of querying the hardware for current state each query.

Happy coding.

[edited by - LordShade on March 29, 2003 4:40:24 PM]

Share this post


Link to post
Share on other sites
Another thing, when translating keys to printable characters, do NOT do a huge switch or if/then/else function. Create a table of data that associates the SYSKEY with LowerChar, UpperChar, etc. This allows you to use a simple lookup based on the SYSKEY parameter.


  
// structure for holding your data

typedef struct tagKeyLookup
{
char cLower;
char cUpper;
} KEY_LOOKUP, *P_KEY_LOOKUP;

KEY_LOOKUP g_KeyTransTable[] =
{
{ /* DIK_0 */ 0, ), },
{ /* DIK_1 */ 1, !, },
// etc....
{ /* DIK_A */ a, A, }, // should be at DIK_A offset
{ /* DIK_B */
b, B, }, // should be at DIK_B offset

// etc...

};



Share this post


Link to post
Share on other sites