![]() |
|
This thread is locked; no one can reply to it.
![]() ![]() |
1
2
|
5.1 SVN, Windows: keyboard state, wrong modifier flags, patch |
Dennis
Member #1,090
July 2003
![]() |
UPDATE Patch is attached. [1] Reproducing/Demonstrating the problem without patch: 1.) Run ex_keyboard_events in Windows. 2.) Press and hold SHIFT+P in the main Window and see how the modifier flags and the keyboard events are correctly displayed in the log. 3.) While still holding the keys from step 2, switch away from the main window by clicking something else. 4.) Release all keys. 5.) Click back into the main window and press any key and see how the SHIFT modifier flag is incorrect. Patch Description: The patch does not clear the keyboard state on switching out to achieve consistency with an event based handling (where you would not receive KEY_UP messages either if you switch away while you're still holding down something). I also added some modifier flags which seemed to be missing in the function which handled modifier flag updates (special L/RWIN keys and MENU key). Demonstrating the fix after patching: Someone should test and confirm, before committing this. --- 0xDB | @dennisbusch_de --- |
torhu
Member #2,727
September 2002
![]() |
Sigh. Let me try to explain. Quote: Numpad Enter does work and sets the state flag for both the normal Enter and the Numpad Enter whereas the normal Enter only sets the state for the normal Enter and not the Numpad Enter, so if you test the state flag for Numpad Enter you can be sure that's what was pressed. So if the numpad Enter was pressed, I get the other Enter as a bonus? That's just wrong. I don't want to special case the Enter keys in my game, I want Allegro to take care of it. And currently it does that just fine. From reading MSDN docs, I'm pretty sure that neither GetKeyboardState, GetKeyState, nor GetAsyncKeyState can actually do what you want here, as there is no bit for the extended key flag. In other words, this cannot be done properly. What I think you should do is this:
Nothing more. Don't update the non-toggle modifiers either, just clear everything. It's consistent, less code, easier to maintain. And games don't use the modifier keys as modifiers, they just use them as any other key. Another thing you can do: Update the toggle modifiers in the keyboard driver initialization, this is missing. And, yes add the missing keys in update_modifiers. |
Dennis
Member #1,090
July 2003
![]() |
torhu, you're quoting information I wrote about the old, wrong patch, which is why I won't respond to that here. This patch is entirely new and does not do what the old patch did. It only addresses what is described in the first post of THIS thread. Nothing more, nothing less. If there are other issues, I need a clean description of the problem and the steps necessary to reproduce the erroneous behavior before I can patch it. --- 0xDB | @dennisbusch_de --- |
torhu
Member #2,727
September 2002
![]() |
I did read your new patch before replying, and it does update the keys in basically the same way. So what I said still applies. |
Dennis
Member #1,090
July 2003
![]() |
Your examination of the new patch can not have been very thorough then as it clearly does additional things and some things different and also, what's more important, does it only on switching-in and not all the time like the old wrong patch (which was addressing different issues that this one is not addressing). Clearing the state on switching out would cause an inconsistency with the event system: I repeat again: This patch only fixes the wrong modifier flags as described in the OP. I also repeat again: The information from the old thread you quoted does NOT apply to this patch. The behavior is different. --- 0xDB | @dennisbusch_de --- |
torhu
Member #2,727
September 2002
![]() |
Dennis said: Clearing the state on switching out would cause an inconsistency with the event system: Unless you generate "fake" events to sync it up, the state and the events will be out of sync anyway. This is not a big deal. Just forget about this. I think that you need to stop for a bit, go back and actually read and understand the code, starting here. And then do some testing with ex_keyboard_events, pressing different kinds of keys on your keyboard. See what ALLEGRO_KEY_* codes they generate. Especially the extended keys, and the numpad keys, with Num Lock on and off, etc. Because your patch does not give the same ALLEGRO_KEY constants as the event system does. Please make some effort to understand how things work. It's hard to create a good patch if you don't know what you are doing. I improved and bugfixed some of the Allegro Windows code, and to do that I had have a good understanding of it. I am not making things up when I say that your patch has problems. |
Thomas Fjellstrom
Member #476
June 2000
![]() |
Maybe since you have a better understanding of the problems involved, you could make the necessary fixes? -- |
torhu
Member #2,727
September 2002
![]() |
I guess, but I shouldn't be coding since my left shoulder is fucked up for the time being I thought I had given pretty exact intructions how to do this, but I don't seem to get through |
Elias
Member #358
May 2000
|
torhu: Are you saying when returning after the switch, we should not use GetKeyboardState() but another function to update the state? -- |
torhu
Member #2,727
September 2002
![]() |
No. The state cannot be properly updated, so don't try either. See this. EDIT: |
Elias
Member #358
May 2000
|
torhu said: 2. Update the toggle modifier keys. From reading the patch it looks like that's what the GetKeyboardState() is for. -- |
Dennis
Member #1,090
July 2003
![]() |
torhu said: I thought I had given pretty exact intructions how to do this, but I don't seem to get through The problem here is that in my opinion, you're displaying quite the annoying and immature attitude and I'm tempted to simply ignore you (I am aware of the fact that this makes me seem immature as well but you're not exactly making this easy). You also seem to fail at understanding the very limited scope and purpose of this small patch in this thread. I also doubt you tested the new patch because if you had, you would have noticed that the state is being correctly reported by al_get_keyboard_state after switching back in because after the fire-just-once-on-switch-in update it is immediately based on the event maintained state afterwards which already was correct before the patch (before the old one which has already been reverted). I explained why the state can not be cleared on switching out. There are other issues. Those can be addressed in another patch outside of the scope of this one as described in the OP. torhu said: The state cannot be properly updated, so don't try either. The state can be properly updated in that case, because the respective function to do so to acquire the state from the Windows API is called within the correct thread. Please stop spreading false information. The only case where it would not work correctly (by system design) is when the Window does not have input focus. That's consistent with the event driven system however so it's a non-issue. --- 0xDB | @dennisbusch_de --- |
torhu
Member #2,727
September 2002
![]() |
This is from your patch. Note how it loops over all the 256 elements. Is this not the patch you are talking about? This loop will cause the key state to be wrong, like I have been repeatedly trying to tell you. What you need to to is to update only some of the keys. I suggest only Scroll Lock, Num Lock and Caps Lock. The update_toggle_modifiers function does this for you already. Updating the other modifiers, is an option, but not much point IMHO. Since you can't update all the keys correctly, I think it's better to make all keys (except the toggle modifiers) behave consistently. 1+ if (windowHandle != NULL) {
2+ /* Get real most current state from Windows API call. */
3+ _al_win_wnd_call_proc(windowHandle, fill_windows_keyboard_state,
4+ &ret_val);
5+ if (ret_val) {
6+ /* Translate Windows key states to Allegro key states. */
7+ for (i = 0; i < 256; i++) {
8+ if (win_key_state[i] & 0x80)
9+ _AL_KEYBOARD_STATE_SET_KEY_DOWN(the_state, hw_to_mycode[i]);
10+ else
11+ _AL_KEYBOARD_STATE_CLEAR_KEY_DOWN(the_state, hw_to_mycode[i]);
12+ }
13+
14+ /* Update toggle modifier key flags. */
15+ update_toggle_modifiers();
16+
17+ /* Update modifier key flags. */
18+ update_modifiers(ALLEGRO_KEY_LSHIFT, _AL_KEYBOARD_STATE_KEY_DOWN(the_state, ALLEGRO_KEY_LSHIFT));
19+ update_modifiers(ALLEGRO_KEY_RSHIFT, _AL_KEYBOARD_STATE_KEY_DOWN(the_state, ALLEGRO_KEY_RSHIFT));
20+ update_modifiers(ALLEGRO_KEY_LCTRL, _AL_KEYBOARD_STATE_KEY_DOWN(the_state, ALLEGRO_KEY_LCTRL));
21+ update_modifiers(ALLEGRO_KEY_RCTRL, _AL_KEYBOARD_STATE_KEY_DOWN(the_state, ALLEGRO_KEY_RCTRL));
22+ update_modifiers(ALLEGRO_KEY_ALT, _AL_KEYBOARD_STATE_KEY_DOWN(the_state, ALLEGRO_KEY_ALT));
23+ update_modifiers(ALLEGRO_KEY_ALTGR, _AL_KEYBOARD_STATE_KEY_DOWN(the_state, ALLEGRO_KEY_ALTGR));
24+ update_modifiers(ALLEGRO_KEY_LWIN, _AL_KEYBOARD_STATE_KEY_DOWN(the_state, ALLEGRO_KEY_LWIN));
25+ update_modifiers(ALLEGRO_KEY_RWIN, _AL_KEYBOARD_STATE_KEY_DOWN(the_state, ALLEGRO_KEY_RWIN));
26+ update_modifiers(ALLEGRO_KEY_MENU, _AL_KEYBOARD_STATE_KEY_DOWN(the_state, ALLEGRO_KEY_MENU));
27+ }
28+ }
I think we should just stop this here. I will do it later this summer. |
Dennis
Member #1,090
July 2003
![]() |
torhu said: This loop will cause the key state to be wrong, like I have been repeatedly trying to tell you. No, it does cause the key state to be synchronized with the key state that the windowing system (Windows) intends for the application. An application is not intended/supposed (by the system) to know of any keys being pressed while it does not have input focus. It is also not supposed to get key up messages while it does not have input focus. It is only supposed to know the last state as it was when it lost focus. When it gets focus back it is only natural that you need to press a key again to get another key down message or in this case an updated state (which you will get correctly even by al_get_keyboard_state because the Windows events will update the state after that initial correction). Quote: Updating the other modifiers, is an option, but not much point IMHO. It's not optional. If shift is not pressed anymore after switching back in, pressing just P should not still report shift. That's what this patch fixes. --- 0xDB | @dennisbusch_de --- |
Elias
Member #358
May 2000
|
torhu said: Updating the other modifiers, is an option, but not much point IMHO. So you are suggesting that in the initial example, when you press P, the .modifiers field of the event should have the SHIFT bit set, even though shift is not pressed? It's a very minor issue of course, but it seems to make more sense to not set it (and it's also what we do under X11). -- |
Dennis
Member #1,090
July 2003
![]() |
There are other issues (which I repeat, this patch does not address, I lost count how many times I stressed that). For example, if a key is being held while switching in, the event system never gets a key-down and thus it can't be correctly reported in the state. This would then not be consistent with the default behavior of Windows applications only relying on (Windows)event (not Allegro Events) based input. But again, that will have to be fixed in a separate patch. --- 0xDB | @dennisbusch_de --- |
Thomas Fjellstrom
Member #476
June 2000
![]() |
torhu said: What I think you should do is this: Clear all keys. So wait, if you hold a key down, switch away, and switch back in, that key is now no longer pressed according to allegro or the app? I don't think that makes as much sense as you think it does. Broken key state ftl. -- |
torhu
Member #2,727
September 2002
![]() |
Okay, looks like I'll be up all night anyway... Dennis said: If shift is not pressed anymore after switching back in, pressing just P should not still report shift. Is this your original issue? Like said earlier: just clear the state (as in the_state) on switch in. With a single call to memset(). That's it. In addition, I would call update_toggle_modifiers(). Thomas Fjellstrom said: So wait, if you hold a key down, switch away, and switch back in, that key is now no longer pressed according to allegro or the app? I don't think that makes as much sense as you think it does. Broken key state ftl. Now I think you're just looking for mistakes in my posts Just for fun I tried confusing the Allegro 4 game Saucelifter by switching in/out while holding keys, etc. And it didn't take much to mess it up. This is just for illustrating the problem, I know we are talking about Allegro 5. It's just not going to be perfect no matter what we do. But it can be made a bit less noticeable. |
Thomas Fjellstrom
Member #476
June 2000
![]() |
torhu said: Now I think you're just looking for mistakes in my posts Not in your posts, but in what you think might be a good solution. Quote: Windows does not seem to give you enough information to do this through the keyboard state API. So the state API doesn't give you the current state of the keyboard? That seems a bit broken. Maybe I'm misunderstanding what you're talking about here. Quote: Only through window (WM_KEYDOWN etc.) messages. I must be misunderstanding what you're talking about. As WM_KEY events are very broken afaik. It won't send key up events if a key was released outside of the app. Where as, the key state stuff should tell you what the current state is. Quote: And I think just clearing all keys (except the 3 toggle modifiers) is a good solution, instead of updating some keys but not others. But that leads to very broken state. I think we should fix it, rather than leaving it broken. In either case, I don't think allegro should be reporting broken state at all. If allegro's view of the state doesn't match the actual state of the keyboard (regardless of what windows may say it is at any given time via WM_KEY events), its just broken, and needs to be fixed. Even if that means patching up the key state, and sending synthesized events. To be honest, I think the Allegro 5 key state api was a bad idea to begin with. -- |
torhu
Member #2,727
September 2002
![]() |
Thomas Fjellstrom said: So the state API doesn't give you the current state of the keyboard? That seems a bit broken. Maybe I'm misunderstanding what you're talking about here. Of course it does. It's just that Allegro presents a different view of the keyboard, which requires some extra information to create (I have already explained this, please don't ask again). The Windows keyboard state stuff is probably very old, and they haven't updated the API to match the capabilites of the window message system. Maybe because they expect people to use one of the event/message systems instead. Which is what both A4 (yes, it does) and A5 does. Quote: In either case, I don't think allegro should be reporting broken state at all. If allegro's view of the state doesn't match the actual state of the keyboard (regardless of what windows may say it is at any given time via WM_KEY events), its just broken, and needs to be fixed. Even if that means patching up the key state, and sending synthesized events. It's not really broken. It's just that you can't hold down a key while switching to your A5 game and expect it to register. You switch to it, then start playing. Not a big deal, and I wouldn't be surprised if many non-Allegro games behave like this. It's just that you don't notice, because you generally don't do this unless you are testing you keyboard input system What you would notice is keys that get "stuck" in the pressed state. Clearing the key state fixes that. Which is why I keep suggesting it. Quote: I must be misunderstanding what you're talking about. As WM_KEY events are very broken afaik. It won't send key up events if a key was released outside of the app. Where as, the key state stuff should tell you what the current state is. Does other GUI systems do this? I have no idea. That's a different discussion than this anyway. At least it's a different patch. |
Thomas Fjellstrom
Member #476
June 2000
![]() |
torhu said: (I have already explained this, please don't ask again) If you're going to be as antagonistic as you have been in the past couple threads, why should I bother go read your rather negative posts? Especially considering you conveniently push aside points others bring up and claim they aren't an issue, but YOUR problems are all important Give us a calm and thorough explanation of all the issues, and maybe we'll take your word for it. -- |
Bruce Perry
Member #270
April 2000
|
This code is taken from the 'key pressed' event handler in wkeyboard.c that torhu linked to: /* Check for an extended key first. */ my_code = 0; if (extended) my_code = extkey_to_keycode(vcode); /* Map a non-extended key. This also works as a fallback in case the key was extended, but no extended mapping was found. */ if (my_code == 0) { if (vcode == VK_SHIFT) /* Left or right Shift key? */ vcode = MapVirtualKey(scode, MAPVK_VSC_TO_VK_EX); my_code = hw_to_mycode[vcode]; } Allegro aims to represent ALLEGRO_KEY_ENTER and ALLEGRO_KEY_PAD_ENTER as two entirely separate keys. But let's look at how Allegro does that:
This is from Dennis's patch: + for (i = 0; i < 256; i++) { + if (win_key_state[i] & 0x80) + _AL_KEYBOARD_STATE_SET_KEY_DOWN(the_state, hw_to_mycode[i]); + else + _AL_KEYBOARD_STATE_CLEAR_KEY_DOWN(the_state, hw_to_mycode[i]); + } When that loop hits i==0x0D, it will update ALLEGRO_KEY_ENTER. But it's possible that Windows will have set win_key_state[0x0D] if ALLEGRO_KEY_PAD_ENTER is held down. If so, then ALLEGRO_KEY_ENTER will be set incorrectly. Have you checked for this? Even if the loop doesn't introduce an error here, it is still incomplete, as it will never set the entry for ALLEGRO_KEY_PAD_ENTER (because ALLEGRO_KEY_PAD_ENTER doesn't appear in the hw_to_mycode array). (The other thing I was going to mention is that the loop indiscriminately writes garbage to the_state[0] for all the keys with no entries in hw_to_mycode, but then, the existing code does that too.) Right - now that all that is said: torhu, you're in danger of driving away a possible contributor. You could tweak your explaining-fu as follows: torhu said: So if the numpad Enter was pressed, I get the other Enter as a bonus? That's just wrong. I don't want to special case the Enter keys in my game, I want Allegro to take care of it. And currently it does that just fine. You've stated that Allegro "takes care of it" so you don't have to "special case the Enter keys". You should say exactly what Allegro does, which is to treat the Enter keys as separate unrelated keys. Quote: From reading MSDN docs, I'm pretty sure that neither GetKeyboardState, GetKeyState, nor GetAsyncKeyState can actually do what you want here, as there is no bit for the extended key flag. In order for this to make sense, you have to explain what the extended key flag is. Quote: In other words, this cannot be done properly. If you don't get through, don't shout louder. On the contrary, if you make the effort to explain, then Dennis will either reach the same conclusion or win you over to his view, and no one will need to use any underlines. You're absolutely right to defend Allegro 5's best interests - don't stop doing that - just find a more diplomatic way to do it. [APPEND] If I'm playing a game and something like Windows Update or a calendar reminder pops up and steals focus, then there are a number of things I'd like the game to do:
When I go back to the game, I will happily release and re-press a key if I was holding it and it doesn't respond the first time. This is accepted behaviour, as is very rare anyway since the default physical state of a keyboard is 'all keys up' anyway. On the other hand, if my player is moving to the right the whole time, it isn't intuitive to have to press the right arrow again to stop the movement. I usually naturally try to fix it by pressing the left arrow first a few times, which you can imagine accomplishes nothing and is quite frustrating. So pragmatically speaking, the 'broken state' torhu is recommending is a very practical option that will make all real users happy. It's a perfectly good solution if Dennis's approach can't be implemented safely, and it's definitely better than accidentally setting state for a key that isn't held down. (Nothing wrong with the state API. Just fix the bugs, as you would in any other piece of code. Forcing your users to worry about mismatched KEY_DOWN and KEY_UP events, just because Windows does, is on the other hand quite negligent. I would advocate synthetic KEY_UP events on focus loss, perhaps optional but enabled by default, or perhaps flagged as synthetic inside the event object. Oh yeah, another thing that might be good if it's not currently possible - the ability to get the full keyboard state as it was at the time of the current event, as opposed to the latest possible state.) -- |
torhu
Member #2,727
September 2002
![]() |
Thanks for your input, Bruce. This thread needed it. To be fair, this discussion started in another thread, where I already have explained what "extended" keys are, probably more than once. And I didn't start "shouting" until having posted the same information multiple times and having it seemingly ignored. I was hoping that underlining the main points would help. As for the Enter keys, I think he already knew that Allegro treated them as two different keys. I'm posting this clarification in the hope that more people won't start to "gang up on me". Please treat this as a technical discussion, not a political one. Dennis: If my suggested solution is not the right one, please explain the original issue. |
Thomas Fjellstrom
Member #476
June 2000
![]() |
Bruce Perry said: When I go back to the game, I will happily release and re-press a key if I was holding it and it doesn't respond the first time. This is accepted behaviour, as is very rare anyway since the default physical state of a keyboard is 'all keys up' anyway. And you can do that yourself. I just don't think we should make it impossible to get correct keyboard state/events in the case of switch outs. -- |
SiegeLord
Member #7,827
October 2006
![]() |
Bruce Perry said: But it's possible that Windows will have set win_key_state[0x0D] if ALLEGRO_KEY_PAD_ENTER is held down. If so, then ALLEGRO_KEY_ENTER will be set incorrectly. Have you checked for this? Here's how to reproduce this with the current code (using the patch from this thread): 1. Modify ex_keyboard_events to report the ALLEGRO_KEY_ENTER state. E.g. like this: static void log_key(char const *how, int keycode, int unichar, int modifiers) { char multibyte[5] = {0, 0, 0, 0, 0}; const char* key_name; al_utf8_encode(multibyte, unichar <= 32 ? ' ' : unichar); key_name = al_keycode_to_name(keycode); log_printf("%-8s code=%03d, char='%s' (%4d), modifiers=%08x, [%s]\n", how, keycode, multibyte, unichar, modifiers, key_name); }
2. Run the example, highlight the log window and press and hold the numpad enter key "For in much wisdom is much grief: and he that increases knowledge increases sorrow."-Ecclesiastes 1:18 |
|
1
2
|