I have a problem with international keyboard input in SDL, in particular with the dead keys. I have Unicode translation enabled, so when I press the Ñ key (it's a separate key in my spanish keyboard), I get its Unicode number, which I then translate to UTF8 and everything works fine. My problem is with the characters that require two keypresses : to get the à character, I press ' and then A. In every other program, nothing appears when I press ', and when I press A, an à appears. That's how it should work. However, in SDL I'm getting two events, for ' and A in Unicode. I don't want to handle the dead keys myself (ie if I get an ' and then a vowel, substitute the character by hand), and I'm sure there must be a way to do this since SDL is used for several international apps... so... what's the secret?
I don’t know how DSL abstracts this stuff, but you may understand SDL better if you fist understand how Windows deals with this. There is a big difference between keys on your keyboard and the character they type. You need to use different API function (or respond to different messages) depending if you want to know about key events or character events. When I press the shift key I don’t get any character typed. When I press the 3/# key I either get a 3 character or a # character depending in if the shift key is being held down. When I press the G key I either get a G character or a g character depending on the state of the shift key and the caps lock. Keys generate up and down events. Your app can be notified when the G key goes down (WM_KEYDOWN) and when the G key goes up (WM_KEYUP). Games often use key events for actions like run, jump, move and shoot because they want to know if the key is being help and when it gets released. You should never use key events for input fields such as when a player types his name. Key messages to not include ASCII or UNICODE is for the keys. That comes later when a character is generated by the key. The keys are identified by SCAN codes or virtual key codes. There is not a separate scan code for the # key vs. the 3 key. That is a single key with a single scan code. Most keyboard have another key on the numeric keypad that can also type a 3 character. That 3 key has a different scan code than the 3 key at the top of the keyboard. Windows sends WM_CHAR messages when characters are typed. This is what you should respond to when someone is typing in a name. There is no such thing as a character being pressed and released. Characters get typed but not released. A character never goes "UP". This makes character messages bad for thing link run, jump, and duck. Characters are identified by ASCII codes or UNICODE. There is a different character code for 3 and #. But both 3 keys generate the same 3 character. There are not different character codes for the 3 typed on the numeric keyboard vs. the 3 typed at the top of the keyboard. The keys have different scan code, but the generate the same character. In the example you mentioned, windows will send WM_KEY up and down message for both of the keys pressed (’ and A) and also send a fifth message of type WM_CHAR to represent the à character. If you want to know when a player types a à character you should be responding to WM_CHAR messages (or the UNICODE equivalent). If you want to know when the ' KEY is pressed or released you need to be responding to WM_KEYxx messages and looking for virtual key codes or scan codes rather than ASCII or UNICODE. The ' key on your keyboard does not generate CHAR messages until another key is pressed but it does generate KEY up and KEY down messages. It's much like a shift key. It's not a dead key. It does generate KEY messages. It just doesn't type any chacaters just like the shift key doens't type characters.
I know that's how it works in Windows, I just don't know what's the equivalent in SDL, since SDL doesn't have separate messages for keypresses and chars And since the keypress event has a Unicode member, I think these events do the equivalent of TranslateMessage()... I don't know how to interpret it though.
Just to make sure: Gabriel, you are using the unicode member of the SDL_keysym struct, right? If not, try that
I hope not... I could do an ugly hack and handle the spanish keys... german and french keyboards are doable... but korean??? Yes, I am. Do you do text inputs?
If SDL doesn't have a solution for this (maybe you can look through its source?), you can always override the message handler for the window and handle the proper Windows WM_CHAR events (or whatever) yourself. Of course, this isn't cross-platform, but at least it's something.
Yes, but our game doesn't currently support unicode. Someday we may, so I'd be interested if you do find a solution to this problem! Sounds like it's a flaw in SDL itself... as far as I know, there's no other method for obtaining char data from a keystroke. (Well, there's SDL_GetKeyName, but I think it will only report on the key pressed/released, ignoring modifiers.)
That sounds to me like a big flaw in the design SDL. I hope an SDL expert could come along and explain it for us. I seems very bad to me to shield the developer form the differences between key presses and the characters they generate. So in SDL, how can you tell if the shift key is down? Do they make up a fake UNICODE or ASCII value for shift?
Actually, I think SDL does work pretty similarly to the way Windows' WM_KEY/WM_CHAR system does. If you want the key up/down events, you look at the SDL_keysym's sym member. If you want the "char" value, you look at the SDL_keysym's unicode member (which is only defined on keydown events). I think the problem here is that the unicode result is broken for the non-standard "modifier" keys. As you can see here, the list of modifier keys is static... so, if your keyboard uses a modifier key that is not listed, I imagine that SDL will ignore it for the purposes of deciding the value of the unicode member. For standard modifiers, it works fine. (ie. If you press "SHIFT-A" the unicode member's value will be a capital "A".)
This is fine if you are trying to type an A but not fine if you are trying to use shift as your duck or jump key. My question was how can an game use SDL to see if the shift key was pressed.
Yep, soniCron is right. SDL_keysym's sym member is analogous to Windows' WM_KEY events. My SDL game uses arrow keys (which have no character representation), and the up/down sym values are exactly what I need. I think Gabriel's problem is a (smaller) flaw in SDL: The unicode value doesn't account for foreign "modifier" keys.
Exactly. The SDL_KEYDOWN event has a lot of info (scan code, key symbol, modifiers, unicode translation), so you CAN know when the user presses the shift key without any problem. The problem is that the unicode translation apparently doesn't work as expected for foreign characters composed using dead keys. It works just fine for Ñ (U001F) which is a single key in my keyboard, but not for á or Ã, because of the dead key.
A quick search of the SDL source shows no signs of handling the WM_DEADCHAR message, which would be required to do what you want. It looks like a quick little hack in SDL_dibevents.c in DIB_HandleMessage() might do the trick. I think I can see how to code something that will work, but I can't test it as I have no dead keys on my keyboard. I suggest you have a look at the source and do something similar to the NO_GETKEYBOARDSTATE hack, but in the WM_KEYUP code -- and looking for WM_DEADCHAR, instead of WM_CHAR, course. Please let us know if you come up with a fix that works.
Remember: If you change the SDL source itself, you're going to have to redistribute that source with your program! If you submit your fix as a patch to the SDL project, hopefully they'll merge it into the next release... then there'll be no problem
You don't have to distribute the changed SDL sources with your program, but you do have to make them available for anyone who asks for it (possibly for a fee). If you don't want to go through the hassle of changing SDL, do what I suggested earlier: override the winproc of the SDL window, handle the WM_ events, and post an SDL event to the SDL loop in response. (I have sample code available if you want it, although it's not for WM_DEADCHAR.)
Actually, I don't even think he'd need to go that far. He could post a link to the SDL website and a .diff of his changes, which should suffice. That said, the one problem with these suggestions is that he loses cross-platform compatability until his patch is accepted to the next SDL release (which would be months) and someone else writes code for Mac and Linux (which could be years even). I don't know if he's interested in cross-platform development, but if so, it won't help to have only Windows code that handles this. Of course, I have nothing to offer!
I just checked out with one of my games that my SDL event handling seems to correctly handle dead keys. I couldn't find anything really specific about it in the source, though.. and my bitmap font didn't really support much of the special chars. But for the few umlaut ones it has, the dead key method of entering them worked fine (i.e. press ¨ and then a resulted in ä). I noticed one thing in initialization though; it is probably pretty essential that you call SDL_EnableUNICODE(1); (and it probably has to be called after other SDL initialization). Other than that I just check in SDL_KEYDOWN SDL_Event processing that ctrl/alt are not pressed down and then event.key.keysym.unicode contains the char code.
So are you saying this ' key doesn't generate a WM_KEYDOWN and WM_KEYUP messages like a shift key would? I woun't expect it to generate any WM_CHAR message since it doen't type a character. To be honest, I am not familar with WM_DEADCHAR. I can understand why a WM_DEADCHAR message would be genrated rather than a normal WM_CHAR. But I don't understand why WM_KEYxx messages wouln't be generated or why you wouldn't use them if they are generated. According to the MSDN doecs, the WM_DEADCHAR is generated when a WM_KEYUP message is translated by the TranslateMessage function. So it seems the WM_KEYxx message are being generated. Isn't that what you should be resonding to?