No unicode information in key releases

Hello everyone

I’ve got a problem; remember when we were discussing possible SDL_GetKeyState drawbacks and why it’s better to use events? Since then I rewritten my input manager to use events just like you adviced me to do; it worked perfectly (well, at least it helped me to overcome “bug” that couldn’t let you type uppercase characters :-)) until today, when I discovered that my edit control in GUI doesn’t respond to keypresses. I fixed it, but then, I’ve seen that actuall test demo (that operates with keyboard just like real game will do) doesn’t respond to keypresses. I fixed it, but then again, GUI wasn’t working as expected - when pressing anything combined with shift, that key reported keypresses even when in reality, it was released long ago. I’ve investigated code and it all comes to one line of code, let me show you:--------------------------

// it’s called at the beginning of main loop:

bool SC :: InputTask :: Start()
{
// ignore to speed things up in the Kernel and InputTask Update sections that loop through all received events.

SDL_EventState(SDL_MOUSEMOTION, SDL_IGNORE);
SDL_EnableUNICODE(1);
if ( SDL_EnableKeyRepeat(300, 30) == -1)
logError2(“Input”, “Couldn’t set key repeat value.”)

// SDL_GetKeyState returns a reference to the key state array, not a copy, so we must copy it manually
tmpKeys = SDL_GetKeyState( &keyCount );

actKeys = new uchar[keyCount];
if (!actKeys) return false;

oldKeys = new uchar[keyCount];
if (!oldKeys)
{
Stop();
return false;
}

// twice to flush any pending keypresses
SDL_PumpEvents();
SDL_PumpEvents();

memset(oldKeys, 0, keyCount);
memset(actKeys, 0, keyCount);
return true;
}


// it’s called every frame

void SC :: InputTask :: Update()
{
SDL_PumpEvents();

// this construction dispatches up to 8 keypresses each frame
maxEventCount = 8;
// copy actual keypresess to old ones
memcpy( oldKeys, actKeys, keyCount);

// memset(actKeys, 0, keyCount); // ### it’s here !!!

while ( (SDL_PollEvent ( &event )) && (maxEventCount))
{

if (event.type == SDL_KEYDOWN)
 {
  if ((event.key.keysym.unicode ) == 0)
   actKeys[event.key.keysym.sym] = 1;
  else
   actKeys[event.key.keysym.unicode] = 1;
 }
 else if (event.type == SDL_KEYUP) 
 {
  actKeys[event.key.keysym.sym] = 0;  // ***
 }
--maxEventCount;

}

}


The problem really lies in that the key realeses doesn’t have unicode codes attatched, so if we press ie. shift + 1 (which on my keyboard produces !) then it’s keysym.sym and keysym.unicode will vary, and therefore -> in this line (***) it won’t toggle old unicode off, which will forever produce keypresses for !.
I’ve found possible solution to this: each frame, clear actual keys so that even when sth was pressed, it won’t stay forever (###). It makes GUI work, but test game won’t respond to any keypressess at all. If I comment that line (just like it’s now) then game will work, but GUI will suffer.
Though, there’s hope - when I allow for dynamically choosing of in what mode should input manager work (bool flag: clear each frame actKeys or not clear), then, if I remember to switch modes, GUI and game should work correctly. However, I don’t like to remember about such things - it’s counter intuitive and introduces stupid “bugs”, it would be good if it was handled by input manager internally (in some way or another).

Ehhmm, so, now the question :wink: What are other alternatives to my solution? It would be best if there was some way to dig to that unicode code even for releases… but it’s probably impossible.

Thanks in advance!


Koshmaar
<Of all the things I’'ve lost, I miss my mind the most>
GG: 3928072
http://jnr.sourceforge.net/
www.pongowar.prv.pl
www.liero-turbo.prv.pl

You can’t treat the unicode member of key events as a state.
Think of it instead as a separate event that’s piggy-backed onto the
key press event … “the unicode character X was input” Since there
is no character input generated when a key is released, the unicode
field is not filled in for a key release.

This makes a little more sense if you think about this sequence:
left-shift down
’s’ key pressed (key is SDLK_s, unicode is ‘S’)
left-shift up
’s’ key released (key is SDLK_s, unicode is meaningless)

See ya,
-Sam Lantinga, Software Engineer, Blizzard Entertainment

You can’t treat the unicode member of key events as a state.
Think of it instead as a separate event that’s piggy-backed onto the
key press event … “the unicode character X was input” Since there
is no character input generated when a key is released, the unicode
field is not filled in for a key release.

Yes I know that… maybe I didn’t make myself clear enough in the first letter.
In short: I know that I can’t get unicode information from key releases. I know ugly solution to make this work (switching between 2 modes etc. as explained in first letter). I know that on SDL mailing list there are whole lots of advanced programmers who are writing games using SDL and event based input; it would be unbelievable if no one has ever encountered this problem (at least) and solved it (that’s why I’m writing here and what I’m interested in). Are there any… hmmm, hacks which I could use?

This makes a little more sense if you think about this sequence:
left-shift down
’s’ key pressed (key is SDLK_s, unicode is ‘S’)
left-shift up
’s’ key released (key is SDLK_s, unicode is meaningless)

If meaningless == 0, then I agree :wink:

Koshmaar

Hello Koshmaar,

Selon Koshmaar :

In short: I know that I can’t get unicode information from key releases. I
know ugly solution to make this work (switching between 2 modes etc. as
explained in first letter). I know that on SDL mailing list there are whole
lots of advanced programmers who are writing games using SDL and event based
input; it would be unbelievable if no one has ever encountered this problem
(at least) and solved it (that’s why I’m writing here and what I’m interested
in). Are there any… hmmm, hacks which I could use?

There’s no hack. Nobody store keypresses in an array for use with a GUI like you
do.

Handling keyboard for a GUI and game control are two different things.

In a game context, whenever a key is pressed, you store in a array the fact the
key is down, so you will react accordingly in your input handling code as long
as it is not released. For example, if left is down, you will move player some
pixels to the left. When the key is released, you clear its state. That’s what
you’re doing in your code.

In a GUI context, whenever a key is pressed, you react to that event. If left is
pressed, you move cursor one char to the left. That’s it. You don’t need to
store anything or even handle SDL_KEYUP events. Of course, you need to use
SDL_EnableUNICODE() to get usuable infos. You will also use
SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY, SDL_DEFAULT_REPEAT_INTERVAL), to
properly handle key repeat.

So, you need to switch from one mode to the other depending on the context. For
example when you see in your main game loop that user pressed, say, F12, then
you clear all key pressed, set a flag saying you’re in GUI mode, and draw your
dialog box. Depending on the type of game (realtime or not), you will go to
another loop (in which case the games is paused) or continue in the main one,
but handling keyboard differently since you’re in GUI mode.

Best regards,

Xavier

In a GUI context, whenever a key is pressed, you react to that event. If left is
pressed, you move cursor one char to the left. That’s it. You don’t need to
store anything or even handle SDL_KEYUP events. Of course, you need to use
SDL_EnableUNICODE() to get usuable infos. You will also use
SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY, SDL_DEFAULT_REPEAT_INTERVAL), to
properly handle key repeat.

In my code, reaction to keypress resulting in sending event is completely up to application/subsystems/tasks; GUI code shouldn’t care about handling all the gory details, because it’s what input system is for. GUI just needs to call one function which loops through array of keys and returns the first which is non zero (that is - pressed) and if anything was actually pressed, “event” is fired; it’s very simple system but it works :wink:
So, input system is responsible for storing all keys in one, centralized place; application (and other systems) then can do with it what they want, but with many tasks that do input reading using different methods that can be pretty awkward since constant re-changing of mode would be needed (theoretically, in practice it won’t be the case, BUT etc…), and that’s why I wandered if there’s better way then changing states.

So, you need to switch from one mode to the other depending on the context. For
example when you see in your main game loop that user pressed, say, F12, then
you clear all key pressed, set a flag saying you’re in GUI mode, and draw your
dialog box. Depending on the type of game (realtime or not), you will go to
another loop (in which case the games is paused) or continue in the main one,
but handling keyboard differently since you’re in GUI mode.

Ok, thanks! “there’s no other way, you have to change states” - maybe that’s not what I wanted to hear, but it looks like there’s really no ther way.

Koshmaar