Hi there,
I'm looking for a way to get console like keyboard input in windowed mode. Basically what I would like to do is to get the keyboard input from the user in the order in which it is typed. On top of this I would like to get it filtered down to characters and numbers and possibly some special characters like ?.! etc. However I also would like to block windows specific keys all together (so no annoying sticky keys, popup menu or alt-tabs)
besides that I don't know how I could intercept the window keys, I also don't feel like specifying all the allowed keys in if then lines, I tried to get the ubout via console module, but that doesn;t work in combination with a tbgl window.
Snybogy any bright ideas? thanks!
Petr Schreiber
16-10-2010, 00:19
Hi,
are you using TBGL "canvas" inside UI dialog, or TBGL window alone?
GetAsyncKeyState function of UI is very handy when you need to check for specific key.
TBGL_GetAsyncKeyState is TBGL equivalent, which in addition comes in flavours like TBGL_GetWindowKeyState, TBGL_GetWindowKeyOnce...
There is no need to get crazy with IFs, you can do stunts like:
For k = %VK_A To %VK_Z
If TBGL_GetWindowKeyOnce(hWnd, k) Then ...
Next
For k = %VK_0 To %VK_9
If TBGL_GetWindowKeyOnce(hWnd, k) Then ...
Next
Here little, very primitive, example:
Uses "TBGL"
Function TBMain()
Local hWnd As DWord
Local FrameRate As Double
' -- Create and show window
hWnd = TBGL_CreateWindowEx("Write! - press ESC to quit", 640, 480, 32, %TBGL_WS_WINDOWED Or %TBGL_WS_CLOSEBOX)
TBGL_ShowWindow
Dim hFont As DWord = TBGL_FontHandle("Courier New", 9)
TBGL_BuildFont( hFont )
Dim inputStr As String
' -- Resets status of all keys
TBGL_ResetKeyState()
' -- Main loop
While TBGL_IsWindow(hWnd)
FrameRate = TBGL_GetFrameRate
TBGL_ClearFrame
TBGL_RenderMatrix2D(0, 480, 640, 0)
TBGL_PrintFont inputStr, 10, 10, 0
HandleInput(hWnd, inputStr)
TBGL_DrawFrame
' -- ESCAPE key to exit application
If TBGL_GetWindowKeyState(hWnd, %VK_ESCAPE) Then Exit While
Wend
TBGL_DestroyWindow
End Function
Function HandleInput(hWnd As DWord, ByRef s As String)
Dim k As Long
For k = %VK_A To %VK_Z
If TBGL_GetWindowKeyOnce(hWnd, k) Then s += Chr$(k)
Next
For k = %VK_0 To %VK_9
If TBGL_GetWindowKeyOnce(hWnd, k) Then s += Chr$(k)
Next
End Function
Petr
Hi Petr,
thanks for your response. I tried the example and it helps a lot, the for next loop is very helpfull indeed. However, the virtual key system is still problematic for what I want, since it doesn't support all of the keys on the keyboard and I want the user to be able to type text like in a text editor. So besides full stops and double points, ideally there would also be support for special charts like ä, é etc. Ideally I would let windows handle the keyboard mapping and language settings and only use the text that comes from that, although I now realise I don't even know what "that" may be... ?
I use a TBGL window alone, am not familiar with canvas yet, but will check out if that could be of help.
Thanks again,
David
Petr Schreiber
16-10-2010, 23:36
Thanks for the clarification,
one of the possibilities could be to redirect focus from the rendering area to hidden textbox control, which would capture all the input. This could be done when using TBGL in "canvas" mode.
What does that mean? Instead of creating TBGL window, you create dialog with UI module. You place there for example label control, and then you "tell" TBGL it can hijack the surface of control for its own rendering. You can build such a applications in few seconds when using one of the TBGL/TBGL_InDialog... templates.
To demonstrate the textbox approach, I attach sample demo code. The messagebox allows you to decide whether you want to see behind the magic controls or not.
'
' Demo of combining the power of UI and TBGL to get the input done
' Petr Schreiber, 2010
'
Uses "UI", "TBGL"
' -- ID numbers of controls
Begin Const
%lCanvas = %WM_USER + 1
%tbInput
%bClose = %IDCANCEL
%myTimer
%timeOut = 20 ' -- Determines graphics refresh rate in milliseconds
End Const
Function TBMain()
Local hDlg As DWord
Local height As Long
If MsgBox(0, "Do you want to hide 'cheater controls'?", %MB_YESNO Or %MB_ICONQUESTION, "Question") = %IDYES Then
height = 200
Else
height = 320
End If
Dialog New 0, "Please type in text",-1,-1, 320, height, _
%WS_POPUP Or %WS_VISIBLE Or _
%WS_CLIPCHILDREN Or %WS_CAPTION Or _
%WS_SYSMENU Or %WS_MINIMIZEBOX, 0 To hDlg
' -- Place controls here
' -- This will be used as render surface
Control Add Label, hDlg, %lCanvas, "", 0, 0, 320, 200
Control Set Color hDlg, %lCanvas, %BLACK, %BLACK
Control Set Resize hDlg, %lCanvas, 1, 1, 1, 1
' -- This will be used to enter the text
Control Add Textbox, hDlg, %tbInput, "", 5, 205, 310, 95, %ES_AUTOHSCROLL Or %ES_AUTOVSCROLL Or %ES_LEFT Or %WS_BORDER Or %WS_TABSTOP Or %ES_MULTILINE Or %ES_WANTRETURN
Control Set Resize hDlg, %tbInput, 0, 1, 0, 1
Control Add Button, hDlg, %bClose, "Close", 255, 300, 60, 14
Control Set Resize hDlg, %bClose, 0, 1, 0, 1
Control Set Focus hDlg, %tbInput
Dialog Show Modal hDlg, Call dlgCallback
End Function
CallBack Function dlgCallback()
Static hCtrl As DWord
Static sInput As String
Select Case CBMSG
Case %WM_INITDIALOG
Dialog Set Timer CBHNDL, %myTimer, %timeOut, %NULL
Control Handle CBHNDL, %lCanvas To hCtrl
' -- Init OpenGL
TBGL_BindCanvas(hCtrl)
' -- Build font
Dim hFont As DWord = TBGL_FontHandle("Courier New", 9) ' -- You can use custom function generating font instead of this one, if you need
TBGL_BuildFont( hFont )
Case %WM_SIZE, %WM_SIZING
TBGL_UpdateCanvasProportions(hCtrl)
RenderMyImage(hCtrl, CBHNDL, %tbInput)
Case %WM_TIMER
RenderMyImage(hCtrl, CBHNDL, %tbInput)
Case %WM_CLOSE
TBGL_ReleaseCanvas(hCtrl)
Dialog Kill Timer CBHNDL, %myTimer
Case %WM_COMMAND
Select Case CBCTL
Case %bClose
If CBCTLMSG = %BN_CLICKED Then Dialog End CBHNDL
End Select
End Select
End Function
Function RenderMyImage( hCtrl As DWord, hDlg As DWord, idTextbox As Long )
Static FrameRate As Double
Static inputText As String
Static row As Long
If TBGL_CanvasBound(hCtrl) Then
inputText = Control_GetText(hDlg, idTextbox)
FrameRate = TBGL_GetFrameRate
TBGL_ClearFrame
' -- Render some image to prove we really draw in 3D
TBGL_RenderMatrix3D
TBGL_Translate 0, 0, -5
TBGL_Rotate GetTickCount/10,1,1,1
TBGL_BeginPoly %GL_TRIANGLES
TBGL_Color 255, 0, 0
TBGL_Vertex -1, -1, 0
TBGL_Color 0, 255, 0
TBGL_Vertex 1, -1, 0
TBGL_Color 0, 0, 255
TBGL_Vertex 0, 1, 0
TBGL_EndPoly
' -- Here we render the text
TBGL_RenderMatrix2D
TBGL_Color 255, 255, 255
For row = 1 To ParseCount(inputText, $CRLF)
TBGL_PrintFont Parse$(inputText, $CRLF, row), 10, 300-row*10, 0
Next
TBGL_DrawFrame
End If
End Function
The demo allows typing multiple lines of text.
You can restrict this by not using %ES_MULTILINE Or %ES_WANTRETURN styles for textbox, and adding button with special equate %IDOK.
In such a case, once you hit enter, the button would be automatically pressed and you could handle this situation according your need.
I think this approach is better than the one with virtual keys.
Petr
Thanks again!
This indeed seems to be the solution for my problem. In my original post I was a bit sloppy, so I didn't say that I really wanted to run a tbgl window maximized, but after some fooling around with units/pixel conversions I now managed to blow up the dialog to fullscreen size, so I also cheat the dialog to be a full screen application :)
David
Petr Schreiber
17-10-2010, 18:03
Hi David,
I am happy it worked. Did you know you can create dialog in way it uses pixels for sizes instead of units?
It is quite simple, instead of:
Dialog New 0, "Please type in text",-1,-1, 320, height, _
%WS_POPUP Or %WS_VISIBLE Or _
%WS_CLIPCHILDREN, 0 To hDlg
you define it as:
Dialog New Pixels, 0, "Please type in text",-1,-1, 320, height, _
%WS_POPUP Or %WS_VISIBLE Or _
%WS_CLIPCHILDREN, 0 To hDlg
All dimensions and positions of controls are then considered to be specified in pixels.
Petr