Event Handling

Top  Previous  Next

Event Handling

fblogo_mini

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

 

Event

ScneenEvent

Inkey

MultiKey

GetMouse

Keybsard scancodes