home *** CD-ROM | disk | FTP | other *** search
/ C++ Games Programming / CPPGAMES.ISO / fgl / fglight / manuals.arj / USER14.DOC < prev    next >
Text File  |  1995-02-06  |  74KB  |  1,528 lines

  1.  
  2.  
  3.  
  4.  
  5.  
  6. Chapter 14
  7.  
  8.  
  9.  
  10.  
  11.  
  12. Input Device Support                                                           
  13. 302   Fastgraph User's Guide
  14.  
  15.  
  16. Overview
  17.  
  18.      The selection of application input devices is an important part of
  19. designing a program for the IBM PC and PS/2 family of systems. The keyboard
  20. and mouse are the most popular, and in fact more and more applications,
  21. especially those that use a graphical interface, actually require a mouse to
  22. use the product. Another input device, primarily used in entertainment
  23. software, is the joystick. Although not as popular as the mouse, joysticks
  24. nevertheless can simplify the use of certain applications. Fastgraph provides
  25. support for these three types of input devices, and this chapter will discuss
  26. this in detail.
  27.  
  28.  
  29. Keyboard Support
  30.  
  31.      Fastgraph's keyboard support includes routines to read keystrokes, check
  32. the state of certain keys, and set the state of these keys. In addition,
  33. Fastgraph provides a low-level keyboard handler that replaces the BIOS
  34. keyboard handler to increase keyboard responsiveness. These routines are
  35. independent of the other parts of Fastgraph and thus do not require that you
  36. call fg_setmode. All keyboard-related routines work in text and graphics video
  37. modes.
  38.  
  39.      The IBM PC and PS/2 keyboards produce two types of character codes --
  40. standard codes and extended codes (extended codes are sometimes called
  41. auxiliary codes). The standard codes correspond to the 128 characters in the
  42. ASCII character set. In general, pressing keys on the main part of the
  43. keyboard, or on the numeric keypad with NumLock turned on, will generate a
  44. standard code. The 128 extended codes are specific to the IBM PC and PS/2
  45. keyboards. Some common keystrokes that produce extended codes are keys on the
  46. numeric keypad with NumLock turned off, the function keys, or pressing Alt
  47. with another key. The following tables show the standard and extended keyboard
  48. codes.
  49.  
  50.                        Table of standard keyboard codes
  51.  
  52.            key     code   key     code   key     code   key     code
  53.  
  54.            (none)    0    space    32    @        64    `        96
  55.            Ctrl+A    1    !        33    A        65    a        97
  56.            Ctrl+B    2    "        34    B        66    b        98
  57.            Ctrl+C    3    #        35    C        67    c        99
  58.            Ctrl+D    4    $        36    D        68    d       100
  59.            Ctrl+E    5    %        37    E        69    e       101
  60.            Ctrl+F    6    &        38    F        70    f       102
  61.            Ctrl+G    7    '        39    G        71    g       103
  62.            Ctrl+H    8    (        40    H        72    h       104
  63.            Ctrl+I    9    )        41    I        73    i       105
  64.            Ctrl+J   10    *        42    J        74    j       106
  65.            Ctrl+K   11    +        43    K        75    k       107
  66.            Ctrl+L   12    ,        44    L        76    l       108
  67.            Ctrl+M   13    -        45    M        77    m       109
  68.            Ctrl+N   14    .        46    N        78    n       110
  69.            Ctrl+O   15    /        47    O        79    o       111
  70.            Ctrl+P   16    0        48    P        80    p       112            
  71.                                        Chapter 14:  Input Device Support   303
  72.  
  73.            Ctrl+Q   17    1        49    Q        81    q       113
  74.            Ctrl+R   18    2        50    R        82    r       114
  75.            Ctrl+S   19    3        51    S        83    s       115
  76.            Ctrl+T   20    4        52    T        84    t       116
  77.            Ctrl+U   21    5        53    U        85    u       117
  78.            Ctrl+V   22    6        54    V        86    v       118
  79.            Ctrl+W   23    7        55    W        87    w       119
  80.            Ctrl+X   24    8        56    X        88    x       120
  81.            Ctrl+Y   25    9        57    Y        89    y       121
  82.            Ctrl+Z   26    :        58    Z        90    z       122
  83.            Ctrl+[   27    ;        59    [        91    {       123
  84.            Ctrl+\   28    <        60    \        92    |       124
  85.            Ctrl+]   29    =        61    ]        93    }       125
  86.            Ctrl+^   30    >        62    ^        94    ~       126
  87.            Ctrl+-   31    ?        63    _        95    Ctrl+BS 127
  88.  
  89.  
  90.                        Table of extended keyboard codes
  91.  
  92.               code        key
  93.  
  94.                3          Ctrl+@
  95.               15          Shift+Tab (back tab)
  96.               16-25       Alt+Q to Alt+P (top row of letters)
  97.               30-38       Alt+A to Alt+L (middle row of letters)
  98.               44-50       Alt+Z to Alt+M (bottom row of letters)
  99.               59-68       F1 to F10
  100.               71          Home
  101.               72          up arrow
  102.               73          PgUp
  103.               75          left arrow
  104.               77          right arrow
  105.               79          End
  106.               80          down arrow
  107.               81          PgDn
  108.               82          Ins
  109.               83          Del
  110.               84-93       Shift+F1 to Shift+F10
  111.               94-103      Ctrl+F1 to Ctrl+F10
  112.               104-113     Alt+F1 to Alt+F10
  113.               114         Ctrl+PrtSc
  114.               115         Ctrl+left arrow
  115.               116         Ctrl+right arrow
  116.               117         Ctrl+End
  117.               118         Ctrl+PgDn
  118.               119         Ctrl+Home
  119.               120-131     Alt+1 to Alt+= (top row of keys)
  120.               132         Ctrl+PgUp
  121.  
  122.  
  123. In addition, four keys generate the same standard codes as other control key
  124. combinations. These keys are:
  125.  
  126.                          key          same as   code
  127.  
  128.                          Backspace    Ctrl+H      8                            
  129. 304   Fastgraph User's Guide
  130.  
  131.                          Tab          Ctrl+I      9
  132.                          Enter        Ctrl+M     13
  133.                          Escape       Ctrl+[     27
  134.  
  135.      The CapsLock, NumLock, and ScrollLock keys do not generate a standard or
  136. extended code when pressed. Instead, they toggle between off and on states.
  137.  
  138.  
  139. Reading Keystrokes
  140.  
  141.      When you press a key or key combination, the standard or extended code
  142. representing that keystroke is stored in the ROM BIOS keyboard buffer. This
  143. buffer can hold up to 16 keystrokes and thus provides a type-ahead capability.
  144. Fastgraph includes three routines for reading keystroke information from the
  145. keyboard buffer. The fg_getkey routine reads the next item in the keyboard
  146. buffer if one is available (that is, if a key has been pressed). If the
  147. keyboard buffer is empty (meaning no key has been pressed), fg_getkey waits
  148. for a keystroke and then reports information about it. Another routine,
  149. fg_intkey, reads the next keystroke from the keyboard buffer if one is
  150. available. If the keyboard buffer is empty, fg_intkey immediately returns and
  151. reports this condition. The fg_intkey routine is useful when a program must
  152. continue performing a task until a key is pressed. We've already seen the
  153. third routine, fg_waitkey, which flushes the keyboard buffer and then waits
  154. for another keystroke. Unlike fg_getkey and fg_intkey, fg_waitkey does not
  155. return any keystroke information. It is most useful in "press any key to
  156. continue" situations.
  157.  
  158.      Both fg_getkey and fg_intkey require two one-byte arguments passed by
  159. reference. If the keystroke is represented by a standard keyboard code,
  160. fg_getkey and fg_intkey return its code in the first argument and set the
  161. second argument to zero. Similarly, if the keystroke generates an extended
  162. code, the routines return its code in the second argument and set the first
  163. argument to zero. If fg_intkey detects an empty keyboard buffer, it sets both
  164. arguments to zero.
  165.  
  166.      Example 14-1 is a simple program that uses fg_getkey. It solicits
  167. keystrokes and then displays the two values returned by fg_getkey, one of
  168. which will always be zero. The variable key receives the key's standard code,
  169. while aux receives its extended code. Note that fg_initpm and fg_getkey are
  170. the only Fastgraph routines in the program; this can be done because the
  171. keyboard support routines are logically independent from the rest of
  172. Fastgraph. The program returns to DOS when you press the Escape key.
  173.  
  174.                                  Example 14-1.
  175.  
  176.                 #include <fastgraf.h>
  177.                 #include <stdio.h>
  178.                 void main(void);
  179.  
  180.                 #define ESC 27
  181.  
  182.                 void main()
  183.                 {
  184.                    unsigned char key, aux;
  185.  
  186.                    fg_initpm();                                                
  187.                                        Chapter 14:  Input Device Support   305
  188.  
  189.                    do {
  190.                       fg_getkey(&key,&aux);
  191.                       printf("key = %3d  aux = %3d\n",key,aux);
  192.                       }
  193.                    while (key != ESC);
  194.                 }
  195.  
  196.  
  197.      Example 14-2 reads keystrokes using fg_intkey at half-second intervals
  198. (18.2 fg_waitfor units equal one second). As in the previous example, the
  199. program displays the standard and extended codes for each keystroke. However,
  200. example 14-2 will continuously execute the while loop even if no keystrokes
  201. are available, in which case the key and aux values will both be zero. The
  202. program returns to DOS when you press the Escape key.
  203.  
  204.                                  Example 14-2.
  205.  
  206.                 #include <fastgraf.h>
  207.                 #include <stdio.h>
  208.                 void main(void);
  209.  
  210.                 #define ESC 27
  211.  
  212.                 void main()
  213.                 {
  214.                    unsigned char key, aux;
  215.  
  216.                    fg_initpm();
  217.                    do {
  218.                       fg_waitfor(9);
  219.                       fg_intkey(&key,&aux);
  220.                       printf("key = %3d  aux = %3d\n",key,aux);
  221.                       }
  222.                    while (key != ESC);
  223.                 }
  224.  
  225.  
  226.      When you use fg_intkey in a "tight" loop that does little else, you
  227. should force a small delay within the loop by calling fg_waitfor as in example
  228. 14-2. Typically a delay of one or two clock ticks is enough. Without this
  229. delay, the BIOS may not be able to handle all keyboard activity, and thus some
  230. keystrokes may not be available to your program.
  231.  
  232.  
  233. Testing and Setting Key States
  234.  
  235.      As mentioned earlier, the CapsLock, NumLock, and ScrollLock keys do not
  236. generate a standard or extended code when pressed but instead toggle between
  237. off and on states. Fastgraph includes routines for checking the state of these
  238. keys, as well as setting the state of the CapsLock and NumLock keys.
  239.  
  240.      The Fastgraph routines fg_capslock, fg_numlock, and fg_scrlock
  241. respectively read the state of the CapsLock, NumLock, and ScrollLock keys.
  242. Each routine has no arguments and returns the key state as its function value.
  243. A return value of 0 means the associated key is in the off state, while 1      
  244. 306   Fastgraph User's Guide
  245.  
  246. indicates the key is in the on state. If the keyboard does not have a
  247. ScrollLock key, fg_scrlock considers the key off and returns a value of zero.
  248.  
  249.      Example 14-3 is a simple program that uses fg_capslock, fg_numlock, and
  250. fg_scrlock to print messages describing the current state of these three keys.
  251.  
  252.                                  Example 14-3.
  253.  
  254.                      #include <fastgraf.h>
  255.                      #include <stdio.h>
  256.                      void main(void);
  257.  
  258.                      void main()
  259.                      {
  260.                         fg_initpm();
  261.                         if (fg_capslock())
  262.                            printf("CapsLock is on.\n");
  263.                         else
  264.                            printf("CapsLock is off.\n");
  265.  
  266.                         if (fg_numlock())
  267.                            printf("NumLock is on.\n");
  268.                         else
  269.                            printf("NumLock is off.\n");
  270.  
  271.                         if (fg_scrlock())
  272.                            printf("ScrollLock is on.\n");
  273.                         else
  274.                            printf("ScrollLock is off.\n");
  275.                      }
  276.  
  277.  
  278.      You also can set the state of the CapsLock and NumLock keys within a
  279. program. Fastgraph includes two routines, fg_setcaps and fg_setnum, for this
  280. purpose. Each routine requires an integer argument that specifies the new key
  281. state. If the argument value is 0, the key will be turned off; if the value is
  282. 1, the key will be turned on. Example 14-4 uses fg_setcaps and fg_setnum to
  283. turn off CapsLock and NumLock.
  284.  
  285.                                  Example 14-4.
  286.  
  287.                              #include <fastgraf.h>
  288.                              void main(void);
  289.  
  290.                              void main()
  291.                              {
  292.                                 fg_initpm();
  293.                                 fg_setcaps(0);
  294.                                 fg_setnum(0);
  295.                              }
  296.  
  297.  
  298.      On most keyboards, changing key states with fg_setcaps or fg_setnum also
  299. will change the keyboard state light to reflect the new key state. However,
  300. some older keyboards, especially when used on PC, PC/XT, or Tandy 1000         
  301.                                        Chapter 14:  Input Device Support   307
  302.  
  303. systems, do not update the state light. This makes the state light
  304. inconsistent with the true key state.
  305.  
  306.  
  307. Low-Level Keyboard Handler
  308.  
  309.      Fastgraph includes a low-level keyboard handler that replaces the BIOS
  310. keyboard handler. The replacement handler intercepts keystrokes ahead of the
  311. BIOS and thus eliminates the annoying beep that sounds upon filling the BIOS
  312. keyboard buffer. Fastgraph's keyboard handler is especially well-suited to
  313. game development because it increases keyboard responsiveness in high-speed
  314. action games. However, when the low-level keyboard handler is enabled, it is
  315. not possible to use fg_getkey, fg_intkey, fg_waitkey, or any third party
  316. functions that use BIOS or DOS services for keyboard activity. For this
  317. reason, a program that enables the low-level keyboard handler must disable it
  318. before exiting to DOS.
  319.  
  320.      The low-level keyboard handler can be enabled and disabled at any time.
  321. The fg_kbinit routine is provided for this purpose. To enable Fastgraph's low-
  322. level keyboard handler, pass the value 1 to fg_kbinit. To disable Fastgraph's
  323. handler and re-enable the BIOS keyboard handler, pass the value zero. No harm
  324. is caused if you try to enable Fastgraph's keyboard handler when it is already
  325. active, or if you try to disable it when the BIOS handler is active.
  326.  
  327.      When the low-level keyboard handler is enabled, you can use fg_kbtest to
  328. check if keys are currently pressed or released. This routine provides the
  329. only mechanism for accessing the keyboard when the low-level handler is
  330. enabled. It specifies the keys through scan codes. If the corresponding key is
  331. pressed, fg_kbtest returns 1. If it is released, the routine returns zero. The
  332. fg_kbtest routine can test if any key is pressed if you pass it the value 0
  333. instead of a specific scan code. The following table lists the scan codes
  334. corresponding to the keys on a standard PC keyboard.
  335.  
  336.                               Table of scan codes
  337.  
  338.                    scan           scan           scan           scan
  339.            key     code   key     code   key     code   key     code
  340.  
  341.            Esc       1    I        23    X        45    F9       67
  342.            1         2    O        24    C        46    F10      68
  343.            2         3    P        25    V        47    NumLock  69
  344.            3         4    [        26    B        48    ScrLock  70
  345.            4         5    ]        27    N        49    Home     71
  346.            5         6    Enter    28    M        50    Up arrow 72
  347.            6         7    Ctrl     29    ,        51    PgUp     73
  348.            7         8    A        30    .        52    KP-      74
  349.            8         9    S        31    /        53    L arrow  75
  350.            9        10    D        32    R shift  54    KP5      76
  351.            0        11    F        33    KP*      55    R arrow  77
  352.            -        12    G        34    Alt      56    KP+      78
  353.            =        13    H        35    Space    57    End      79
  354.            BS       14    J        36    CapsLock 58    Dn arrow 80
  355.            Tab      15    K        37    F1       59    PgDn     81
  356.            Q        16    L        38    F2       60    Ins      82
  357.            W        17    ;        39    F3       61    Del      83
  358.            E        18    '        40    F4       62    (unused) 84            
  359. 308   Fastgraph User's Guide
  360.  
  361.            R        19    `        41    F5       63    (unused) 85
  362.            T        20    L shift  42    F6       64    (unused) 86
  363.            Y        21    \        43    F7       65    F11      87
  364.            U        22    Z        44    F8       66    F12      88
  365.  
  366.  
  367.      There are actually more scan codes defined for PC keyboards than listed
  368. in this table. Such scan codes are generated when a key is pressed as a
  369. combination of one or more keys, such as when the shift and slash keys are
  370. pressed together to produce a question mark (?) character. Fastgraph's low-
  371. level keyboard handler is designed to report the pressing or releasing of keys
  372. themselves, as opposed to reporting the actual characters so produced. It is
  373. thus not possible for the keyboard handler to report the scan code for a
  374. multi-key character. If needed, such characters can be identified by the scan
  375. codes generated for each key in the sequence. For example, a question mark
  376. character would be reported as a forward slash (scan code 53) generated while
  377. pressing the left shift (42) or right shift (54) keys.
  378.  
  379.      Example 14-5 illustrates the use of Fastgraph's low-level keyboard
  380. handler. It first uses fg_kbinit to enable Fastgraph's keyboard handler and
  381. displays a message stating this. Then, at approximately one second intervals,
  382. the program calls fg_kbtest to check which of the four arrow keys are pressed
  383. and displays an appropriate message. Pressing Escape restores the BIOS
  384. keyboard handler and exits to DOS.
  385.  
  386.                                  Example 14-5.
  387.  
  388.                 #include <fastgraf.h>
  389.                 #include <stdio.h>
  390.                 void main(void);
  391.  
  392.                 #define ESC    1
  393.                 #define LEFT  75
  394.                 #define RIGHT 77
  395.                 #define UP    72
  396.                 #define DOWN  80
  397.  
  398.                 void main()
  399.                 {
  400.                    fg_initpm();
  401.                    fg_kbinit(1);
  402.                    printf("Keyboard handler enabled.\n");
  403.  
  404.                    do {
  405.                       printf("keys pressed:  ");
  406.                       if (fg_kbtest(LEFT))   printf("Left ");
  407.                       if (fg_kbtest(RIGHT))  printf("Right ");
  408.                       if (fg_kbtest(UP))     printf("Up ");
  409.                       if (fg_kbtest(DOWN))   printf("Down ");
  410.                       printf("\n");
  411.                       fg_waitfor(18);
  412.                    } while (fg_kbtest(ESC) == 0);
  413.  
  414.                    fg_kbinit(0);
  415.                    printf("Keyboard handler disabled.\n");
  416.                 }                                                              
  417.                                        Chapter 14:  Input Device Support   309
  418.  
  419.  
  420.  
  421.      Fastgraph includes two other routines for the low-level keyboard handler.
  422. The fg_kblast function returns the scan code for the most recent keypress
  423. processed by the low-level keyboard handler. If there have been no key presses
  424. since calling fg_kbinit, the return value will be zero. The fg_kbreset routine
  425. resets the state of Fastgraph's low-level keyboard handler to what it was
  426. after being initialized with fg_kbinit(1). This has the effect of "flushing"
  427. the keyboard handler. Neither of these two functions has any arguments.
  428.  
  429.  
  430. Mouse Support
  431.  
  432.      The mouse is a very popular input and pointing device, especially in
  433. graphically-oriented programs. Fastgraph contains several routines to support
  434. mice. These routines perform such tasks as mouse initialization, controlling
  435. and defining the mouse cursor, and reporting information about the mouse
  436. position and button status.
  437.  
  438.      The underlying software that controls the mouse is called the mouse
  439. driver. Fastgraph's mouse support routines provide a high-level interface to
  440. this driver. The Microsoft Mouse and its accompanying mouse driver have become
  441. an industry standard, and other manufacturers of mice have also made their
  442. mouse drivers Microsoft compatible. For this reason, the Fastgraph mouse
  443. support routines assume you are using a Microsoft or compatible mouse driver.
  444.  
  445.      Unfortunately, not all mouse drivers are created equal. That is, some
  446. drivers are not Microsoft compatible, even though they may be advertised as
  447. such. In some cases, these incompatibilities are rather trivial, but others
  448. are significant. For example, early versions of some third party mouse drivers
  449. had real problems in the EGA graphics modes. The Microsoft mouse driver, the
  450. Logitech mouse driver (version 3.2 or above), and the DFI mouse driver
  451. (version 3.00 or above) are known to work well with Fastgraph's mouse support
  452. routines. Any other Microsoft compatible mouse driver also should work
  453. properly.
  454.  
  455.  
  456. Initializing the Mouse
  457.  
  458.      There are two steps required to use Fastgraph's mouse support routines
  459. within an application program. First, you must install the mouse driver. This
  460. is done before running the application, typically by entering the command
  461. MOUSE at the DOS command prompt. Second, you must use Fastgraph's fg_mouseini
  462. function to initialize the mouse within the program.
  463.  
  464.      The fg_mouseini function has no arguments and returns a "success or
  465. failure" indicator as its function value. If the return value is -1, it means
  466. fg_mouseini could not initialize the mouse (either because the mouse driver is
  467. not installed, or the driver is installed but the mouse is physically
  468. disconnected). The return value will also be -1 if fg_mouseini is called when
  469. a virtual buffer is active. If fg_mouseini returns a positive integer value,
  470. the mouse initialization was successful. The value itself indicates the number
  471. of buttons (either 2 or 3) on the mouse. If you don't call fg_mouseini, or if  
  472. 310   Fastgraph User's Guide
  473.  
  474. fg_mouseini can't initialize the mouse, none of Fastgraph's other mouse
  475. support routines will have any effect.3
  476.  
  477.      Example 14-6 illustrates how to initialize the mouse. Unlike the keyboard
  478. support routines, Fastgraph's mouse support routines require that fg_setmode
  479. be called first. In this example, we simply pass fg_setmode the value -1 to
  480. initialize Fastgraph for whatever video mode is in effect when we run the
  481. program. The program then calls fg_mouseini and prints a message indicating
  482. whether or not the initialization was successful. If it was, the message
  483. includes the number of buttons on the mouse.
  484.  
  485.                                  Example 14-6.
  486.  
  487.                #include <fastgraf.h>
  488.                #include <stdio.h>
  489.                void main(void);
  490.  
  491.                void main()
  492.                {
  493.                   int status;
  494.  
  495.                   fg_initpm();
  496.                   fg_setmode(-1);
  497.                   status = fg_mouseini();
  498.  
  499.                   if (status < 0)
  500.                      printf("Mouse not available.\n");
  501.                   else
  502.                      printf("%d button mouse found.\n",status);
  503.                }
  504.  
  505.  
  506.      You should be aware that certain mouse drivers do not fully initialize
  507. the mouse when a program changes video modes. This problem most frequently
  508. occurs when you restore the original video mode at the end of a program that
  509. has called fg_mouseini. When changing video modes, you must first make the
  510. mouse cursor invisible (this is described in the next section), change the
  511. video mode, and then call fg_mouseini again to initialize the mouse for the
  512. new video mode.
  513.  
  514.  
  515. XVGA and SVGA Mouse Considerations
  516.  
  517.      Mouse drivers cannot directly display the mouse cursor in XVGA and SVGA
  518. graphics modes (modes 20 to 29). Hence, Fastgraph must display the mouse
  519. cursor through an interrupt handler that is activated whenever the mouse
  520. moves. The handler is automatically installed when you call fg_mouseini in
  521. modes 20 to 29.
  522.  
  523.  
  524. ____________________
  525.  
  526.    (3) If you use another mouse library or communicate directly with the mouse
  527. driver, you must still call fg_mouseini if your program runs in modes 13
  528. through 18. Otherwise, Fastgraph won't know that your program is using a mouse
  529. and may display graphics incorrectly.                                          
  530.                                        Chapter 14:  Input Device Support   311
  531.  
  532.      If you do not disable this handler before your program exits, it will
  533. remain "hooked" to the mouse driver. This will most likely hang your system
  534. the next time you try doing anything of consequence. The fg_mousefin routine
  535. removes Fastgraph's mouse interrupt handler from the mouse driver. In XVGA and
  536. SVGA graphics modes, you should call fg_mousefin just before restoring the
  537. original video mode, as shown here:
  538.  
  539.  
  540.                              fg_mousefin();
  541.                              fg_setmode(old_mode);
  542.                              fg_reset();
  543.  
  544.  
  545. Again, calling fg_mousefin is required only in XVGA and SVGA graphics modes.
  546. Calling it in other video modes is not applicable, though it causes no
  547. problems.
  548.  
  549.      In the standard VGA/MCGA 256-color mode (mode 19), white pixels in the
  550. mouse cursor are displayed in color 15. This is inconsistent with other
  551. graphics modes, where the mouse cursor's white pixels are displayed in the
  552. highest-numbered color value available in that mode. Fastgraph corrects this
  553. inconsistency in XVGA and SVGA 256-color graphics modes by displaying white
  554. mouse cursor pixels in color 255. Like color 15, color 255 is white by
  555. default. This allows you to redefine color 15 in your 256-color applications
  556. without interfering with the mouse cursor colors.
  557.  
  558.  
  559. Controlling the Mouse Cursor
  560.  
  561.      The mouse cursor indicates the current position of the mouse. By default,
  562. the cursor is a small white arrow in graphics modes and a one-character
  563. rectangle in text modes. After you use fg_mouseini to initialize the mouse,
  564. the mouse cursor is invisible. To make it visible, you must use fg_mousevis.
  565. This routine has a single integer argument that defines the mouse cursor
  566. visibility. If it is 0, the mouse cursor will be invisible; if it is 1, the
  567. mouse cursor becomes visible. If the mouse cursor is already in the requested
  568. state, fg_mousevis does nothing.
  569.  
  570.      If the mouse cursor is in an area of the screen being updated, or if it
  571. moves into this area during the update process, you must make the mouse cursor
  572. invisible or freeze it at its current position. You must also do this when
  573. performing any video output in the native EGA and VGA graphics modes (modes 13
  574. through 18). Instead of checking for these conditions, it is often more
  575. convenient and efficient to make the mouse cursor invisible during all screen
  576. updates and then make it visible again when the updating is finished. An
  577. alternative to making the mouse cursor invisible is freezing it at its current
  578. position using fg_mousepos and fg_mouselim (these routines will be described
  579. shortly) during screen updates and then restoring the default mouse limits.
  580. Note, however, that this method only works if the mouse cursor is outside the
  581. area being updated. You must also make the mouse cursor invisible when
  582. changing the visual page number with fg_setvpage.
  583.  
  584.      After you initialize the mouse, the cursor is positioned in the center of
  585. the screen. Moving the mouse of course changes the cursor position, but you
  586. also can position the mouse cursor with the Fastgraph routine fg_mousemov.
  587. This routine has two arguments that specify the new horizontal and vertical    
  588. 312   Fastgraph User's Guide
  589.  
  590. cursor position. The position is expressed in screen space units for graphics
  591. modes, while it is expressed in character cells for text modes. The
  592. fg_mousemov routine moves the cursor whether or not it is visible.
  593.  
  594.      Sometimes it is useful to restrict the mouse cursor to a specific area of
  595. the screen. The Fastgraph routine fg_mouselim prevents the mouse cursor from
  596. moving outside the specified rectangular area. It requires four arguments that
  597. specify the minimum horizontal coordinate, maximum horizontal coordinate,
  598. minimum vertical coordinate, and maximum vertical coordinate of this area.
  599. Again, the coordinates are expressed in screen space units for graphics modes
  600. and character cells for text modes.
  601.  
  602.      One of the most important functions of the mouse driver is to translate
  603. the horizontal and vertical mouse movements into a position on the screen. The
  604. mouse reports these movements to the mouse driver in units called mickeys (one
  605. mickey is about 1/200 of an inch, though for some mouse drivers it is 1/400 of
  606. an inch). By default, moving the mouse 8 mickeys in the horizontal direction
  607. moves the mouse cursor one horizontal pixel. Similarly, moving the mouse 16
  608. mickeys vertically moves the cursor one vertical pixel. Fastgraph provides a
  609. routine named fg_mousespd that can change these values, which effectively
  610. allows you to control the speed at which the mouse cursor moves relative to
  611. the movement of the mouse itself. The fg_mousespd routine requires two
  612. arguments that define the number of mickeys required for eight pixels of mouse
  613. cursor movement. The first argument specifies this for the horizontal
  614. direction, and the second for the vertical direction.
  615.  
  616.      Example 14-7, which runs in any graphics mode, demonstrates fg_mousevis,
  617. fg_mousemov, fg_mouselim, and fg_mousespd. The program first establishes the
  618. video mode, initializes the mouse, and fills the screen with a white
  619. rectangle. Next, the program calls fg_mousevis to make the mouse cursor
  620. visible and then calls fg_mouselim to restrict the mouse cursor to an area
  621. one-fourth the size of the screen, centered in the middle of the screen. At
  622. this point you should move the mouse cursor around the screen to see the
  623. effect of fg_mouselim and note the speed at which the cursor moves relative to
  624. the mouse itself. The program continues when you press any key.
  625.  
  626.      The program then uses fg_mousemov to move the mouse cursor to each corner
  627. of the region established by fg_mouselim. The call to fg_waitfor keeps the
  628. cursor in each corner for two seconds, unless you move the mouse. Note how the
  629. program tries to move the mouse cursor to each corner of the screen, but since
  630. doing so would move the cursor outside the defined region of movement,
  631. fg_mousemov just positions the cursor at the nearest point possible within
  632. this region. The last call to fg_mousemov moves the cursor back to the middle
  633. of the screen. After doing this, the program calls fg_mousespd to change the
  634. mouse cursor speed. The values passed to fg_mousespd (16 and 32) are twice the
  635. defaults and therefore make you move the mouse twice as far as before to move
  636. the mouse cursor the same distance. When you run the program, compare the
  637. mouse sensitivity to the original speed. After a keystroke, the program
  638. returns to DOS.
  639.  
  640.                                  Example 14-7.
  641.  
  642.                #include <fastgraf.h>
  643.                #include <stdio.h>
  644.                #include <stdlib.h>
  645.                void main(void);                                                
  646.                                        Chapter 14:  Input Device Support   313
  647.  
  648.  
  649.                void main()
  650.                {
  651.                   int maxx, maxy;
  652.                   int old_mode;
  653.  
  654.                   fg_initpm();
  655.                   old_mode = fg_getmode();
  656.                   fg_setmode(fg_automode());
  657.  
  658.                   if (fg_mouseini() < 0) {
  659.                      fg_setmode(old_mode);
  660.                      fg_reset();
  661.                      exit(1);
  662.                      }
  663.  
  664.                   maxx = fg_getmaxx();
  665.                   maxy = fg_getmaxy();
  666.                   fg_setcolor(15);
  667.                   fg_rect(0,maxx,0,maxy);
  668.  
  669.                   fg_mousevis(1);
  670.                   fg_mouselim(maxx/4,3*maxx/4,maxy/4,3*maxy/4);
  671.                   fg_waitkey();
  672.  
  673.                   fg_mousemov(0,0);
  674.                   fg_waitfor(36);
  675.                   fg_mousemov(maxx,0);
  676.                   fg_waitfor(36);
  677.                   fg_mousemov(maxx,maxy);
  678.                   fg_waitfor(36);
  679.                   fg_mousemov(0,maxy);
  680.                   fg_waitfor(36);
  681.                   fg_mousemov(maxx/2,maxy/2);
  682.                   fg_mousespd(16,32);
  683.                   fg_waitkey();
  684.  
  685.                   fg_setmode(old_mode);
  686.                   fg_reset();
  687.                }
  688.  
  689.  
  690.  
  691. Reporting the Mouse Status
  692.  
  693.      It is obviously important to be able to track the mouse position and
  694. button status. The Fastgraph routines fg_mousepos and fg_mousebut enable you
  695. to do this.
  696.  
  697.      The fg_mousepos routine returns information about the current mouse
  698. cursor position and button status. It requires three integer arguments, all
  699. passed by reference. The first two arguments respectively receive the
  700. horizontal and vertical coordinates of the mouse cursor. These values are
  701. expressed in screen space units for graphics modes and character cells for
  702. text modes. The third argument receives a three-bit mask containing the button
  703. status as shown here:                                                          
  704. 314   Fastgraph User's Guide
  705.  
  706.  
  707.                    bit
  708.                  number  meaning
  709.  
  710.                     0    1 if left button pressed, 0 if not
  711.                     1    1 if right button pressed, 0 if not
  712.                     2    1 if middle button pressed, 0 if not
  713.  
  714. For example, if both the left and right buttons are pressed, the button status
  715. will be set to 3. If the mouse only has two buttons, bit 2 will always be
  716. zero.
  717.  
  718.      Another routine, fg_mousebut, is available for returning the number of
  719. button press or release counts that have occurred since the last check, or
  720. since calling fg_mouseini. Each mouse button maintains its own separate
  721. counters, so fg_mousebut returns this information for a specific button.
  722. Additionally, fg_mousebut returns the horizontal and vertical position of the
  723. mouse cursor at the time the specified button was last pressed or released.
  724.  
  725.      The fg_mousebut routine takes four integer arguments, of which the last
  726. three are passed by reference. The absolute value of first argument specifies
  727. the button of interest (1 means the left button, 2 is the right button, and 3
  728. is the middle button), while its actual value determines if we're checking
  729. presses or releases. If the value is positive, button press counts will be
  730. reported. If it is negative, release counts will be reported. The second,
  731. third, and fourth arguments respectively receive the press or release count,
  732. the horizontal mouse cursor position at the time of the last press or release,
  733. and the vertical position at that same time. If the press or release count is
  734. zero, the mouse cursor position is returned as (0,0). The coordinate positions
  735. are expressed in screen space units for graphics modes and character cells for
  736. text modes.
  737.  
  738.      Example 14-8 runs in any graphics video mode and illustrates the use of
  739. fg_mousepos and fg_mousebut. The program first establishes the video mode and
  740. then initializes the mouse (the program exits if the initialization fails). It
  741. next fills the entire screen with a white rectangle and then calls fg_mousevis
  742. to make the mouse cursor visible.
  743.  
  744.      The main part of example 14-8 is a while loop that polls the mouse at
  745. three-second intervals (the call fg_waitfor(54) delays the program for three
  746. seconds). Within the loop, the program first uses fg_mousebut to get the
  747. number of times the left mouse button was pressed in the last three seconds.
  748. Following this, the fg_mousepos routine gets the current mouse position. The
  749. program then displays this information in the upper left corner of the screen;
  750. note how fg_mousevis is used to make the cursor invisible during graphics
  751. operations. The program continues until you press the right mouse button,
  752. checked by the call to fg_mousebut at the end of the loop.
  753.  
  754.                                  Example 14-8.
  755.  
  756.           #include <fastgraf.h>
  757.           #include <stdio.h>
  758.           #include <stdlib.h>
  759.           void main(void);
  760.  
  761.           void main()                                                          
  762.                                        Chapter 14:  Input Device Support   315
  763.  
  764.           {
  765.              int old_mode;
  766.              int buttons, count;
  767.              int x, y;
  768.              char string[25];
  769.  
  770.              fg_initpm();
  771.              old_mode = fg_getmode();
  772.              fg_setmode(fg_automode());
  773.  
  774.              if (fg_mouseini() < 0) {
  775.                 fg_setmode(old_mode);
  776.                 fg_reset();
  777.                 exit(1);
  778.                 }
  779.  
  780.              fg_setcolor(15);
  781.              fg_rect(0,fg_getmaxx(),0,fg_getmaxy());
  782.              fg_mousevis(1);
  783.  
  784.              do {
  785.                 fg_waitfor(54);
  786.                 fg_mousebut(1,&count,&x,&y);
  787.                 fg_mousepos(&x,&y,&buttons);
  788.                 sprintf(string,"X=%3d  Y=%3d  count=%4d",x,y,count);
  789.                 fg_mousevis(0);
  790.                 fg_setcolor(15);
  791.                 fg_rect(0,fg_xconvert(25),0,fg_yconvert(1));
  792.                 fg_setcolor(0);
  793.                 fg_locate(0,0);
  794.                 fg_text(string,24);
  795.                 fg_mousevis(1);
  796.                 fg_mousebut(2,&count,&x,&y);
  797.                 }
  798.              while (count == 0);
  799.  
  800.              fg_setmode(old_mode);
  801.              fg_reset();
  802.           }
  803.  
  804.  
  805.  
  806. Defining the Mouse Cursor
  807.  
  808.      By default, the mouse cursor is a small white arrow in graphics modes and
  809. a one-character rectangle in text modes. In graphics modes, you can change the
  810. mouse cursor to any 16 by 16 pixel image with the Fastgraph routine
  811. fg_mouseptr (in the CGA four-color graphics modes, the cursor size is 8 by 16
  812. pixels). You cannot change the mouse cursor shape in text modes, but you can
  813. use the Fastgraph routine fg_mousecur to define how it interacts with existing
  814. characters on the screen.                                                      
  815. 316   Fastgraph User's Guide
  816.  
  817. Text Modes
  818.  
  819.      To change the mouse cursor in text modes, you must first define two 16-
  820. bit quantities called the screen mask and cursor mask. The following figure
  821. defines the format of each mask.
  822.  
  823.                     bits           meaning
  824.  
  825.                     0 to 7         ASCII character value
  826.                     8 to 11        foreground color
  827.                     12 to 14       background color
  828.                     15             blink
  829.  
  830. Notice how this structure parallels the character and attribute bytes
  831. associated with each character cell. The default screen mask is 77FF hex, and
  832. the default cursor mask is 7700 hex.
  833.  
  834.      When you position the mouse over a specific character cell, the mouse
  835. driver uses the current screen and cursor masks to determine the mouse
  836. cursor's appearance. First, the mouse driver logically ANDs the screen mask
  837. with the existing contents of that character cell. It then XORs that result
  838. with the cursor mask to display the mouse cursor.
  839.  
  840.      For example, consider how the mouse cursor is produced in the 80-column
  841. color text mode (mode 3). Suppose a specific character cell contains the ASCII
  842. character 0 (48 decimal, 30 hex) and an attribute byte that specifies a white
  843. (color 15) foreground on a blue background (color 1) and does not blink (blink
  844. bit 0). The binary structure of the character and its attribute are:
  845.  
  846.                              attribute    character
  847.  
  848.                              0 001 1111   00110000
  849.  
  850.  
  851. Now let's see what happens when we apply the screen and cursor masks to the
  852. character and its attribute.
  853.  
  854.  
  855.             attribute/character   0001 1111 0011 0000   (1F30 hex)
  856.             default screen mask   0111 0111 1111 1111   (77FF hex)
  857.                                   -------------------
  858.             result of AND         0001 0111 0011 0000   (1730 hex)
  859.             default cursor mask   0111 0111 0000 0000   (7700 hex)
  860.                                   -------------------
  861.             result of XOR         0110 0000 0011 0000   (6030 hex)
  862.  
  863.  
  864. The resulting character (30 hex) is the original character, but the new
  865. attribute (60 hex) represents a black foreground with a brown background and
  866. does not blink. As long as the mouse cursor remains positioned on this
  867. character cell, it would appear black on brown.
  868.  
  869.      When we use the default screen and cursor masks, the mouse cursor will
  870. always display the original character and it will not blink. The cursor
  871. foreground color will be 15-F, where F is the displayed character's foreground
  872. color. Similarly, the cursor background color will be 7-B, where B is the      
  873.                                        Chapter 14:  Input Device Support   317
  874.  
  875. displayed character's background color. The default masks will virtually
  876. always produce a satisfactory mouse cursor.
  877.  
  878.      It is possible, however, to change the appearance of the mouse cursor in
  879. text modes by using your own screen and cursor masks. The Fastgraph routine
  880. fg_mousecur does just that. It expects two arguments, the first being the
  881. cursor mask and the second the screen mask. Example 14-9 demonstrates the use
  882. of fg_mousecur. The program displays some text and uses the default mouse
  883. cursor. After waiting for a keystroke, the program calls fg_mousecur to define
  884. a new mouse cursor. The new cursor is similar to the default cursor, but it
  885. displays the foreground colors in the opposite intensity as the default
  886. cursor. The program then waits for another keystroke before returning to DOS.
  887.  
  888.                                  Example 14-9.
  889.  
  890.                   #include <fastgraf.h>
  891.                   #include <stdio.h>
  892.                   #include <stdlib.h>
  893.                   void main(void);
  894.  
  895.                   void main()
  896.                   {
  897.                      int old_mode;
  898.                      int row;
  899.  
  900.                      fg_initpm();
  901.                      old_mode = fg_getmode();
  902.                      fg_setmode(3);
  903.  
  904.                      if (fg_mouseini() < 0) {
  905.                         fg_setmode(old_mode);
  906.                         fg_reset();
  907.                         exit(1);
  908.                         }
  909.  
  910.                      fg_setattr(7,0,0);
  911.                      fg_rect(0,fg_getmaxx(),0,fg_getmaxy());
  912.  
  913.                      fg_setattr(12,7,0);
  914.                      for (row = 0; row < 25; row++) {
  915.                         fg_locate(row,34);
  916.                         fg_text("example 14-9",12);
  917.                         }
  918.  
  919.                      fg_mousevis(1);
  920.                      fg_waitkey();
  921.                      fg_mousecur(0x7FFF,0x7F00);
  922.                      fg_waitkey();
  923.  
  924.                      fg_setmode(old_mode);
  925.                      fg_reset();
  926.                   }                                                            
  927. 318   Fastgraph User's Guide
  928.  
  929. Graphics Modes
  930.  
  931.      Defining the mouse cursor in graphics video modes also requires creating
  932. a screen mask and cursor mask, but as one might expect, the structure of these
  933. masks is vastly different from text modes. In fact, it closely resembles the
  934. mode-independent bitmap format used by fg_drawmap. Although their structure
  935. differs, the way the mouse driver applies the masks is the same as in the text
  936. modes. That is, the driver displays the mouse cursor by first logically ANDing
  937. video memory with the screen mask, and then XORing that result with the cursor
  938. mask.
  939.  
  940.      Let's begin by looking at the masks for the default mouse cursor in
  941. graphics modes. The size of each mask (and hence the mouse cursor) is 16
  942. pixels wide and 16 pixels high. As mentioned earlier, the default cursor is a
  943. small white arrow with a black outline around it. Here are its screen and
  944. cursor masks expressed as binary values.
  945.  
  946.               screen                cursor                cursor
  947.                mask                  mask               appearance
  948.  
  949.          1001111111111111      0000000000000000       **
  950.          1000111111111111      0010000000000000       *x*
  951.          1000011111111111      0011000000000000       *xx*
  952.          1000001111111111      0011100000000000       *xxx*
  953.          1000000111111111      0011110000000000       *xxxx*
  954.          1000000011111111      0011111000000000       *xxxxx*
  955.          1000000001111111      0011111100000000       *xxxxxx*
  956.          1000000000111111      0011111110000000       *xxxxxxx*
  957.          1000000000011111      0011111111000000       *xxxxxxxx*
  958.          1000000000001111      0011111000000000       *xxxxx*****
  959.          1000000011111111      0011011000000000       *xx*xx*
  960.          1000100001111111      0010001100000000       *x* *xx*
  961.          1001100001111111      0000001100000000       **  *xx*
  962.          1111110000111111      0000000110000000            *xx*
  963.          1111110000111111      0000000110000000            *xx*
  964.          1111111000111111      0000000000000000             ***
  965.  
  966.      The mouse driver first ANDs the screen mask with video memory at the
  967. mouse cursor position. This means the screen mask 1 bits leave video memory
  968. intact, while the 0 bits change the corresponding pixels to black. Next, the
  969. mouse driver XORs the result with the cursor mask. This time the cursor mask 0
  970. bits leave video memory unchanged, while the 1 bits change the corresponding
  971. pixels to white. This produces a mouse cursor as shown above on the right,
  972. where a dot ( ) represents an unchanged pixel, an asterisk (*) a black pixel,
  973. and an x a white pixel. The following table summarizes the cursor appearance
  974. for all possible combinations of mask bits.
  975.  
  976.              screen mask bit  cursor mask bit    resulting cursor pixel
  977.  
  978.                     0                0                    black
  979.                     0                1                    white
  980.                     1                0                  unchanged
  981.                     1                1                  inverted
  982.  
  983.      The color of an "inverted" pixel is n-k, where n is the maximum color
  984. number in the current video mode, and k is the color of the pixel being        
  985.                                        Chapter 14:  Input Device Support   319
  986. replaced. Also, "black" and "white" pixels are not necessarily these colors in
  987. 16-color and 256-color modes. More correctly, "black" pixels are displayed in
  988. the color assigned to palette 0, and "white" pixels are the displayed in the
  989. color assigned to palette 15 (255 in XVGA and SVGA 256-color modes). If you're
  990. using the CGA color modes, "black" pixels are displayed in the background
  991. color, and "white" pixels appear in color 3 (whose actual color is determined
  992. by the selected CGA palette).
  993.  
  994.      With an understanding of the way the default mouse cursor works in
  995. graphics modes, we're now ready to define our own mouse cursor. Shown here are
  996. the screen mask, cursor mask, and resulting appearance for a solid plus-shaped
  997. cursor. The hexadecimal equivalents of the binary mask values are also given.
  998.  
  999.    ----- screen mask ----      ----- cursor mask ----
  1000.                                                                 cursor
  1001.         binary       hex            binary       hex          appearance
  1002.  
  1003.    1110000000111111  E03F      0000000000000000  0000      ...*******......
  1004.    1110000000111111  E03F      0000111110000000  0F80      ...*xxxxx*......
  1005.    1110000000111111  E03F      0000111110000000  0F80      ...*xxxxx*......
  1006.    0000000000000111  0007      0000111110000000  0F80      ****xxxxx****...
  1007.    0000000000000111  0007      0111111111110000  7FF0      *xxxxxxxxxxx*...
  1008.    0000000000000111  0007      0111111111110000  7FF0      *xxxxxxxxxxx*...
  1009.    0000000000000111  0007      0111111111110000  7FF0      *xxxxxxxxxxx*...
  1010.    0000000000000111  0007      0111111111110000  7FF0      *xxxxxxxxxxx*...
  1011.    0000000000000111  0007      0111111111110000  7FF0      *xxxxxxxxxxx*...
  1012.    0000000000000111  0007      0000111110000000  0F80      ****xxxxx****...
  1013.    1110000000111111  E03F      0000111110000000  0F80      ...*xxxxx*......
  1014.    1110000000111111  E03F      0000111110000000  0F80      ...*xxxxx*......
  1015.    1110000000111111  E03F      0000000000000000  0000      ...*******......
  1016.    1111111111111111  FFFF      0000000000000000  0000      ................
  1017.    1111111111111111  FFFF      0000000000000000  0000      ................
  1018.    1111111111111111  FFFF      0000000000000000  0000      ................
  1019.  
  1020. If we wanted to make the mouse cursor hollow rather than solid, the masks and
  1021. resulting cursor appearance would look like this.
  1022.  
  1023.    ----- screen mask ----      ----- cursor mask ----
  1024.                                                                 cursor
  1025.         binary       hex            binary       hex          appearance
  1026.  
  1027.    1110000000111111  E03F      0000000000000000  0000      ...*******......
  1028.    1110111110111111  EFBF      0000000000000000  0000      ...*.....*......
  1029.    1110111110111111  EFBF      0000000000000000  0000      ...*.....*......
  1030.    0000111110000111  0F87      0000000000000000  0000      ****.....****...
  1031.    0111111111110111  7FF7      0000000000000000  0000      *...........*...
  1032.    0111111111110111  7FF7      0000000000000000  0000      *...........*...
  1033.    0111111111110111  7FF7      0000001000000000  0200      *.....x.....*...
  1034.    0111111111110111  7FF7      0000000000000000  0000      *...........*...
  1035.    0111111111110111  7FF7      0000000000000000  0000      *...........*...
  1036.    0000111110000111  0F87      0000000000000000  0000      ****.....****...
  1037.    1110111110111111  EFBF      0000000000000000  0000      ...*.....*......
  1038.    1110111110111111  EFBF      0000000000000000  0000      ...*.....*......
  1039.    1110000000111111  E03F      0000000000000000  0000      ...*******......
  1040.    1111111111111111  FFFF      0000000000000000  0000      ................
  1041.    1111111111111111  FFFF      0000000000000000  0000      ................   1111111111111111  FFFF      0000000000000000  0000      ................    
  1042. 320   Fastgraph User's Guide
  1043.  
  1044. Note that the center bit defined in the cursor mask causes the corresponding
  1045. pixel in video memory to be inverted.
  1046.  
  1047.      There is one more item needed to define a graphics mode mouse cursor
  1048. completely. That item is the hot spot, or the actual screen position used or
  1049. reported by the mouse driver. For the plus-shaped cursors just constructed, it
  1050. would make sense to define the hot spot in the center of the plus. The hot
  1051. spot is specified relative to the upper left corner of the cursor, so its
  1052. position within the cursor would be (6,6) -- that is, six pixels to the right
  1053. and six pixels below the upper left corner. You can specify the hot spot
  1054. offsets using negative values or values above 15 to position it outside the
  1055. mouse cursor matrix if desired.
  1056.  
  1057.      The Fastgraph routine fg_mouseptr defines a mouse cursor in graphics
  1058. modes. The first of its three arguments is a 32-element 16-bit integer array,
  1059. passed by reference. The array's first 16 elements contain the screen mask,
  1060. and its second 16 elements contain the cursor mask. The remaining two
  1061. arguments respectively specify the horizontal and vertical offsets for the hot
  1062. spot. The fg_mouseptr routine has no effect in a text video mode. In C or C++
  1063. programs, we recommend using the short data type for the mask array because
  1064. short means a 16-bit integer for both 16-bit and 32-bit environments.
  1065. Similarly, FORTRAN programmers should define the mask array as an INTEGER*2
  1066. item.
  1067.  
  1068.      Example 14-10 is similar to example 14-9. It shows how to define a
  1069. graphics mode mouse cursor using fg_mouseptr. The values stored in the solid
  1070. and hollow arrays define the screen and cursor masks for the solid and hollow
  1071. plus-shaped mouse cursors discussed earlier. After making the mouse cursor
  1072. visible, the program uses the default mouse cursor until a key is pressed.
  1073. Following this, it changes to the solid cursor. After another keystroke, the
  1074. program changes to the hollow cursor. When you run example 14-10, compare the
  1075. differences between the three mouse cursors.
  1076.  
  1077.                                 Example 14-10.
  1078.  
  1079.                 #include <fastgraf.h>
  1080.                 #include <stdio.h>
  1081.                 #include <stdlib.h>
  1082.                 void main(void);
  1083.  
  1084.                 short solid[]  = {0xE03F,0xE03F,0xE03F,0x0007,
  1085.                                   0x0007,0x0007,0x0007,0x0007,
  1086.                                   0x0007,0x0007,0xE03F,0xE03F,
  1087.                                   0xE03F,0xFFFF,0xFFFF,0xFFFF,
  1088.                                   0x0000,0x0F80,0x0F80,0x0F80,
  1089.                                   0x7FF0,0x7FF0,0x7FF0,0x7FF0,
  1090.                                   0x7FF0,0x0F80,0x0F80,0x0F80,
  1091.                                   0x0000,0x0000,0x0000,0x0000};
  1092.  
  1093.                 short hollow[] = {0xE03F,0xEFBF,0xEFBF,0x0F87,
  1094.                                   0x7FF7,0x7FF7,0x7FF7,0x7FF7,
  1095.                                   0x7FF7,0x0F87,0xEFBF,0xEFBF,
  1096.                                   0xE03F,0xFFFF,0xFFFF,0xFFFF,
  1097.                                   0x0000,0x0000,0x0000,0x0000,                 
  1098.                                        Chapter 14:  Input Device Support   321
  1099.  
  1100.                                   0x0000,0x0000,0x0200,0x0000,
  1101.                                   0x0000,0x0000,0x0000,0x0000,
  1102.                                   0x0000,0x0000,0x0000,0x0000};
  1103.  
  1104.                 void main()
  1105.                 {
  1106.                    int old_mode;
  1107.                    int column, row, last_row;
  1108.  
  1109.                    fg_initpm();
  1110.                    old_mode = fg_getmode();
  1111.                    fg_setmode(fg_automode());
  1112.  
  1113.                    if (fg_mouseini() < 0)
  1114.                    {
  1115.                       fg_setmode(old_mode);
  1116.                       fg_reset();
  1117.                       exit(1);
  1118.                    }
  1119.  
  1120.                    fg_setcolor(15);
  1121.                    fg_rect(0,fg_getmaxx(),0,fg_getmaxy());
  1122.  
  1123.                    fg_setcolor(12);
  1124.                    column = fg_xalpha(fg_getmaxx()/2) - 6;
  1125.                    last_row = fg_yalpha(fg_getmaxy()) + 1;
  1126.  
  1127.                    for (row = 0; row < last_row; row++)
  1128.                    {
  1129.                       fg_locate(row,column);
  1130.                       fg_text("example 14-10",13);
  1131.                    }
  1132.  
  1133.                    fg_mousevis(1);
  1134.                    fg_waitkey();
  1135.                    fg_mouseptr(solid,6,6);
  1136.                    fg_waitkey();
  1137.                    fg_mouseptr(hollow,6,6);
  1138.                    fg_waitkey();
  1139.  
  1140.                    fg_setmode(old_mode);
  1141.                    fg_reset();
  1142.                 }
  1143.  
  1144.  
  1145. CGA Considerations
  1146.  
  1147.      The mouse driver treats the screen and cursor masks differently in the
  1148. CGA four-color graphics modes (modes 4 and 5) than in the other graphics
  1149. modes. In the CGA modes, each pair of mask bits corresponds to one pixel. This
  1150. means the masks more closely resemble the mode-specific format used by
  1151. fg_drwimage instead of the mode-independent format of fg_drawmap.
  1152.  
  1153.      Fastgraph uses a different default mouse cursor for modes 4 and 5. Its
  1154. screen and cursor masks, as well as the resulting cursor appearance, are shown
  1155. in the following diagram.                                                      
  1156. 322   Fastgraph User's Guide
  1157.  
  1158.  
  1159.                 screen                  cursor              cursor
  1160.                  mask                    mask             appearance
  1161.  
  1162.            0000111111111111        0000000000000000        **
  1163.            0000001111111111        0011000000000000        ***
  1164.            0000000011111111        0011110000000000        ****
  1165.            0000000000111111        0011111100000000        *****
  1166.            0000000000001111        0011111111000000        ******
  1167.            0000000000000011        0011111111110000        *******
  1168.            0000000000000011        0011111100000000        *******
  1169.            0000000000111111        0011111110000000        *****
  1170.            0000000000001111        0011000011000000        ******
  1171.            0000110000001111        0000000011000000        ** ***
  1172.            1111111100000011        0000000000110000            ***
  1173.            1111111100000011        0010000000110000            ***
  1174.            1111111111000011        0000000000000000             **
  1175.            1111111111111111        0000000000000000
  1176.            1111111111111111        0000000000000000
  1177.            1111111111111111        0000000000000000
  1178.  
  1179. As you can see, the resulting mouse cursor is eight pixels wide instead of 16.
  1180.  
  1181.      Another important point concerning mouse cursors in modes 4 and 5 is the
  1182. chance of pixel bleeding, or the changing of colors within the mouse cursor as
  1183. it moves horizontally. Bleeding will occur if you use the bit pairs 01 or 10
  1184. in either mask to represent a pixel. In the default masks for modes 4 and 5,
  1185. note that only the binary values 00 and 11 appear as bit pairs. Keep this in
  1186. mind if you create your own masks in these video modes.
  1187.  
  1188. XVGA and SVGA Considerations
  1189.  
  1190.      In XVGA graphics modes and 256-color SVGA graphics modes (20 to 27), it's
  1191. possible to create a multicolored mouse cursor. To do this, use fg_mouse256
  1192. instead of fg_mouseptr to define the mouse cursor's shape and appearance. The
  1193. fg_mouse256 routine uses the same arguments as fg_mouseptr, but the masks are
  1194. passed in a 512-byte array consisting of a 256-byte screen mask followed by a
  1195. 256-byte cursor mask. As with fg_mouseptr, each mask is structured as a 16x16
  1196. pixel grid, but each pixel is represented by a byte value rather than a single
  1197. bit.
  1198.  
  1199.      The mouse driver displays the mouse cursor by logically ANDing video
  1200. memory with the screen mask, and then XORing that result with the cursor mask.
  1201. This normally means the screen mask values are either 0 or 255, while cursor
  1202. mask values are between 0 and 255. For example, consider again the default
  1203. graphics mode mouse cursor (the arrow). If we wanted to display the cursor in
  1204. yellow (color 14) instead of its default white, you would expand the screen
  1205. mask from 16 to 256 bytes, replacing the zero bits in the "standard" mask with
  1206. zero bytes and replacing the one bits with the value 255. You would similarly
  1207. expand the cursor mask, replacing the zero bits with zero bytes and the one
  1208. bits with the value 14.                                                        
  1209.                                        Chapter 14:  Input Device Support   323
  1210.  
  1211.  
  1212. Joystick Support
  1213.  
  1214.      The third type of input device supported by Fastgraph is the joystick.
  1215. Although joysticks are not as popular as mice, they are often preferable when
  1216. a user's reactions are critical, such as in an arcade-style game. Fastgraph
  1217. includes routines for initializing a joystick, reading a joystick's position
  1218. or button status, and making a joystick behave analogously to the keyboard.
  1219. These routines are independent of the rest of Fastgraph and thus do not
  1220. require that you first call fg_setmode.
  1221.  
  1222.      Joysticks are connected to a system through a game port. The PCjr and
  1223. Tandy 1000 systems come equipped with two game ports, and hence support two
  1224. joysticks. On other systems in the IBM family, you can install a game card
  1225. with one or two game ports. If the card only has one game port, you can use a
  1226. splitter cable to fork two joysticks into the port.
  1227.  
  1228.  
  1229. Initializing Joysticks
  1230.  
  1231.      Before you can use any of Fastgraph's joystick support routines with a
  1232. specific joystick, you must initialize that joystick. The fg_initjoy routine
  1233. performs this task. This routine requires a single integer argument that
  1234. specifies which joystick to initialize, either 1 or 2. If successful,
  1235. fg_initjoy returns 0 as the function value. If the machine has no game port,
  1236. or if the requested joystick is not connected to the game port, fg_initjoy
  1237. returns -1. When you use fg_initjoy, the joystick being initialized must be
  1238. centered (that is, the stick itself must not be tilted in either direction).
  1239.  
  1240.      Example 14-11 uses the fg_initjoy routine to try to initialize both
  1241. joysticks. For each joystick, the program prints a message stating whether or
  1242. not the initialization was successful.
  1243.  
  1244.                                 Example 14-11.
  1245.  
  1246.                  #include <fastgraf.h>
  1247.                  #include <stdio.h>
  1248.                  void main(void);
  1249.  
  1250.                  void main()
  1251.                  {
  1252.                     fg_initpm();
  1253.                     if (fg_initjoy(1) < 0)
  1254.                        printf("Joystick 1 not available.\n");
  1255.                     else
  1256.                        printf("Joystick 1 found.\n");
  1257.  
  1258.                     if (fg_initjoy(2) < 0)
  1259.                        printf("Joystick 2 not available.\n");
  1260.                     else
  1261.                        printf("Joystick 2 found.\n");
  1262.                  }                                                             
  1263. 324   Fastgraph User's Guide
  1264.  
  1265.  
  1266. Reporting Joystick Status
  1267.  
  1268.      Each joystick can report three items: its horizontal position, its
  1269. vertical position, and the button status. Fastgraph includes routines for
  1270. obtaining each of these quantities.
  1271.  
  1272.      The fg_getxjoy and fg_getyjoy routines respectively return the horizontal
  1273. and vertical position of the indicated joystick. Both routines require a
  1274. single integer argument, whose value is either 1 or 2, to identify the
  1275. joystick. The requested position is returned as the function value. Horizontal
  1276. coordinates increase as the joystick moves to the right, while vertical
  1277. coordinates increase as the joystick moves downward. If fg_initjoy did not
  1278. initialize the specified joystick, or if your program hasn't yet called
  1279. fg_initjoy, both fg_getxjoy and fg_getyjoy will return -1.
  1280.  
  1281.      Joystick characteristics vary more than those of any other input device.
  1282. The values returned by fg_getxjoy and fg_getyjoy depend on the system's
  1283. processor speed and the brand of joystick used. It often suffices to know the
  1284. joystick position relative to its previous position, in which case the actual
  1285. coordinate values do not matter. However, if you must rely on specific
  1286. coordinate values, your program must perform some type of manual joystick
  1287. calibration and then scale the coordinates reported by fg_getxjoy and
  1288. fg_getyjoy as needed.
  1289.  
  1290.      The other piece of information joysticks provide is the button status.
  1291. Most joysticks have two buttons, called the top and bottom buttons. Others
  1292. have three buttons, but one of them duplicates the functionality of another
  1293. (for example, a joystick might have one bottom button on its left side and
  1294. another on its right side). The Fastgraph routine fg_button returns the
  1295. joystick button status as its function value. Like fg_getxjoy and fg_getyjoy,
  1296. fg_button requires a single argument that specifies the joystick number. The
  1297. meaning of the return value is shown here:
  1298.  
  1299.                             value meaning
  1300.  
  1301.                               0   neither button pressed
  1302.                               1   top button pressed
  1303.                               2   bottom button pressed
  1304.                               3   top and bottom buttons pressed
  1305.  
  1306.      You don't need to call fg_initjoy before using fg_button. If the
  1307. specified joystick is not present, fg_button will return a value of 0.
  1308.  
  1309.      Example 14-12 uses fg_getxjoy, fg_getyjoy, and fg_button to poll both
  1310. joysticks at half-second intervals. It then displays the joystick number (1 or
  1311. 2), horizontal position, vertical position, and button status for each
  1312. joystick. As the program runs, you can move the joysticks and watch how the
  1313. movements affect the displayed coordinate values. The program continues doing
  1314. this until you press Ctrl/C or Ctrl/Break to stop it.
  1315.  
  1316.                                 Example 14-12.
  1317.  
  1318.                   #include <fastgraf.h>
  1319.                   #include <stdio.h>
  1320.                   void main(void);                                             
  1321.                                        Chapter 14:  Input Device Support   325
  1322.  
  1323.  
  1324.                   void main()
  1325.                   {
  1326.                      int b, x, y;
  1327.  
  1328.                      fg_initpm();
  1329.                      fg_initjoy(1);
  1330.                      fg_initjoy(2);
  1331.  
  1332.                      while (1) {
  1333.                         x = fg_getxjoy(1);
  1334.                         y = fg_getyjoy(1);
  1335.                         b = fg_button(1);
  1336.                         printf("1:  %3d %3d %1d\n",x,y,b);
  1337.                         x = fg_getxjoy(2);
  1338.                         y = fg_getyjoy(2);
  1339.                         b = fg_button(2);
  1340.                         printf("2:  %3d %3d %1d\n\n",x,y,b);
  1341.                         fg_waitfor(9);
  1342.                         }
  1343.                   }
  1344.  
  1345.  
  1346.      There are two ways of effectively monitoring joystick button status. One
  1347. is to call fg_button at many places in your program and then take the
  1348. necessary action depending on the button status. However, the preferable
  1349. method is to extend the BIOS time-of-day interrupt to check the button status
  1350. at each clock tick (there are 18.2 clock ticks per second), set a flag if a
  1351. button is pressed, and then check the flag as needed in your program.
  1352. Information on changing the BIOS time-of-day interrupt appears in Appendix C.
  1353.  
  1354.  
  1355. Keyboard Emulation
  1356.  
  1357.      Although we can use fg_getxjoy and fg_getyjoy to monitor relative
  1358. joystick movements, it is usually easier to do this with another Fastgraph
  1359. routine, fg_intjoy. This routine is similar to fg_intkey in that it returns
  1360. two values equivalent to the standard or extended keyboard codes for analogous
  1361. keystrokes.
  1362.  
  1363.      The fg_intjoy routine needs three arguments. The first argument specifies
  1364. the joystick number, either 1 or 2. The second and third arguments, both one-
  1365. byte quantities passed by reference, receive the standard and extended
  1366. keyboard codes analogous to the joystick movement and button status. The
  1367. second argument receives a value of 13 (the standard keyboard code for the
  1368. Enter key) if any joystick button is pressed; it receives a value of 0 if not.
  1369. The third argument receives a value corresponding to the extended keyboard
  1370. code for one of the directional keys on the numeric keypad, as summarized in
  1371. the following table.
  1372.  
  1373.             joystick position   corresponding key   extended key code
  1374.  
  1375.                up and left            Home                 71
  1376.                    up               up arrow               72
  1377.               up and right            PgUp                 73
  1378.                   left             left arrow              75                  
  1379. 326   Fastgraph User's Guide
  1380.  
  1381.                 centered           (no action)              0
  1382.                   right            right arrow             77
  1383.               down and left            End                 79
  1384.                   down             down arrow              80
  1385.              down and right           PgDn                 81
  1386.  
  1387. The fg_intjoy routine will set both key code arguments to zero if the
  1388. specified joystick has not yet been initialized.
  1389.  
  1390.      Example 14-13 is similar to example 14-11, but it uses fg_intjoy in place
  1391. of fg_getxjoy and fg_getyjoy to report relative joystick position. This
  1392. program does not report the joystick button status as example 14-11 does, but
  1393. you could readily add this feature to it.
  1394.  
  1395.                                 Example 14-13.
  1396.  
  1397.                     #include <fastgraf.h>
  1398.                     #include <stdio.h>
  1399.                     void main(void);
  1400.  
  1401.                     void main()
  1402.                     {
  1403.                        char key, aux;
  1404.  
  1405.                        fg_initpm();
  1406.                        fg_initjoy(1);
  1407.                        fg_initjoy(2);
  1408.  
  1409.                        while (1) {
  1410.                           fg_intjoy(1,&key,&aux);
  1411.                           printf("1: %2d %2d\n",key,aux);
  1412.                           fg_intjoy(2,&key,&aux);
  1413.                           printf("2: %2d %2d\n\n",key,aux);
  1414.                           fg_waitfor(9);
  1415.                           }
  1416.                     }
  1417.  
  1418.  
  1419.  
  1420. Special Joystick Considerations
  1421.  
  1422.      If you develop a program that supports only one joystick, you should use
  1423. joystick 1. The reasons for this are twofold. First, it will make your program
  1424. consistent with most other products that support joysticks. Second, many Tandy
  1425. 1000 series machines cannot determine if joystick 2 is present when neither
  1426. joystick is connected. This means if you use joystick 2 instead of joystick 1
  1427. in a single joystick program, you won't be able to tell if a joystick is
  1428. available when running on a Tandy 1000.
  1429.  
  1430.  
  1431. Summary of Input Routines
  1432.  
  1433.      This section summarizes the functional descriptions of the Fastgraph
  1434. routines presented in this chapter. More detailed information about these
  1435. routines, including their arguments and return values, may be found in the
  1436. Fastgraph Reference Manual.                                                    
  1437.                                        Chapter 14:  Input Device Support   327
  1438.  
  1439.  
  1440.      FG_BUTTON returns information about the state of either joystick's
  1441. buttons.
  1442.  
  1443.      FG_CAPSLOCK determines the state of the CapsLock key.
  1444.  
  1445.      FG_GETKEY waits for a keystroke (or reads the next entry from the BIOS
  1446. keyboard buffer). It returns the keystroke's standard or extended keyboard
  1447. code.
  1448.  
  1449.      FG_GETXJOY and FG_GETYJOY return the horizontal and vertical coordinate
  1450. position of the specified joystick. The actual coordinates depend on the
  1451. processor speed and brand of joystick used.
  1452.  
  1453.      FG_INITJOY initializes joystick 1 or 2 and must be called before using
  1454. fg_getxjoy, fg_getyjoy, or fg_intjoy. It returns a status code indicating
  1455. whether or not the initialization was successful.
  1456.  
  1457.      FG_INTJOY returns the standard and extended keyboard codes analogous to
  1458. the current position and button status of the specified joystick.
  1459.  
  1460.      FG_INTKEY reads the next entry from the BIOS keyboard buffer and returns
  1461. the keystroke's standard or extended keyboard code. It is similar to
  1462. fg_getkey, but it does not wait for a keystroke if the keyboard buffer is
  1463. empty.
  1464.  
  1465.      FG_KBINIT enables or disables Fastgraph's low-level keyboard handler. If
  1466. the keyboard handler is already in the requested state, nothing happens.
  1467.  
  1468.      FG_KBLAST returns the scan code for the most recent keypress processed by
  1469. Fastgraph's low-level keyboard handler.
  1470.  
  1471.      FG_KBRESET resets the state of Fastgraph's low-level keyboard handler to
  1472. what it was after being enabled with fg_kbinit.
  1473.  
  1474.      FG_KBTEST determines if the key having the specified scan code is now
  1475. pressed or released. The low-level keyboard handler must be enabled for this
  1476. routine to work properly.
  1477.  
  1478.      FG_MOUSE256 defines the shape and appearance of a multicolored mouse
  1479. cursor in XVGA and 256-color SVGA graphics modes.
  1480.  
  1481.      FG_MOUSEBUT returns information about mouse button press or release
  1482. counts, as well as the mouse cursor position at the time of the last button
  1483. press or release.
  1484.  
  1485.      FG_MOUSECUR defines the appearance of the mouse cursor in text video
  1486. modes.
  1487.  
  1488.      FG_MOUSEFIN unhooks Fastgraph's XVGA or SVGA mouse handler from the mouse
  1489. driver. This routine should be used just before reverting to text mode in
  1490. programs that have called fg_mouseini in XVGA or SVGA graphics modes. It has
  1491. no effect in other video modes.
  1492.  
  1493.      FG_MOUSEINI initializes the mouse and must be called before any of
  1494. Fastgraph's other mouse support routines. It returns an error status if the    
  1495. 328   Fastgraph User's Guide
  1496.  
  1497. mouse driver has not been loaded, if the mouse is not connected, or if a
  1498. virtual buffer is active.
  1499.  
  1500.      FG_MOUSELIM defines the rectangular area in which the mouse cursor may
  1501. move.
  1502.  
  1503.      FG_MOUSEMOV moves the mouse cursor to the specified character cell (in
  1504. text modes) or screen space position (in graphics modes).
  1505.  
  1506.      FG_MOUSEPOS returns the current mouse position and button status.
  1507.  
  1508.      FG_MOUSEPTR defines the shape and appearance of the mouse cursor in
  1509. graphics video modes.
  1510.  
  1511.      FG_MOUSESPD defines the number of mickey units per eight pixels of cursor
  1512. movement. This effectively controls the speed at which the mouse cursor moves
  1513. relative to the movement of the mouse itself.
  1514.  
  1515.      FG_MOUSEVIS makes the mouse cursor visible or invisible.
  1516.  
  1517.      FG_NUMLOCK determines the state of the NumLock key.
  1518.  
  1519.      FG_SCRLOCK determines the state of the ScrollLock key (which is not
  1520. present on some keyboards).
  1521.  
  1522.      FG_SETCAPS controls the state of the CapsLock key.
  1523.  
  1524.      FG_SETNUM controls the state of the NumLock key.
  1525.  
  1526.      FG_WAITKEY flushes the BIOS keyboard buffer (that is, removes any type-
  1527. ahead characters) and then waits for another keystroke.
  1528.