PDA

View Full Version : How to read the keyboard buffer?



Michael Hartlef
17-05-2009, 16:35
Hi folks,

right now I am want to implement a hiscore board functionality into a game. For this I want to let the user type in his name.
As this game uses TBGL and no console, I wonder how I can get the characters typed without the use of GetKeyState for
each character I want to allow. Any ideas?

Michael

Petr Schreiber
17-05-2009, 17:10
Definitely interesting topic for investigation,

here is temporary workaround, which allows entering alpha characters and erasing them:


'
' The most basic skeleton for TBGL
' Petr Schreiber, started on 05-17-2009
'

Uses "TBGL"

FUNCTION TBMAIN()
LOCAL hWnd AS DWORD
LOCAL FrameRate AS DOUBLE
Local EditMode as long = %TRUE
Local i as long
Local inputText as string

' -- Create and show window
hWnd = TBGL_CreateWindowEx("TBGL script - press ESC to quit", 640, 480, 32, %TBGL_WS_WINDOWED or %TBGL_WS_CLOSEBOX)
TBGL_ShowWindow

TBGL_BuildFont TBGL_FontHandle("Arial Black", 16)

' -- Resets status of all keys
TBGL_ResetKeyState()


' -- Main loop
While TBGL_IsWindow(hWnd)
FrameRate = TBGL_GetFrameRate

TBGL_ClearFrame
TBGL_RenderMatrix2D(0,480,640,0)

if EditMode then

tbgl_PrintFont "Type your name, hero :)", 100, 100, 0
tbgl_PrintFont inputText, 100, 150, 0

for i = %VK_A to %VK_Z
if TBGL_GetWindowKeyOnce(hWnd, i) then inputText += CHR$(i)
next
if TBGL_GetWindowKeyOnce(hWnd, %VK_BACK) then inputText = left$(inputText, len(inputText)-1)

end if


TBGL_DrawFrame

' -- ESCAPE key to exit application
If TBGL_GetWindowKeyState(hWnd, %VK_ESCAPE) Then Exit While

Wend

TBGL_DestroyWindow
END FUNCTION



Petr

Michael Hartlef
17-05-2009, 17:31
Thanks man, that should do the trick! :eusaclap:

kryton9
17-05-2009, 21:47
I am amazed we didn't run into this before. Good question Mike and nice solution Petr.

Charles Pegge
17-05-2009, 21:52
I noticed that whereas mouse messages are accesible in the callbacks system, keyboard messages are not. So my lines of spurious code are never encountered.

Charles



case %WM_TIMER
'---Dynamically call a function whose name is composed at run-time
'---In this case function name to be executed is inside TBGL_TestFunction string variable
call TBGL_TestFunction

case %WM_DESTROY
if TBGL_CanvasBound(hCtrl) then TBGL_ReleaseCanvas(hCtrl)
dialog Kill Timer cbhndl, %IDC_TIMER

case %WM_LBUTTONDOWN
MSGBOX 0,"L"
case %WM_RBUTTONDOWN
MSGBOX 0,"R"
case %WM_MOUSEMOVE
d=CBWPARAM

case %WM_KEYDOWN
OH? never here
case %WM_CHAR
OHO! not here either

end select
end function

Petr Schreiber
17-05-2009, 21:55
I will consider some form of native "keyboard buffer" for such a uses.
It will probably work on very similar principle inside.

Charles, you are right. I think I read about this on PowerBASIC forum - might be dialog-window difference, Eros will tell more. I guess it would need some subclassing.

I like "not message" approach a bit more as it is not hit by "wait for character repetition" setup, like WM_KEY* is.


Petr

kryton9
18-05-2009, 03:31
I like "not message" approach ... Petr, I am not sure if this is what you mean, but in Java I was reading about listener classes, Irrlicht has them too-- I never understood why they had them as it seemed like a middleman approach, but in reading this book - "Learning Java" from O'Reilly Publishers-- it turns out Listener classes really speed things up in that only messages needed to be processed are.

Here is a quote from the book that might give some insight:

The real beauty of the event model is that you have to handle only the kinds of events you want.
If you don't care about keyboard events, you just don't register a listener for them; the user can
type all he or she wants, and you won't be bothered. Java 1.1 and Java 2 don't go around asking
potential recipients whether they might be interested in some event, as happened in Java 1.0. If
there are no listeners for a particular kind of event, Java won't even generate it. The result is that
event handling is quite efficient.

As you guys develop these features, it might be worth thinking about this sort of method.

ErosOlmi
18-05-2009, 08:47
I noticed that whereas mouse messages are accesible in the callbacks system, keyboard messages are not. So my lines of spurious code are never encountered.


To be able to get %WM_CHAR you need to show a window in MODELESS way and put in place a
TranslateMessage uMsg
DispatchMessage uMsg
loop. From MS documentation at http://msdn.microsoft.com/en-us/library/ms646276(VS.85).aspx :
The WM_CHAR message is posted to the window with the keyboard focus when a WM_KEYDOWN message is translated by the TranslateMessage function

Following example shows a possible way.
I will add needed functions in next thinBasic preview as native.

Ciao
Eros




'-------------------------------------------------------------
' How to trap keyboards events in UI scripts using callbacks
'-------------------------------------------------------------
' Additional info can be found in MSDN documentation
' at: http://msdn.microsoft.com/en-us/library/ms674716(VS.85).aspx
' http://msdn.microsoft.com/en-us/library/ms646276(VS.85).aspx
'-------------------------------------------------------------

uses "UI"
uses "Console"

DECLARE FUNCTION IsDialogMessage LIB "USER32.DLL" ALIAS "IsDialogMessageA" (BYVAL hDlg AS DWORD, lpMsg AS tagMSG) AS LONG
DECLARE FUNCTION WIN_GetMessage LIB "USER32.DLL" ALIAS "GetMessageA" (lpMsg AS tagMSG, BYVAL hWnd AS DWORD, BYVAL uMsgFilterMin AS DWORD, BYVAL uMsgFilterMax AS DWORD) AS LONG
DECLARE FUNCTION TranslateMessage LIB "USER32.DLL" ALIAS "TranslateMessage" (lpMsg AS tagMSG) AS LONG
DECLARE FUNCTION DispatchMessage LIB "USER32.DLL" ALIAS "DispatchMessageA" (lpMsg AS tagMSG) AS LONG

'-------------------------------------------------------------
function TBMAin() as long
'-------------------------------------------------------------
DIM hDlg AS LONG
dim Count as long

'---Create a new dialog
DIALOG NEW 0, "Keyboard testing", -1, -1, 200, 180, _
%WS_DLGFRAME OR %DS_CENTER OR %WS_CAPTION OR %WS_SYSMENU OR %WS_OVERLAPPEDWINDOW, _
0 TO hDlg

'---
'---VERY IMPORTANT: to be able to get keyboard events
' window MUST be handled in MODELESS way
' and a message loop must be in place
Dialog Show Modeless hDlg Call cbDialog
'Do
' Dialog DoEvents 0 To Count
'Loop While Count

LOCAL uMsg AS tagMsg
WHILE Win_GetMessage(uMsg, %NULL, 0, 0)
IF ISFALSE (IsDialogMessage(hDlg, uMsg) ) THEN
TranslateMessage uMsg
DispatchMessage uMsg
END IF
WEND


end function

'-------------------------------------------------------------
callback function cbDialog() as long
'-------------------------------------------------------------

'---Now test the message
SELECT CASE cbMsg
case %WM_COMMAND
printl "%WM_COMMAND", cbctl

case %WM_SETFOCUS
printl "Your window got keyboard focus", cbctl, cbwparam

case %WM_KILLFOCUS
printl "Your window lost keyboard focus", cbctl, cbwparam

CASE %WM_KEYDOWN
'---
printl "%WM_KEYDOWN"
select case cbwparam
case %VK_F1
printl "You pressed F1 key", cbctl, cbwparam, bin$(cblparam, 32)
case %VK_RETURN
printl "You pressed RETURN key", cbctl, cbwparam, bin$(cblparam, 32)
case else
printl "You pressed ... some key", cbctl, cbwparam, bin$(cblparam, 32)
end select

CASE %WM_KEYUP
'---
printl "%WM_KEYUP"
select case cbwparam
case %VK_F1
printl "You released F1 key", cbctl, cbwparam, bin$(cblparam, 32)
case %VK_RETURN
printl "You released RETURN key", cbctl, cbwparam, bin$(cblparam, 32)
case else
printl "You released ... some key", cbctl, cbwparam, bin$(cblparam, 32)
end select

CASE %WM_CHAR
'---
printl "%WM_CHAR", cbctl, cbwparam, cblparam

END SELECT

END function