home *** CD-ROM | disk | FTP | other *** search
/ The Devil's Doorknob BBS Capture (1996-2003) / devilsdoorknobbbscapture1996-2003.iso / Dloads / PROGRAMM / FGL112B.ZIP / USER12.DOC < prev    next >
Text File  |  1992-10-05  |  60KB  |  1,285 lines

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