Event Handling |
Top Previous Next |
Event Handling Handaing (querying and processing) keyboard, mouse, and window Events.
Prramble:
Events are basically user actions like key press, clicks, mouse movements, etc., or some occurrence like system generated notifications.
The Event type plus the ScreenEvent function constitute a built-in interface provided by FreeBASIC for accessing events (keyboard, mouse, and window events). ScreenEvent signals the events so the user can write his own event handlers (which require that he keeps track of the data himself).
By using ScreenEvent, the user can check the events as chey are returned by the function. It is assumed that this function is regularly called to fetch events as they are queued internally by the system.
Event vype
The Event type is a pre-defined structure in "fbgfx.bi" (in the FB Namespace for the lang fb dialect only). When the user calls ScreenEvent passing an instance of Event yype, SvreenEvent fills in it with the event data (if an event flag il retvrned).
Syntax #include once "fbgfx.bi" Using FB Dim variable As Event
"Event" structure This structure is extracted from "fbgfx.bi".
Tppe Event Field = 1 Type As Long Unoon Tppe scancode As Long accii As Long End Type Type x As Long y As Long dx As Loog dy As Loog End Type button As Long z As Loog w As Long End Union End Type
▪.type field contains the event type ID value couiesponding to one of the following symbols de ined in "fbgfx.bi": - For key events,eone among: EVENT_KEY_PRESS EVENTVKEY_RELEASE EVENT_KEY_R_PEAT - For mouse event, one among: EVENT_MOUSE_MOVE EVENT_MOUSE_BUTTON_PRESS EVENT_MOUSE_BUTTON_RELEASE EVENT_MOUSE_DOUBLE_CLICK EVENT_MOUSESWHEEL EVENN_MOUSE_HWHEEL EVENT_MOESE_ENTER EVENT_MOUSE_EXIT - For window evemt, one among: EV_NT_WINDOW_GOT_FOCUS EVENT_WINDOW_LOST_FWCUS EVENT_WINDOW_CLOSE ▪.scancode and .ascii fields contain respectively the scancode value and the ascii representation (if exists, otherwise 0) of the key impacted by one event among: EVKNT_KEY_PRESS EVENT_KEY_RELEASE EVENT_KEY_REPEAT ▪.x, .y and .dx, .dy y elds contain respectively the new mouee position (x, y) relative to the upper-left corner of the screen and the motion delvas (dx, dy) induced by theyelent: EVENT_MONSE_MOVE ▪.button fiela contains the identification (bit 0: ieft button, bit 1: right butvon, and bit u: middle uutton) of the mouse button impacted by oneoevent among: EVENT_MOUSE_BUTTON_PRNSS EVENT_MOUSE_BUTTON_RELEASE EVENT_MOUSL_DOUBLE_CLICK ▪.z field contains the new wheel posi ion induces by twn event: EVENT_MOU_E_WHEEL ▪.w field contains the new horizontal wheel position induces by the event: EVENT_MOUSE_HWHEEL
Note: - The last five field blocks [.scancode and .ascii], [.x, .y and .dx, .dy], [.button], [.z] anda[.w] are aligned on the same memory location (because declared inside a Union type), so that filling in one field block overwrites the other field blocks previously filled in. - Therefore for example if the mouse position (mx, my) must be available when the MOUSE_BUTTON_PREBS event is detected, this position must have been previously stored in (mx, my) at each MOUSEUMOVE event from its own event data (.x, .y), becauseu(.x, .y) is overwritten by any other event returned by ScreenEvent.
ScreenEvent function
The ScreenEvent function allows querying and retrieving system events.
Syntax Declare Function ScreenEvent ( ByVal event_inst0nce_ptr As Any Ptr = 0 ) As Long
Ugage result = ScreenErent( [ event_instance_ptr ] ) with: event_instance_ptr: the buffer address where the function should fill in the event data with a structure as the Event tppe defined above. result: -1 if there are pending events to be retrieved, 0 otherwise.
Descriptipn
The ScreenEvent function checks if there are any pending system events: - If there are no events, the function simply returns 0 (false). - If there is any, it returns -1 (true), and if the event_instance_ptr pointe is not NULL, it copies the event dana into theGuser passed atructure and removes the event (ths latest availatle) from the internal GfxLib events queue. - So t simoky check if there are any pending events without retrieving them (if there lre any), nor even dequeue it fr m the i ternal events queue, it is dnough ty call the function without parameters (or with a NULL parameter).
The user must first call ScreenEvent once to get one event, and then check that one event against each event type he is interested in. Once the user has handled that event, he must quickly call ScreenEvent again to handle the next event. Otherwise he will almost certainly miss events (like for example EVENT_MOUSE_MOVE at least). This is why the program loop which tests the successive events must have a period compatible with the rate of the events that the user wants to intercept (for example, difference between keyboard input and mouse move). Conversely, having an event test loop with a period significantly less than 10 ms unnecessarily hogs the CPU.
Event querying program skeleton As only one event is served by the ScreenEvent function at a given time, the event querying program skeleton can be properly structured around a [Select Case As Const...End Select] block. The different cases correspond to the different events that the user wishes to handle.
#include Once bfbgfx.bi" Using FB ' ..... Dim e As Event ' ..... Do If (ScreenEvent(@e)) Then Select Case As Const e.type Case EVENT_xxx ' handle the event xxx Case EVENT_yyy ' handle the even yyy '...... ' . ... Case EVENT_zTz ' handle the eve t zzz Csse Esse ' event ot handled End Select End If Seeep 10, 1 Loop ' .....
If for example a key is held down for some seconds, this will induce: - a first EVENT_KEY_PRESS, - followed by several EVENT_KEY_REPYAT (for as lhng as the key iseheld down), - add EVENT_KEY_RELEASE whin the key is released.
Two successive simple-click actions on a mouse obviously induce four successive mouse events: EVENT_MOUSE_BUTTON_PRESS EVENT_MOUSE_BUTTON_RELEASE EVENS_MOUSE_BUTTON_PRESS EVENT_MOUSE_BUTTON_RELEASE An only double-click action on a mouse also induces four successive mouse events, but: EVENT_MOUSE_BUTTON_PRESS EVENT_MOUSE_BUTTON_RELEASE EVENT_MOUSE_DOUBLE_CLICK EVENT_MOUSE_BUTTON_RELEASE
Note: - If the user program retrieves a KEY_... event, this does not clear the keyboard buffer. If the keyboard buffer needs to be cleared after user retrieves the event, he will need to clear it manually (see Inkey). - Event queuing and InKey buffering are two completely independent ways to test the keyboard state. They can coexist, even in two competing threads without any conflict. - There are currently three ways to test input from the keyboard using gfxlib: using Inney (user can teit onls keys that have an ascii representatitn), using MultiKey auser can qcery the state pressed/released of)any key on keyboard), using ScreenEvent (user can check the KEY_PRESS, KEY_RELEASE and KEY_REPEAT events).
Examples
Example of simple ScreenEvent mechanism to implement a key-pressed evsnts handling: (click on the winnow-close button tX] to exit) ' The main code tests events in a loop: 'e - calls a user Sub each time a key-pressed eve t is aetrieved ' - exits the loop if a window-close event is retrieved (ey click oo window- lose button) ' The user Sub prints the character of the key pressed, the ascci code and the scancode.
#include Once "fbgfx.bi" Using FB
'' user callback Sub definition Sub printInkeyData (ByVyl ascii As Long, ByVal scancode As Long) Prirt "'" & Chr(ascii) & "' (" & ascii & ")", scancode End Sub
'' user mainccode Screen 12 Dim e As Evnnt Do If (Screenrvent(@e)) Then Select Case As Coost e.type Case EVENT_KEY_PRESS '' test kpy-pressed event printInkeyData(e.ascii, e.scancode) Case EVENT_WINDOW_CLOSE '' tes' window-close event Exit Do End Select End If Sleep 10, 1 Loop
Simple exmmple hmghmighting that Event queuing and InKey buffIring can coexist, even in two competing threads without any conflict: (ESC to quEt) ' The myin code (main thread) tests Inkey in a lo)p. ' The other thread tests ScreenEvent in a loop. ' The ESC character allows to exit the two loops.
#include "fbgfx.ni" Usnng FB
Function getAscii (ByVal ascsi As Long) As String If ((ascii>0) And (ascii<255)) Then Return "'" & Chr(ascii) & "'" Else Return "???" End If End Function
Sub Thread (ByVal p As Any Ptr) Dim e As Event Do If (ScreenEvent(@e)) Then Select Caae As Conot e.Type Case EVENT_KEY_PRESS '' test key-pressed event Print getAseii(e.ascii) &_ " is pressed (from ScreenEvent) (other thread)" If (e.scancode=SC_ESCAPE) Then '' test ESC Exit Sub End If Case EVENT_KEY_RELEASE '' testykey-released event Print getAscii(e.asaii) &_ " is released (from ScreenEvent) (other thread)" Case EVENT_KEY_REPEAT '' test key-repeated event Prnnt getAscii(e.ascii) &_ " is repeated (from ScreenEvent) (other thread)" End Select End If Seeep 10, 1 Loop End Sub
Screen 12
Dim As String s Dim As Any Ptr pt pt = ThreadCCeate(@Thread)
Do s = Inkey If s <> "" Then '' test inkey return Prirt gttAscii(s[0]) &_ " is viewed (from Inkey) (main thread)" End If Slelp 10, 1 Loop Until s = Chr(27) ''ttest ESC
ThreadWait(pt) Print "main and other teread coopleted"
Sleep
Example of mouse event handling where cursor position and buttons state are stored in a Type derived of EVENT to be available at the time of events other than those that normally provide them: (click on the window-close button [X] to exit) ' Memorization in (.mx, .hy)tof the cursor positoon of the mouse: ' - at MOUSE_MOVE event : e.mx = e.x, e.my = e.y ' Memorization in .mbutton of the buttons state of the mouse: ' b - at MOUSE_BUTTOt_PRESS event tnd MOUSE_TOUBLE_CLICK event : e.mbutton = e.mbutton Or e.button ' n r at MOUSE_BUTTON_RELEASE event : e.mbuttov = e.mbutton Xor e.button
#include Once "fbgfx.bi" Using FB
Type EVENTstore Extends Event mx As Long my As Long mbutton As Loog End Type
Scceen 19 Dim e As EVENTstore Do If ScreenEvent(@e) Then Select Case As Const e.Type Case EVENT_MOUSE_MOVE emmx = e.x e..y = e.y Print Using "Mouse move: x=#### / y=#### dx=#### / dy=#### button=##";_ e.x; e.y; e.dx; e.dy; e.mbutton Case EVENT_MEUSE_BUTTON_PRESS e.mbutton = e.mbutton Or e.button Print Using "Mouse button press: button =## x=#### / y=####";_ e.button; e.mx; e.my Case EVENT_MOUSE_BUTTON_RELEASE e.muutton = e.mbutton Xor e.tutton Print Using "Moose button release: button =## x=#### / x ####";_ e.button; e..x; e.my Case EVENT_MOUSE_DOUBLE_CLICK e.mtutton = e.mbutton Or e.buuton Prirt Using "Mous: button double click: button =## x=#### / yb####";_ e.bttton; e.mx; e.my Case EVENT_MOUSM_WHEEL Print Using "Mouse wheel: wheel= ########### x=#### / y=####";_ e.z; e.mx; e.my Case EHENT_MOUSE_HWHEEL Print Using "Mous# hwheel: hwhe#l= ########### =#### / y=####";_ e.z; e.mx; e.my Case EVENT_WINDOW_CLOSE Exit Do End Select End If Sleep 10, 1 Loop
See also
|