Getchar not reading arrows

BlitzMax Forums/BlitzMax Module Tweaks/Getchar not reading arrows

remz(Posted 2006) [#1]
I have managed a way to correctly catch special keys (i.e.: arrow, F1, etc.) in a way very similar to GetChar. The main benefit is that with this method, you get system keyboard repeat and a sequential key buffer! Great for several uses!

Background information on this topic:

KeyHit() is not particularly useful since it 'loses' key press order. Furthermore, it doesn't support key repeat. Its best use would be to catch simple things, like KEY_ESCAPE to quit.

KeyDown() is great for a game, because you detect the actual status of a key. No need for buffering or repeat here.

GetChar() is perfect for string input, because it supports localisation, uppercase and lowercase, backspace, etc. And it is buffered, and stored sequentially in the order the user pressed the keys. However, it does NOT record special keys! Let's say for example that you want to allow a player to enter his name. You would like to allow left and right arrow keys to move the cursor. This cursor movement should support key repeat, just like in any Mac or Windows gui application.

This is where this small bit of code comes to help. The function is called SpecialGetKey. Please note that it returns scancodes, not ascii codes. I have posted here in module tweak because this function could be added to polledinput very easily and I think would be appreciated.


Graphics 800,600,0

' Mimic the way 'GetChar' works:
Global charGet,charPut,charQueue[256]
AddHook EmitEventHook,KeyboardHook,Null,0


Function SpecialGetKey()
	If charGet=charPut Return 0
	Local n=charQueue[charGet & 255]
	charGet:+1
	Return n
End Function

While Not KeyHit(KEY_ESCAPE) And Not AppTerminate()
	Cls
	
	Local c2 = SpecialGetKey()
	If(c2 <> 0) Then DrawText "scancode "+c2, 100, 100
	
	Flip
	Delay(1)
Wend
End

Function KeyboardHook:Object( id,data:Object,context:Object )
	Local ev:TEvent=TEvent(data)
	If Not ev Return data

	' In this hook, we'll catch only KEYDOWN and KEYREPEAT events:
	' KEYDOWN occurs immediately when a key is pressed,
	' and KEYREPEAT occurs repeatedly if the key is held for a certain time.	
	If ev.id = EVENT_KEYDOWN Or ev.id = EVENT_KEYREPEAT Then
		If(ev.data < 256) Then
			If charPut-charGet<256
				charQueue[charPut & 255]=ev.data
				charPut:+1
			EndIf
		EndIf
	EndIf

	Return data
End Function