Part VI
Adding Keyboard Control



    In most cases, you need to have a grid function respond to both mouse and keyboard events. For instance, if the user's computer does not have a mouse, or the user cannot physically use a mouse, then they should be able to use the program by strictly using the keyboard.

    We will add keyboard event support by using the arrow keys and the PgUp, PgDn, and Shift keys. The arrow keys will move the currently selected date one day/week forwards or backwards. The PgUp/PgDn keys will select the next/previous month. And finally, the Shift-PgUp/Shift-PgDn combinations will select the next/previous year.

Responding to #TextEvent Messages
     In order for our grid function to be able to respond to keyboard text events created by our day PressButton grids, we need to set up a SUB for this message. In SUB Initialize we must first add the following line:

Sub[#TextEvent] = SUBADDRESS(TextEvent)

This will register our TextEvent Subroutine address with the array of messages for our grid.

Set Keyboard Focus Kid Grid
    Unless we set the keyboard focus to the currently selected  day PressButton kid grids,  we won't receive any textevent callbacks. So, in  SUB HighlightCurrentDay we add:

 XuiSetKeyboardFocusGrid (grid, #SetKeyboardFocusGrid, 0, 0, 0, 0, curDayGrid, 0 )

where the kid argument curDayGrid is set to our currently selected day grid.

    In the SUB Initialize, I now can comment out or delete the line which sets the starting focusKid as the  $MonthLeftArrowPressB (month left arrow press button).

' XuiSetGridTypeProperty (gridType, @"focusKid", $MonthLeftArrowPressB)

Add our SUB TextEvent
    Now we can add our SUB TextEvent to handle all of our keyboard events. This part is actually quite easy since we can make use of the current subroutines which handle selecting days, months, and years.

SUB TextEvent
'PRINT "text event", "v2="; v2, " r0="; r0
 IF r0 < $Day1 || r0 > $Day42 THEN EXIT SUB

'capture shift+PgUp or shift+PgDn for next year, previous year selection
 IF v2 AND $$ShiftBit THEN
  SELECT CASE v2{$$VirtualKey}
   CASE $$KeyPageUp   : r0 = $YearLeftArrowPressB
                        GOSUB Selection

   CASE $$KeyPageDown : r0 = $YearRightArrowPressB
                        GOSUB Selection
  END SELECT
 ELSE
'User arrows to select day, PgUp for previous month, PgDn for next month
  SELECT CASE v2{$$VirtualKey}
   CASE $$KeyDownArrow : IF r0 < $Day36 THEN
                           r0 = r0 + 7
                           GOSUB DaySelection
                         END IF

   CASE $$KeyUpArrow   : IF r0 > $Day7 THEN
                          r0 = r0 - 7
                          GOSUB DaySelection
                         END IF

   CASE $$KeyRightArrow: INC r0
                         IF r0 > $Day42 THEN
                           r0 = $Day42
                           EXIT SUB
                         ELSE
                           GOSUB DaySelection
                         END IF

   CASE $$KeyLeftArrow : DEC r0
                         IF r0 < $Day1 THEN
                           r0 = $Day1
                           EXIT SUB
                         ELSE
                          GOSUB DaySelection
                         END IF

   CASE $$KeyPageUp    : r0 = $MonthLeftArrowPressB
                         GOSUB Selection

   CASE $$KeyPageDown  : r0 = $MonthRightArrowPressB
                         GOSUB Selection

  END SELECT
 END IF
END SUB

SUB TextEvent Discussion - state v2 and  kid r0
    There are two SELECT CASE statements in this subroutine. The first one checks whether the user has pressed the Shift key and then handles the PgUp or PgDn key events. If the Shift key has not been pressed, then the second SELECT CASE statement takes care of all of the arrow key events and the normal PgUp/PgDn key events.

    You should also note that a text event callback provides the kid grid that sent the callback in r0 and the keyboard state in argument v2.

    In addition, we are mostly interested in looking at two just two parts of the state argument v2, the Virtual Key Code in Bits 24-31 and the Shift Key Bit 16. From the docs you see them defined as:

state (v2)
state contains the state of the keyboard when the keyboard event was detected, and reflects the new state of the keyboard.
Bit 24 - 31 : Virtual Key Code
Bit 16 = 1  : Shift key was down when the keyboard event occured.

Using Brace Notation to extract bit fields
    Xbasic provides a way to extract any bit from a 32 bit integer variable using Brace Notation {}. The first argument inside the braces is the number of bits to be extracted. The second argument is the starting bit to begin the extraction. So, to extract the Virtual Key Code from v2 we want to extract 8 bits starting with bit number 24.

vkc = v2{8,24}        '8 bits  24-31

    Fortunately, there are Virtual Key Code constants that can be used instead of trying to remember bit positions and lengths. The Graphics Library Instant Help file shows these Virtual Key Code constants for every keyboard key. It also has a constant for extracting the correct Virtual Key bitfield from v2:

 $$VirtualKey = BITFIELD (8,24)

Thus we can get our virtual key code more simply using:

vkc = v2{VirtualKey}

We then can compare the value from the Virtual Key Code against various key code constants to see which key event occurred.  Below are listed the Key constants used in our SELECT CASE statement:

$$KeyDownArrow
$$KeyUpArrow
$$KeyRightArrow
$$KeyLeftArrow
$$KeyPageUpArrow
$$KeyPageDownArrow

    Thus, by using Brace Notation and Key Code Constants, we are able to capture any combination of user key events.  In addition, it makes it much easier to understand our code since we are using easily read and understood constants rather than numbers.  The current stage of our program is given in calendar5.x.

In Part VII...



    In our next installment we will take a look at Multiple Versions of the Truth.

Previous     Home   Next

(c) 2000  David SZAFRANSKI