In order for this site to work correctly, and for us to improve the site, we need to store a small file (called a cookie) on your computer.
By continuing to use this website, you agree to our cookies and privacy policy.
  
Home page Home page Home page Home page
Pixel
Pixel Header R1 C1 Pixel
Pixel Header R2 C1 Pixel
Pixel Header R3 C1 Pixel
Pixel

Version 3 Technical Highlights - Input.Char

The central system routine for keyboard input has been modified to be "mouse aware". It now returns additional codes permitting the user to know where the mouse was when a button was clicked, and what status line button has been pressed. Thus there are now five functions of Input.Char, 1 - to handle background processing/@Priority.Int etc. 2 - To return a pressed key. 3 - To provide the mouse position when a button is clicked. 4 - To identify the status line cell that has been clicked on. 5 - To permit clicking on the top screen line to display the menu. As 1 and 2 have not changed they will not be dealt with here.

Mouse Position

Input.Char now accepts a second additional parameter MousePosFlag. If this is set to true, then if a mouse button is clicked (regardless of which mouse button) a string of length four characters will be returned in the first parameter having the format Char(0) : Char(0) : Char(X) : Char(Y) where X and Y are the ascii values representing the X and Y position of the mouse respectively. Thus if the cursor was at 65, 10, the string returned would be Char(0) : Char(0) : Char(65) : Char(10).

Status Line Cells

To display custom "mouseable" buttons on the status line requires a knowledge of status record structures. All status line images are stored in the SYSTEXT table with a row key of Name*Status where Name is the name of the status line image and Status is the literal "Status", e.g. WINDOW*STATUS. In release 3.0 this record has five fields, each field being a dynamic array having a structure as follows

  < 1 >   Normally the name of the status line (Name above), although can be
          different if required.

  < 2 >   The information to display in each cell, value mark delimited.

  < 3 >   Format information for the dynamic section of cell 3.

  < 4 >   Reserved for compiled status line image.

  < 5 >   Array of start positions and lengths for active "mouseable" areas
          of the status line. This is a multivalue for each "mouseable"
          section of the status line. Each multivalue has two subvalues. The
          first being the start position of the area (note the relative
          position not the absolute position, thus the first character is 1
          not 0), and the second being the length. Thus to define a hot spot
          with 1 at the first character of the status line, a hot spot width
          10 in the middle of the status line, and a hot spot width one at
          the far right of the status line, field 5 would contain
          113510801

          Note that it is the job of the programmer to ensure that hot areas
          correspond to screen literals.

As many "hot areas" can be defined as are required by the application.

When a "hot area" is clicked on, Input.Char returns a string indicating which numbered hot area has been selected. This has a similar structure to the X/Y information but is only three bytes long, in this case Char(0) : Char(0) : Char(X) where X is the position in the "hot area" array. It is then the job of the programmer to act upon this information.

Note that due to the way in which this has been implemented (hot areas are not associated with code and commands, rather they just tell the calling program which area has been chosen) it is not possible to alter functionality of existing status lines. Hot area locations and legends may be changed, but choosing hot area 4 in a window will always display "Options " regardless of the legend/position. For reference there are 6 hot areas defined for the Window status line, as follows

     1    Browse previous
     2    Browse
     3    Browse next
     4    Options
     5    Softkeys
     6    Save

The following code shows the use of INPUT.CHAR in its modified form along with INRECT to provide a "Radio Button" window which takes as input a field mark delimited set of button names and displays a small window allowing the user to mouse to each button to toggle the button status, or tab and use the space bar to toggle status. Note that in the real world this would be rewritten using VSpace but space considerations preclude that here. Whilst it would be possible to achieve a similar result using hooks in the window processor this is shown as 3GL code merely to illustrate the use of the new routines and return values.


0001    Function Radio_Window(ButtonLabels)
0002    /*
0003      Author      AMcA, CC
0004      Date        Sept 92
0005      Purpose     To display a field mark delimited set of prompts with a
0006                  corresponding radio button for each prompt. These may be
0007                  toggled using mouse and/or tab/spacebar and will return a
0008                  dynamic array of results when <Save> is moused, or an empty
0009                  array if Esc or the close button are pressed.
0010    */
0011      Declare Function Min, Max, Esc.To.Attr, InRect
0012      Declare Subroutine Msg,Video.RW,Border.Up,Input.Char,Delay
0013      $Insert SysInclude, Logical
0014      Equ Escape$  to \1B\
0015      Equ Tab$     to \09\
0016      Equ BackTab$ to \000F\
0017      GoSub SetUp
0018      GoSub DisplayScreen
0019      GoSub ProcessMouse
0020    Return ResultArray
0021  
0022    SetUp:
0023      Colour4 = \1B\:'C1O'
0024      Colour1 = Esc.To.Attr(Colour4)
0025      ButtonCtr = Count(ButtonLabels, @Fm) + (ButtonLabels#"")
0026      ResultArray = str(0:@fm,ButtonCtr)
0027      ResultArray[-1,1] = ''
0028      Rectangles = ''
0029      MaxWidth = 6 ; Pos = 0 ; Mark = 0 ; Screen = ""
0030      Ptr = 2 ; Depth = ButtonCtr * 2
0031      Ypos = Int((@CrtHigh-(Depth+3))/2)
0032      ScreenTop = Ypos - 2
0033      OldYpos = Ypos
0034      Loop
0035       Remove NextLabel From ButtonLabels At Pos Setting Mark
0036       MaxWidth = Max(MaxWidth, Len(NextLabel))
0037       Screen := @(2, Ypos) : NextLabel
0038       Ypos += 2
0039      While Mark
0040      Repeat
0041      For X = 1 To ButtonCtr
0042       Screen := @(4 + MaxWidth, OldYpos) : "[ ]"
0043       ThisBox = Char(5 + MaxWidth) : Char(OldYpos)
0044       Rectangles := ThisBox:ThisBox
0045       OldYpos += 2
0046      Next
0047      BottomLine = '<Save>'
0048      Screen := @(2, Ypos) : BottomLine
0049      Rectangles := Char(3):Char(Ypos):Char(6):Char(Ypos)
0050      Rectangles :=Char(3):Char(ScreenTop):Char(3):Char(ScreenTop)
0051      OldYpos += 2
0052    Return
0053  
0054    DisplayScreen:
0055      Video.RW(1,ScreenTop,7+MaxWidth,OldYpos,'R', Image)
0056      Video.RW(1,ScreenTop,7+MaxWidth,OldYpos,'C',' ':Colour1)
0057      Border.Up(1,Screentop,7+MaxWidth,OldYpos,1,Colour4)
0058      Print @(2,ScreenTop):'[':@fm:']'
0059      Print Colour4:Screen
0060      CurrentButton = 1
0061      Print @(5 + MaxWidth, ScreenTop +2):
0062    Return
0063  
0064    ProcessMouse:
0065      ExitSet = False$
0066      Loop Until ExitSet
0067       Input.Char(Chr,True$)
0068       Begin Case
0069         Case Len(Chr) = 4
0070         * A Mouse Button was pressed - a slight delay is in order here !
0071            Delay(0.25)
0072            MouseX = Seq(Chr[3,1])
0073            MouseY = Seq(Chr[4,1])
0074            * Now see if the mouse press was somewhere we need to act on
0075            Rectangle = InRect(MouseX, MouseY, Rectangles, '')
0076    Begin Case
0077             Case Rectangle = ButtonCtr + 2
0078                * Border "Cancel" icon.
0079                ExitSet = True$
0080                Resultarray = ''
0081             Case Rectangle = ButtonCtr + 1
0082                * <Save> icon.
0083                ExitSet = True$
0084             Case Rectangle > 0
0085                If ResultArray<Rectangle> Then
0086                   ResultArray<Rectangle> = 0 ; Choice = ' '
0087                End Else
0088                   ResultArray<Rectangle> = 1 ; Choice = @fm
0089                End
0090                Print @(5+MaxWidth,ScreenTop+(Rectangle*2)):Choice
0091                Print @(5+MaxWidth,ScreenTop+(CurrentButton*2)):
0092            End Case
0093         Case Chr = Tab$
0094            CurrentButton += 1
0095            If CurrentButton > ButtonCtr then CurrentButton = 1
0096            Print @(5 + MaxWidth, ScreenTop + (CurrentButton*2)):
0097         Case Chr = BackTab$
0098            CurrentButton -= 1
0099            If CurrentButton < 1 then CurrentButton = ButtonCtr
0100            Print @(5 + MaxWidth, ScreenTop + (CurrentButton*2)):
0101         Case Chr = ' '
0102            If ResultArray<CurrentButton> then
0103             Choice = ' ' ; ResultArray<CurrentButton> = 0
0104            End Else
0105             Choice = @fm ; ResultArray<CurrentButton> = 1
0106            End
0107            Print @(5+MaxWidth,ScreenTop+(CurrentButton*2)):Choice
0108            Print @(5 + MaxWidth, ScreenTop + (CurrentButton*2)):
0109         Case Chr = Escape$
0110            ExitSet = True$ ; ResultArray = ''
0111       End Case
0112      Repeat
0113      Video.RW(1,ScreenTop,7+MaxWidth,OldYpos,'W',Image)
0114    Return

(Volume 4, Issue 5, Pages 7-10)
Pixel
Pixel Footer R1 C1 Pixel
Pixel
Pixel
Pixel