PB's keyboard library and "problematic" keys

Just starting out? Need help? Post your questions and find answers here.
User avatar
luis
Addict
Addict
Posts: 3893
Joined: Wed Aug 31, 2005 11:09 pm
Location: Italy

PB's keyboard library and "problematic" keys

Post by luis »

Since I'm writing my keyboard sub-library for the lib I'm working on, I had to confront with the numerous quirks of the windows keyboard model.

More infos:

http://blog.ngedit.com/2005/06/13/whats ... put-model/

I'm encountering some problems, and I thought to check if the PB keyboard library solved them in some way or simply ignored them. It seem it simply ignore them, so I'm asking your opinion... it's perfectly ok for you (and so if I do the same it will sound reasonable to you) or do you think something should be done to treat these keys in a different way ?

For the F10 / Left Alt I don't see a way honestly, but for the other... maybe something convoluted can be thought.

Example follow for a couple of the more problematic keys

Code: Select all

  OpenWindow(0,10,10,600,400,"KEYB")
  ButtonGadget(1, 450,10, 100, 30, "keyb")
  
  If InitSprite() And InitKeyboard() And OpenWindowedScreen(WindowID(0),0,0,400,300,0,0,0)
    Paused = #False
    Repeat
      iEvent = WindowEvent()
      FlipBuffers()

      If StartDrawing(ScreenOutput())

        ExamineKeyboard()
        If KeyboardReleased(#PB_Key_F9) ; all ok
        ; If KeyboardReleased(#PB_Key_F10) ; press f10 and see what happen, then try f10 and down arrow to show the system menu
        ; If KeyboardReleased(#PB_Key_LeftControl) ; press right alt instead !
        ; If KeyboardReleased(#PB_Key_LeftAlt) ; problem similar to F10
        
          If Paused = #False
            Paused = #True
          Else
            Paused = #False
          EndIf
        EndIf

        DrawingMode(0)

        If Paused = #False
          DrawText(20, 20, "Program is running...")
        Else
          DrawText(20, 20, "Program paused...    ")
        EndIf

        StopDrawing()
      EndIf
    Until KeyboardPushed(#PB_Key_Escape) Or iEvent = #PB_Event_CloseWindow
  EndIf
Try the code as it is, and press F9

Code: Select all

If KeyboardReleased(#PB_Key_F9) ; all ok
then activate (uncomment) the line below and obviously comment out the previous one

Code: Select all

If KeyboardReleased(#PB_Key_F10)
try with f10, as you see doesn't work quite right

and then the following one

Code: Select all

If KeyboardReleased(#PB_Key_LeftControl) 
Try to press the Left Control, all seem ok. But then try to press the Right Alt. Surprise! It's seen like a Left Control.


Now: I know this is "normal". F10 activates a menu or the system menu (try to press f10 and then down arrow to see the system menu appear). Similar thing with Left Alt. About the Right Alt (also known as AltGr) it actually generate two messages, to simulate the ctrl+alt combination. That's why the third version of the "if" works with both keys.

The questions are...

1) Were you expecting the keyboard library to work this way?

2) Is that a problem in your view ?


Please note that when working in full screen than only this case

Code: Select all

 If KeyboardReleased(#PB_Key_LeftControl) ; press right alt instead !
... is acting "funny".
Last edited by luis on Mon Aug 09, 2010 4:12 pm, edited 2 times in total.
"Have you tried turning it off and on again ?"
A little PureBasic review
User avatar
idle
Always Here
Always Here
Posts: 5836
Joined: Fri Sep 21, 2007 5:52 am
Location: New Zealand

Re: PB's keyboard library and "problematic" keys

Post by idle »

You would hope that it worked like you specified.

F10 on my system seems to be firing two releases, pause-running
Pressing F10 + Down Arrow does nothing that I can see.
Ctrl key works fine on US keyboard, pressing right alt does nothing
though if I change the keyboard layout to Spanish and press the right alt I suspect it would fire a ctrl+Alt
User avatar
luis
Addict
Addict
Posts: 3893
Joined: Wed Aug 31, 2005 11:09 pm
Location: Italy

Re: PB's keyboard library and "problematic" keys

Post by luis »

idle wrote:You would hope that it worked like you specified.
Well that's the general idea, there are exceptions as you pointed out with the USA layout.

That layout is one where the right ALT is simply an ALT and not a ALTGR.

In many other layouts, for the example the one I'm using (the international US layout) the right ALT is actually an ALTGR and behave as explained above (and the PB library simply ignore this).

http://en.wikipedia.org/wiki/Keyboard_l ... ted_States

Problem is, I would know I to put a workaround in my code, but I cannot do so because I cannot alter the message queue using GetMessage() and then a PeekMessage() to get a preview of the next message (and hence knowing the current LCTRL I'm reading is a fake one since is followed by RALT).

Cannot do so because I need to call the WindowEvent() from purebasic after I'm done with my work, or pb programs will not work as expected anymore, and obviously if I use getmessage() that message will be lost forever.

I can use only peekmessage, and with peekmessage I can see only the message about to be processed by the next getmessage issued by the PB's windowevent() (signaling the LALT), and not the one who follows too (the one signaling RALT).


Even using GetAsyncKeyState() doesn't work, because it seem to believe too the LCTRL is actually pushed (even if it's a fake one), so I cannot use it to check it.

I don't see a solution.
"Have you tried turning it off and on again ?"
A little PureBasic review
User avatar
luis
Addict
Addict
Posts: 3893
Joined: Wed Aug 31, 2005 11:09 pm
Location: Italy

Re: PB's keyboard library and "problematic" keys

Post by luis »

Unless I use the unsupported EventlParam() / EventWParam() and reverse the logic of my lib.
First I call WindowEvent() and THEN do my checkings for WM_KEYDOWN/UP WM_SYSKEYDOWN/UP events.

The bad of this solution is:

1) I must use unsupported commands.

2) I can have access to only lParam\wParam instead of the full MSG structure. Could be limiting and source of more problems going ahead (for example I cannot access the "time" field).
"Have you tried turning it off and on again ?"
A little PureBasic review
User avatar
luis
Addict
Addict
Posts: 3893
Joined: Wed Aug 31, 2005 11:09 pm
Location: Italy

Re: PB's keyboard library and "problematic" keys

Post by luis »

AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAH!

Found THE solution.

The sweet sequence to accomplish all:

1) I do a PeekMessage() to know if there is something in the message queue else exit with 0 events

2) I save the result of WindoEvent() in a var

3) At this point WindowEvent() already called a GetMessage() so the message I'm about to examine is actually removed from the queue

4) I do my magics with the MSG structure I saved at the point 1). That MSG is the same MSG retrieved by WindowEvent() with GetMessage() so I have access to all the fields.

5) If I find a LCTRL I can do a PeekMessage() to see if the next message is signaling a #VK_MENU (the ALT key). Now I can do the PeekMessage() to spy onto the next message because the previous one has been removed. I check if the signaled ALT has the same timestamp of the LCTRL I'm currently processing. If true, that's a fake LCTRL and I return 0 events.
In any other case, the LCTRL is legit.

6) I process, store, convert any other non problematic key for my use

7) I exit from my sgl_Event() returning the var saved at point 2)

8 ) I rejoice

The original questions are still valid though :)
"Have you tried turning it off and on again ?"
A little PureBasic review
User avatar
idle
Always Here
Always Here
Posts: 5836
Joined: Fri Sep 21, 2007 5:52 am
Location: New Zealand

Re: PB's keyboard library and "problematic" keys

Post by idle »

glad you got it sorted, sorry I wasn't paying attention to the thread didn't check email all weekend.

How did you test for the Alt or control key?

This works fine on my system!

Code: Select all


Procedure WindowCallback(hwnd,msg,wparam,lparam)

result = #PB_ProcessPureBasicEvents

Select msg 
    Case #WM_SYSKEYDOWN
      If GetAsyncKeyState_(#VK_RMENU) & $8000 
        Debug "right alt"
      ElseIf  GetAsyncKeyState_(#VK_LMENU) & $8000  
        Debug "left alt" 
         
      EndIf 
    Case #WM_KEYDOWN
       If GetAsyncKeyState_(#VK_LCONTROL) & $8000
         Debug "left control"
       ElseIf GetAsyncKeyState_(#VK_RCONTROL) & $8000
         Debug "right control" 
         
       EndIf 
EndSelect

ProcedureReturn result 

EndProcedure 

OpenWindow(0,10,10,600,400,"KEYB")
  SetWindowCallback(@WindowCallback(),0)
  
  ButtonGadget(1, 450,10, 100, 30, "keyb")
   
  If InitSprite() And InitKeyboard() And OpenWindowedScreen(WindowID(0),0,0,400,300,0,0,0)
    Paused = #False
    Repeat
      iEvent = WindowEvent()
      FlipBuffers()

      If StartDrawing(ScreenOutput())

        ExamineKeyboard()
        If KeyboardReleased(#PB_Key_F9) ; all ok
        ; If KeyboardReleased(#PB_Key_F10) ; press f10 and see what happen, then try f10 and down arrow to show the system menu
        ; If KeyboardReleased(#PB_Key_LeftControl) ; press right alt instead !
        ; If KeyboardReleased(#PB_Key_LeftAlt) ; problem similar to F10
       
          If Paused = #False
            Paused = #True
          Else
            Paused = #False
          EndIf
        EndIf

        DrawingMode(0)

        If Paused = #False
          DrawText(20, 20, "Program is running...")
        Else
          DrawText(20, 20, "Program paused...    ")
        EndIf

        StopDrawing()
      EndIf
    Until KeyboardPushed(#PB_Key_Escape) Or iEvent = #PB_Event_CloseWindow
  EndIf

User avatar
luis
Addict
Addict
Posts: 3893
Joined: Wed Aug 31, 2005 11:09 pm
Location: Italy

Re: PB's keyboard library and "problematic" keys

Post by luis »

idle wrote: How did you test for the Alt or control key?
Expressed in words, see point 5) in my previous post, translated to code see excerpt below:

Code: Select all

   
    Case #VK_CONTROL
        ;  extended key (right key) ?
         If lParam & $01000000 
            iRetCode = #SGL_KEY_RCONTROL
         Else
            iRetCode = #SGL_KEY_LCONTROL
            
            ; ALTR_GR sends LCTRL, then ALT
            iTimeStamp = GetMessageTime_()
    
            If PeekMessage_(@NextMSG, *WinMsg\hWnd, 0, 0, #PM_NOREMOVE)
                If NextMSG\message = #WM_KEYDOWN Or NextMSG\message = #WM_SYSKEYDOWN Or NextMSG\message = #WM_KEYUP Or NextMSG\message = #WM_SYSKEYUP
                    If NextMSG\wParam = #VK_MENU ; ALT
                        If NextMSG\time = iTimeStamp ; generated at the same time !
                            iRetCode = 0 ; it was a fake one
                        EndIf
                    EndIf
                EndIf            
            EndIf                                
         EndIf  
idle wrote: This works fine on my system!
On mine does not, it says "left control" when I press the right alt. The reason is the one discussed above, the ALT_GR "thing" and the fact GetAsyncKeyState() didn't help :wink:
"Have you tried turning it off and on again ?"
A little PureBasic review
User avatar
luis
Addict
Addict
Posts: 3893
Joined: Wed Aug 31, 2005 11:09 pm
Location: Italy

Re: PB's keyboard library and "problematic" keys

Post by luis »

BTW using the WM_ message is nicer also because you don't lose keys, they are queued...

if you try to add a delay() in the loop of your test program you'll likely end up missing keypresses... :)


edited a typo 4 years later... :shock:
Last edited by luis on Sat Feb 07, 2015 7:23 pm, edited 1 time in total.
"Have you tried turning it off and on again ?"
A little PureBasic review
User avatar
idle
Always Here
Always Here
Posts: 5836
Joined: Fri Sep 21, 2007 5:52 am
Location: New Zealand

Re: PB's keyboard library and "problematic" keys

Post by idle »

Ok interesting, the behavior seems to be based on the keyboard language setting, I'm assuming that if the language has accented chars then the right alt is going to produce a crtl+alt, Though I would have thought you could catch it in the #WM_SYSKEYDOWN
User avatar
idle
Always Here
Always Here
Posts: 5836
Joined: Fri Sep 21, 2007 5:52 am
Location: New Zealand

Re: PB's keyboard library and "problematic" keys

Post by idle »

A random thought, just load the US layout for the process, though I guess it depends on what keys you need to map and the keyboard type.

Code: Select all

   keyhandle = LoadKeyboardLayout_(@"00000409",$00000001) 
  If keyhandle 
     Debug ActivateKeyboardLayout_(keyhandle,$00000100)
  EndIf
User avatar
luis
Addict
Addict
Posts: 3893
Joined: Wed Aug 31, 2005 11:09 pm
Location: Italy

Re: PB's keyboard library and "problematic" keys

Post by luis »

idle wrote:A random thought, just load the US layout for the process
Hi idle, thank you for the suggestion !

Yes, it is something I was already considering but only as an option to be specified by the library's user.

It's ok if you only need to catch specific keypresses, but not if you are for example entering some text, in that case all the WM_CHAR messages would be wrong and the user would be pissed off in seeing his keyboard mapping changed!

So it can definitely have some uses and I probably put an option for it, but the lib must work with the default mapping without problems.

It shall have the option to work with simple chars (using the current layout for entering text), polling for specific keypresses or combinations, register for callbacks on keypress and work with both virtual keys and scan codes (for layout-independent mapping).

BTW, the library will be an OpenGL library to make tech demos/simple games with PB.

It's still in the very early stage, but my idea is to do this for myself as usual as a learning experience/fun and probably then to share it with all PB users, if it will be some interest in this. Anyway, I'm just started it, so for now I simply negate I just said that. :)
"Have you tried turning it off and on again ?"
A little PureBasic review
User avatar
Rescator
Addict
Addict
Posts: 1769
Joined: Sat Feb 19, 2005 5:05 pm
Location: Norway

Re: PB's keyboard library and "problematic" keys

Post by Rescator »

If you plan to make a keyboard lib/include for games then maybe you should take a look at:
GetKeyboardState which "Copies the status of the 256 virtual keys to the specified buffer."

That way you could theoretically support the ability for the user to press every single key at the same time. (not technically possible on any keyboard I've ever heard about yet)


Additionally you might want to use MapVirtualKeyEx (translates virtual key to scan code) and GetKeyNameText (translate scancode to textual name).
That way the config screen could show: Alt Fire= "Shift" + "Ctrl" when the user sets their preferred keys.

These API functions and more cool stuff are found here: http://msdn.microsoft.com/en-us/library ... 85%29.aspx
User avatar
luis
Addict
Addict
Posts: 3893
Joined: Wed Aug 31, 2005 11:09 pm
Location: Italy

Re: PB's keyboard library and "problematic" keys

Post by luis »

Rescator wrote:If you plan to make a keyboard lib/include for games then maybe you should take a look at:
GetKeyboardState which "Copies the status of the 256 virtual keys to the specified buffer."

That way you could theoretically support the ability for the user to press every single key at the same time. (not technically possible on any keyboard I've ever heard about yet)
Yep, I know that one. But I keep already two arrays (one for virtual codes and one for scancodes) in my lib with a flag on/off to be able to detect multiple keypress, and do some other nice things :)
I populate them using the WM_KEY* WM_SYSKEY* messages. It's lighter and you don't miss keys.
Rescator wrote: Additionally you might want to use MapVirtualKeyEx (translates virtual key to scan code)
Yep, I know that one but at the moment I don't need it, since I keep already that kind of info.
Rescator wrote: and GetKeyNameText (translate scancode to textual name).
Yep, I know that one too but for now I'm going to map that internally, for some reason I don't remember I was not satisfied with that (maybe something to do with some differentiation between left/right with some specific key). I keep that api in mind, anyway.

Thanks for all the suggestions and I appreciate them, but I have already looked at all the keyboard related api's quite thoroughly (I hope) :)
"Have you tried turning it off and on again ?"
A little PureBasic review
User avatar
Rescator
Addict
Addict
Posts: 1769
Joined: Sat Feb 19, 2005 5:05 pm
Location: Norway

Re: PB's keyboard library and "problematic" keys

Post by Rescator »

Hey Luis you might find this interesting. (I kinda ended up messing around a little with the keyboard apis.

It's a lot simpler, you only need the single array. (storing scan codes make no sense as someone with two keyboards that hit the same key may generate different scancodes, but they will generate the same VK's).

Unfortunately one still need to add a little kludge code to handle Alt Gr + a character (PS! If your Alt Gr ever breaks then you can press Ctrl & Alt + a character instead),
there is no need to do anything special when it's pressed down, it's only when it's released that you need too ensure the key array Ctrl is set to 0 as well..
I guess one sneaky way would be to always set Ctrl to 0 when Alt is also released. It is very rare for someone to press Ctrl and Alt at the same time and still wanting to keep Ctrl pressed afterwards.
An amusing thing wit the example below,. as it's a windowed app the Alt is stolen by the menu so it's unlikely Ctrl + Alt would ever be used normally, thus in the example one "could" assume that any Alt is actually an Alt Gr. (you know this Luis but others might not, that the Alt key is considered a System Command key, amusingly enough the Windows keys still get reported correctly, I'm not sure if to blame MicroSoft or the hardware makers for this mess, or maybe both)

Obviously this isn't the only "quirk" with keyboards. On mine GetKeyNameText has major issues dealing with Pause/Break and PrtScr/SysRq, and the media buttons (like play, mute etc.) ends up as D and so on. The VK however is still correct so one could use the volume key in a game, though I would NOT recommend that as people might wish to be able to adjust the system volume and mute etc. as intended)

Code: Select all

EnableExplicit

#MAPVK_VK_TO_VSC=0
Procedure.s VirtualKeyToName(vk.l)
	Protected sc.i,text$,gkntl.i
	sc=MapVirtualKey_(vk,#MAPVK_VK_TO_VSC)
	If sc
		text$=Space(255)
		GetKeyNameText_(sc<<16,@text$,Len(text$)+1) ;Just an example of how to get the key name to display to the user.
	EndIf
	ProcedureReturn Trim(text$)
EndProcedure

Global Dim keys.b(254) ;0-255, the range is actually 1-254, it's just easier to map this way.
;Obviously a lot of these keys are not really usefull, and some are not actual keys at all but input info.
;For more please see http://msdn.microsoft.com/en-us/library/dd375731%28v=VS.85%29.aspx

Procedure.i WindowCallback(hwnd.i,uMsg.l,wParam.i,lParam.i)
	Protected result=#PB_ProcessPureBasicEvents,sc.i,text$,gkntl.i

	Select uMsg
		Case #WM_KEYDOWN
			If Not (lParam&$40000000) ;Only count first press not repeats.
				keys(wParam)=#True ;set VK table to true for this key, later you can check keys() to see which keys are pressed or not.
				Debug "$"+Rset(Hex(wParam),2,"0")+" = "+VirtualKeyToName(wParam)
			EndIf
		Case #WM_KEYUP
			If (lParam&$40000000) ;Only count release if previously pressed.
				keys(wParam)=#False
				Debug "$"+Rset(Hex(wParam),2,"0")+" = "+VirtualKeyToName(wParam)+" (up)"
			EndIf
	EndSelect

	ProcedureReturn result
EndProcedure

Define Event.i,Quit.i
If OpenWindow(0, 100, 200, 195, 260, "PureBasic Window", #PB_Window_SystemMenu | #PB_Window_MinimizeGadget | #PB_Window_MaximizeGadget)
	SetWindowCallback(@WindowCallback(),0)
	Repeat
		Event = WaitWindowEvent()
		If Event = #PB_Event_CloseWindow
			Quit = 1
		EndIf
	Until Quit = 1
EndIf

End
It's a real shame there is no Scan code to Virtual Key api as that would make it easier to erm "scan" a keyboard/driver and find out all the VK's that keyboard support/exposes.
Then again, the easiest way to configure is simply a list of actions in the game/program and default to safe common VK's (for example VK_HELP does not exist on my keyboard), then let the user actually press the keys they wish to use if they want to re-assign any. In that respect the simple way I did it should be enough (a small kludge still need to be added to handle "Alt Gr"'s odd behavior though (I'm surprised there isn't a"VK_AltGR" as it's not exactly a "new" key). *laughs*
User avatar
Rescator
Addict
Addict
Posts: 1769
Joined: Sat Feb 19, 2005 5:05 pm
Location: Norway

Re: PB's keyboard library and "problematic" keys

Post by Rescator »

Just for completeness sake, here is the source again, but this time wit the "kludge" to ensure that Ctrl is not virtually "stuck" when you release the AltGr key.
(unfortunately this also means that pressing Ctrl then Alt then releasing Alt will also magically release Ctrl, even if you are still pressing it, but that is the lesser evil I guess compared to say AltGr making Ctrl stuck causing you to cause friendly fire *laughs*)

Code: Select all

EnableExplicit

#MAPVK_VK_TO_VSC=0
Procedure.s VirtualKeyToName(vk.l)
	Protected sc.i,text$,gkntl.i
	sc=MapVirtualKey_(vk,#MAPVK_VK_TO_VSC)
	If sc
		text$=Space(255)
		GetKeyNameText_(sc<<16,@text$,Len(text$)+1) ;Just an example of how to get the key name to display to the user.
	EndIf
	ProcedureReturn Trim(text$)
EndProcedure

Global Dim keys.b(254) ;0-255, the range is actually 1-254, it's just easier to map this way.
;Obviously a lot of these keys are not really usefull, and some are not actual keys at all but input info.
;For more please see http://msdn.microsoft.com/en-us/library/dd375731%28v=VS.85%29.aspx

Procedure.i WindowCallback(hwnd.i,uMsg.l,wParam.i,lParam.i)
	Protected result=#PB_ProcessPureBasicEvents,sc.i,text$,gkntl.i

	Select uMsg
		Case #WM_KEYDOWN
			If Not (lParam&$40000000) ;Only count first press not repeats.
				keys(wParam)=#True ;set VK table to true for this key, later you can check keys() to see which keys are pressed or not.
				Debug "$"+Rset(Hex(wParam),2,"0")+" = "+VirtualKeyToName(wParam)
			EndIf
		Case #WM_KEYUP
			If (lParam&$40000000) ;Only count release if previously pressed.
				keys(wParam)=#False
 				If wParam=#VK_MENU And keys(#VK_CONTROL)
 					keys(#VK_CONTROL)=#False
 				EndIf
				Debug "$"+Rset(Hex(wParam),2,"0")+" = "+VirtualKeyToName(wParam)+" (up)"
			EndIf
	EndSelect

	ProcedureReturn result
EndProcedure

Define Event.i,Quit.i
If OpenWindow(0, 100, 200, 195, 260, "PureBasic Window", #PB_Window_SystemMenu | #PB_Window_MinimizeGadget | #PB_Window_MaximizeGadget)
	SetWindowCallback(@WindowCallback(),0)
	Repeat
		Event = WaitWindowEvent()
		If Event = #PB_Event_CloseWindow
			Quit = 1
		EndIf
	Until Quit = 1
EndIf
End
Post Reply