home *** CD-ROM | disk | FTP | other *** search
/ For Beginners & Professional Hackers / cd.iso / docum / advdos.doc / s1c05 < prev    next >
Encoding:
Text File  |  1992-04-21  |  37.2 KB  |  838 lines

  1. ────────────────────────────────────────────────────────────────────────────
  2. Chapter 5  Keyboard and Mouse Input
  3.  
  4.   The fundamental means of user input under MS-DOS is the keyboard. This
  5.   follows naturally from the MS-DOS command-line interface, whose lineage
  6.   can be traced directly to minicomputer operating systems with Teletype
  7.   consoles. During the first few years of MS-DOS's existence, when
  8.   8088/8086-based machines were the norm, nearly every popular application
  9.   program used key-driven menus and text-mode displays.
  10.  
  11.   However, as high-resolution graphics adapters (and 80286/80386-based
  12.   machines with enough power to drive them) have become less expensive,
  13.   programs that support windows and a graphical user interface have steadily
  14.   grown more popular. Such programs typically rely on a pointing device such
  15.   as a mouse, stylus, joystick, or light pen to let the user navigate in a
  16.   "point-and-shoot" manner, reducing keyboard entry to a minimum. As a
  17.   result, support for pointing devices has become an important consideration
  18.   for all software developers.
  19.  
  20.  
  21. Keyboard Input Methods
  22.  
  23.   Applications running under MS-DOS on IBM PC─compatible machines can use
  24.   several methods to obtain keyboard input:
  25.  
  26.   ■  MS-DOS handle-oriented functions
  27.  
  28.   ■  MS-DOS traditional character functions
  29.  
  30.   ■  IBM ROM BIOS keyboard-driver functions
  31.  
  32.   These methods offer different degrees of flexibility, portability, and
  33.   hardware independence.
  34.  
  35.   The handle, or stream-oriented, functions are philosophically derived from
  36.   UNIX/XENIX and were first introduced in MS-DOS version 2.0. A program uses
  37.   these functions by supplying a handle, or token, for the desired device,
  38.   plus the address and length of a buffer.
  39.  
  40.   When a program begins executing, MS-DOS supplies it with predefined
  41.   handles for certain commonly used character devices, including the
  42.   keyboard:
  43.  
  44.   Handle             Device name                          Opened to
  45.   ──────────────────────────────────────────────────────────────────────────
  46.   0                  Standard input (stdin)               CON
  47.   1                  Standard output (stdout)             CON
  48.   2                  Standard error (stderr)              CON
  49.   3                  Standard auxiliary (stdaux)          AUX
  50.   4                  Standard printer (stdprn)            PRN
  51.   ──────────────────────────────────────────────────────────────────────────
  52.  
  53.   These handles can be used for read and write operations without further
  54.   preliminaries. A program can also obtain a handle for a character device
  55.   by explicitly opening the device for input or output using its logical
  56.   name (as though it were a file). The handle functions support I/O
  57.   redirection, allowing a program to take its input from another device or
  58.   file instead of the keyboard, for example. Redirection is discussed in
  59.   detail in Chapter 15.
  60.  
  61.   The traditional character-input functions are a superset of the character
  62.   I/O functions that were present in CP/M. Originally included in MS-DOS
  63.   simply to facilitate the porting of existing applications from CP/M, they
  64.   are still widely used. In MS-DOS versions 2.0 and later, most of the
  65.   traditional functions also support I/O redirection (although not as well
  66.   as the handle functions do).
  67.  
  68.   Use of the IBM ROM BIOS keyboard functions presupposes that the program is
  69.   running on an IBM PC─compatible machine. The ROM BIOS keyboard driver
  70.   operates at a much more primitive level than the MS-DOS functions and
  71.   allows a program to circumvent I/O redirection or MS-DOS's special
  72.   handling of certain control characters. Programs that use the ROM BIOS
  73.   keyboard driver are inherently less portable than those that use the
  74.   MS-DOS functions and may interfere with the proper operation of other
  75.   programs; many of the popular terminate-and-stay-resident (TSR) utilities
  76.   fall into this category.
  77.  
  78. Keyboard Input with Handles
  79.  
  80.   The principal MS-DOS function for keyboard input using handles is Int 21H
  81.   Function 3FH (Read File or Device). The parameters for this function are
  82.   a handle, the segment and offset of a buffer, and the length of the
  83.   buffer. (For a more detailed explanation of this function, see Section
  84.   II of this book, "MS-DOS Functions Reference.")
  85.  
  86.   As an example, let's use the predefined standard input handle (0) and Int
  87.   21H Function 3FH to read a line from the keyboard:
  88.  
  89.   ──────────────────────────────────────────────────────────────────────────
  90.   buffer  db   80 dup (?)     ; keyboard input buffer
  91.           .
  92.           .
  93.           .
  94.           mov  ah,3fh         ; function 3fh = read file or device
  95.           mov  bx,0           ; handle for standard input
  96.           mov  cx,80          ; maximum bytes to read
  97.           mov  dx,seg buffer  ; DS:DX = buffer address
  98.           mov  ds,dx
  99.           mov  dx,offset buffer
  100.           int  21h            ; transfer to MS-DOS
  101.           jc   error          ; jump if error detected
  102.           .
  103.           .
  104.           .
  105.   ──────────────────────────────────────────────────────────────────────────
  106.  
  107.   When control returns from Int 21H Function 3FH, the carry flag is clear if
  108.   the function was successful, and AX contains the number of characters
  109.   read. If there was an error, the carry flag is set and AX contains an
  110.   error code; however, this should never occur when reading the keyboard.
  111.  
  112.   The standard input is redirectable, so the code just shown is not a
  113.   foolproof way of obtaining input from the keyboard. Depending upon whether
  114.   a redirection parameter was included in the command line by the user,
  115.   program input might be coming from the keyboard, a file, another character
  116.   device, or even the bit bucket (NUL device). To bypass redirection and be
  117.   absolutely certain where your input is coming from, you can ignore the
  118.   predefined standard input handle and open the console as though it were a
  119.   file, using the handle obtained from that open operation to perform your
  120.   keyboard input, as in the following example:
  121.  
  122.   ──────────────────────────────────────────────────────────────────────────
  123.   buffer  db     80 dup (?)   ; keyboard input buffer
  124.   fname   db     'CON',0      ; keyboard device name
  125.   handle  dw     0            ; keyboard device handle
  126.           .
  127.           .
  128.           .
  129.           mov    ah,3dh       ; function 3dh = open
  130.           mov    al,0         ; mode = read
  131.           mov    dx,seg fname ; DS:DX = device name
  132.           mov    ds,dx
  133.           mov    dx,offset fname
  134.           int    21h          ; transfer to MS-DOS
  135.           jc     error        ; jump if open failed
  136.           mov    handle,ax    ; save handle for CON
  137.           .
  138.           .
  139.           .
  140.           mov    ah,3fh       ; function 3fh = read file or device
  141.           mov    bx,handle    ; BX = handle for CON
  142.           mov    cx,80        ; maximum bytes to read
  143.           mov    dx,offset buffer ; DS:DX = buffer address
  144.           int    21h          ; transfer to MS-DOS
  145.           jc     error        ; jump if error detected
  146.           .
  147.           .
  148.           .
  149.   ──────────────────────────────────────────────────────────────────────────
  150.  
  151.   When a programmer uses Int 21H Function 3FH to read from the keyboard, the
  152.   exact result depends on whether MS-DOS regards the handle to be in ASCII
  153.   mode or binary mode (sometimes known as cooked mode and raw mode). ASCII
  154.   mode is the default, although binary mode can be selected with Int 21H
  155.   Function 44H (IOCTL) when necessary.
  156.  
  157.   In ASCII mode, MS-DOS initially places characters obtained from the
  158.   keyboard in a 128-byte internal buffer, and the user can edit the input
  159.   with the Backspace key and the special function keys. MS-DOS automatically
  160.   echoes the characters to the standard output, expanding tab characters to
  161.   spaces (although they are left as the ASCII code 09H in the buffer). The
  162.   Ctrl-C, Ctrl-S, and Ctrl-P key combinations receive special handling, and
  163.   the Enter key is translated to a carriage return─linefeed pair. When the
  164.   user presses Enter or Ctrl-Z, MS-DOS copies the requested number of
  165.   characters (or the actual number of characters entered, if less than the
  166.   number requested) out of the internal buffer into the calling program's
  167.   buffer.
  168.  
  169.   In binary mode, MS-DOS never echoes input characters. It passes the
  170.   Ctrl-C, Ctrl-S, Ctrl-P, and Ctrl-Z key combinations and the Enter key
  171.   through to the application unchanged, and Int 21H Function 3FH does not
  172.   return control to the application until the exact number of characters
  173.   requested has been received.
  174.  
  175.   Ctrl-C checking is discussed in more detail at the end of this chapter.
  176.   For now, simply note that the application programmer can substitute a
  177.   custom handler for the default MS-DOS Ctrl-C handler and thereby avoid
  178.   having the application program lose control of the machine when the user
  179.   enters a Ctrl-C or Ctrl-Break.
  180.  
  181. Keyboard Input with Traditional Calls
  182.  
  183.   The MS-DOS traditional keyboard functions offer a variety of character and
  184.   line-oriented services with or without echo and Ctrl-C detection. These
  185.   functions are summarized on the following page.
  186.  
  187.   Int 21H Function   Action                               Ctrl-C checking
  188.   ──────────────────────────────────────────────────────────────────────────
  189.   01H               Keyboard input with echo             Yes
  190.   06H               Direct console I/O                   No
  191.   07H               Keyboard input without echo          No
  192.   08H               Keyboard input without echo          Yes
  193.   0AH               Buffered keyboard input              Yes
  194.   0BH               Input-status check                   Yes
  195.   0CH               Input-buffer reset and input         Varies
  196.   ──────────────────────────────────────────────────────────────────────────
  197.  
  198.   In MS-DOS versions 2.0 and later, redirection of the standard input
  199.   affects all these functions. In other words, they act as though they were
  200.   special cases of an Int 21H Function 3FH call using the predefined
  201.   standard input handle (0).
  202.  
  203.   The character-input functions (01H, 06H, 07H, and 08H) all return a
  204.   character in the AL register. For example, the following sequence waits
  205.   until a key is pressed and then returns it in AL:
  206.  
  207.   ──────────────────────────────────────────────────────────────────────────
  208.           mov     ah,1        ; function 01h = read keyboard
  209.           int     21h         ; transfer to MS-DOS
  210.   ──────────────────────────────────────────────────────────────────────────
  211.  
  212.   The character-input functions differ in whether the input is echoed to the
  213.   screen and whether they are sensitive to Ctrl-C interrupts. Although
  214.   MS-DOS provides no pure keyboard-status function that is immune to Ctrl-C,
  215.   a program can read keyboard status (somewhat circuitously) without
  216.   interference by using Int 21H Function 06H. Extended keys, such as the
  217.   IBM PC keyboard's special function keys, require two calls to a
  218.   character-input function.
  219.  
  220.   As an alternative to single-character input, a program can use
  221.   buffered-line input (Int 21H Function 0AH) to obtain an entire line from
  222.   the keyboard in one operation. MS-DOS builds up buffered lines in an
  223.   internal buffer and does not pass them to the calling program until the
  224.   user presses the Enter key. While the line is being entered, all the usual
  225.   editing keys are active and are handled by the MS-DOS keyboard driver. You
  226.   use Int 21H Function 0AH as follows:
  227.  
  228.   ──────────────────────────────────────────────────────────────────────────
  229.   buff    db      81          ; maximum length of input
  230.           db      0           ; actual length (from MS-DOS)
  231.           db      81 dup (0)  ; receives keyboard input
  232.           .
  233.           .
  234.           .
  235.           mov     ah,0ah      ; function 0ah = read buffered line
  236.           mov     dx,seg buff ; DS:DX = buffer address
  237.           mov     ds,dx
  238.           mov     dx,offset buff
  239.           int     21h         ; transfer to MS-DOS
  240.           .
  241.           .
  242.           .
  243.   ──────────────────────────────────────────────────────────────────────────
  244.  
  245.   Int 21H Function 0AH differs from Int 21H Function 3FH in several
  246.   important ways. First, the maximum length is passed in the first byte of
  247.   the buffer, rather than in the CX register. Second, the actual length is
  248.   returned in the second byte of the structure, rather than in the AX
  249.   register. Finally, when the user has entered one less than the specified
  250.   maximum number of characters, MS-DOS ignores all subsequent characters and
  251.   sounds a warning beep until the Enter key is pressed.
  252.  
  253.   For detailed information about each of the traditional keyboard-input
  254.   functions, see Section II of this book, "MS-DOS Functions Reference."
  255.  
  256. Keyboard Input with ROM BIOS Functions
  257.  
  258.   Programmers writing applications for IBM PC compatibles can bypass the
  259.   MS-DOS keyboard functions and choose from two hardware-dependent
  260.   techniques for keyboard input.
  261.  
  262.   The first method is to call the ROM BIOS keyboard driver using Int 16H.
  263.   For example, the following sequence reads a single character from the
  264.   keyboard input buffer and returns it in the AL register:
  265.  
  266.   ──────────────────────────────────────────────────────────────────────────
  267.           mov    ah,0         ; function 0=read keyboard
  268.           int    16h          ; transfer to ROM BIOS
  269.   ──────────────────────────────────────────────────────────────────────────
  270.  
  271.   Int 16H Function 00H also returns the keyboard scan code in the AH
  272.   register, allowing the program to detect key codes that are not ordinarily
  273.   returned by MS-DOS. Other Int 16H services return the keyboard status
  274.   (that is, whether a character is waiting) or the keyboard shift state
  275.   (from the ROM BIOS data area 0000:0417H). For a more detailed explanation
  276.   of ROM BIOS keyboard functions, see Section III of this book, "IBM ROM
  277.   BIOS and Mouse Functions Reference."
  278.  
  279.   You should consider carefully before building ROM BIOS dependence into an
  280.   application. Although this technique allows you to bypass any I/O
  281.   redirection that may be in effect, ways exist to do this without
  282.   introducing dependence on the ROM BIOS. And there are real disadvantages
  283.   to calling the ROM BIOS keyboard driver:
  284.  
  285.   ■  It always bypasses I/O redirection, which sometimes may not be
  286.      desirable.
  287.  
  288.   ■  It is dependent on IBM PC compatibility and does not work correctly,
  289.      unchanged, on some older machines such as the Hewlett-Packard
  290.      TouchScreen or the Wang Professional Computer.
  291.  
  292.   ■  It may introduce complicated interactions with TSR utilities.
  293.  
  294.   The other and more hardware-dependent method of keyboard input on an IBM
  295.   PC is to write a new handler for ROM BIOS Int 09H and service the keyboard
  296.   controller's interrupts directly. This involves translation of scan codes
  297.   to ASCII characters and maintenance of the type-ahead buffer. In ordinary
  298.   PC applications, there is no reason to take over keyboard I/O at this
  299.   level; therefore, I will not discuss this method further here. If you are
  300.   curious about the techniques that would be required, the best reference is
  301.   the listing for the ROM BIOS Int 09H handler in the IBM PC or PC/AT
  302.   technical reference manual.
  303.  
  304.  
  305. Ctrl-C and Ctrl-Break Handlers
  306.  
  307.   In the discussion of keyboard input with the MS-DOS handle and traditional
  308.   functions, I made some passing references to the fact that Ctrl-C entries
  309.   can interfere with the expected behavior of those functions. Let's look at
  310.   this subject in more detail now.
  311.  
  312.   During most character I/O operations, MS-DOS checks for a Ctrl-C (ASCII
  313.   code 03H) waiting at the keyboard and executes an Int 23H if one is
  314.   detected. If the system break flag is on, MS-DOS also checks for a Ctrl-C
  315.   entry during certain other operations (such as file reads and writes).
  316.   Ordinarily, the Int 23H vector points to a routine that simply terminates
  317.   the currently active process and returns control to the parent process──
  318.   usually the MS-DOS command interpreter.
  319.  
  320.   In other words, if your program is executing and you enter a Ctrl-C,
  321.   accidentally or intentionally, MS-DOS simply aborts the program. Any files
  322.   the program has opened using file control blocks will not be closed
  323.   properly, any interrupt vectors it has altered may not be restored
  324.   correctly, and if it is performing any direct I/O operations (for example,
  325.   if it contains an interrupt driver for the serial port), all kinds of
  326.   unexpected events may occur.
  327.  
  328.   Although you can use a number of partially effective methods to defeat
  329.   Ctrl-C checking, such as performing keyboard input with Int 21H Functions
  330.   06H and 07H, placing all character devices into binary mode, or turning
  331.   off the system break flag with Int 21H Function 33H, none of these is
  332.   completely foolproof. The simplest and most elegant way to defeat Ctrl-C
  333.   checking is simply to substitute your own Int 23H handler, which can take
  334.   some action appropriate to your program. When the program terminates,
  335.   MS-DOS automatically restores the previous contents of the Int 23H vector
  336.   from information saved in the program segment prefix. The following
  337.   example shows how to install your own Ctrl-C handler (which in this case
  338.   does nothing at all):
  339.  
  340.   ──────────────────────────────────────────────────────────────────────────
  341.           push    ds          ; save data segment
  342.                               ; set int 23h vector...
  343.           mov     ax,2523h    ; function 25h = set interrupt
  344.                               ; int 23h = vector for
  345.                               ; Ctrl-C handler
  346.           mov     dx,seg handler ; DS:DX = handler address
  347.           mov     ds,dx
  348.           mov     dx,offset handler
  349.           int     21h         ; transfer to MS-DOS
  350.  
  351.           pop     ds          ; restore data segment
  352.           .
  353.           .
  354.           .
  355.   handler:                    ; a Ctrl-C handler
  356.           iret                ; that does nothing
  357.   ──────────────────────────────────────────────────────────────────────────
  358.  
  359.   The first part of the code (which alters the contents of the Int 23H
  360.   vector) would be executed in the initialization part of the application.
  361.   The handler receives control whenever MS-DOS detects a Ctrl-C at the
  362.   keyboard. (Because this handler consists only of an interrupt return, the
  363.   Ctrl-C will remain in the keyboard input stream and will be passed to the
  364.   application when it requests a character from the keyboard, appearing on
  365.   the screen as ^C.)
  366.  
  367.   When an Int 23H handler is called, MS-DOS is in a stable state. Thus, the
  368.   handler can call any MS-DOS function. It can also reset the segment
  369.   registers and the stack pointer and transfer control to some other point
  370.   in the application without ever returning control to MS-DOS with an IRET.
  371.  
  372.   On IBM PC compatibles, an additional interrupt handler must be taken into
  373.   consideration. Whenever the ROM BIOS keyboard driver detects the key
  374.   combination Ctrl-Break, it calls a handler whose address is stored in the
  375.   vector for Int 1BH. The default ROM BIOS Int 1BH handler does nothing.
  376.   MS-DOS alters the Int 1BH vector to point to its own handler, which sets a
  377.   flag and returns; the net effect is to remap the Ctrl-Break into a Ctrl-C
  378.   that is forced ahead of any other characters waiting in the keyboard
  379.   buffer.
  380.  
  381.   Taking over the Int 1BH vector in an application is somewhat tricky but
  382.   extremely useful. Because the keyboard is interrupt driven, a press of
  383.   Ctrl-Break lets the application regain control under almost any
  384.   circumstance──often, even if the program has crashed or is in an endless
  385.   loop.
  386.  
  387.   You cannot, in general, use the same handler for Int 1BH that you use for
  388.   Int 23H. The Int 1BH handler is more limited in what it can do, because it
  389.   has been called as a result of a hardware interrupt and MS-DOS may have
  390.   been executing a critical section of code at the time the interrupt was
  391.   serviced. Thus, all registers except CS:IP are in an unknown state; they
  392.   may have to be saved and then modified before your interrupt handler can
  393.   execute. Similarly, the depth of the stack in use when the Int 1BH handler
  394.   is called is unknown, and if the handler is to perform stack-intensive
  395.   operations, it may have to save the stack segment and the stack pointer
  396.   and switch to a new stack that is known to have sufficient depth.
  397.  
  398.   In normal application programs, you should probably avoid retaining
  399.   control in an Int 1BH handler, rather than performing an IRET. Because of
  400.   subtle differences among non-IBM ROM BIOSes, it is difficult to predict
  401.   the state of the keyboard controller and the 8259 Programmable Interrupt
  402.   Controller (PIC) when the Int 1BH handler begins executing. Also, MS-DOS
  403.   itself may not be in a stable state at the point of interrupt, a situation
  404.   that can manifest itself in unexpected critical errors during subsequent
  405.   I/O operations. Finally, MS-DOS versions 3.2 and later allocate a stack
  406.   from an internal pool for use by the Int 09H handler. If the Int 1BH
  407.   handler never returns, the Int 09H handler never returns either, and
  408.   repeated entries of Ctrl-Break will eventually exhaust the stack pool,
  409.   halting the system.
  410.  
  411.   Because Int 1BH is a ROM BIOS interrupt and not an MS-DOS interrupt,
  412.   MS-DOS does not restore the previous contents of the Int 1BH vector when a
  413.   program exits. If your program modifies this vector, it must save the
  414.   original value and restore it before terminating. Otherwise, the vector
  415.   will be left pointing to some random area in the next program that runs,
  416.   and the next time the user presses Ctrl-Break a system crash is the best
  417.   you can hope for.
  418.  
  419. Ctrl-C and Ctrl-Break Handlers and High-Level Languages
  420.  
  421.   Capturing the Ctrl-C and Ctrl-Break interrupts is straightforward when you
  422.   are programming in assembly language. The process is only slightly more
  423.   difficult with high-level languages, as long as you have enough
  424.   information about the language's calling conventions that you can link in
  425.   a small assembly-language routine as part of the program.
  426.  
  427.   The BREAK.ASM listing in Figure 5-1 contains source code for a Ctrl-Break
  428.   handler that can be linked with small-model Microsoft C programs running
  429.   on an IBM PC compatible. The short C program in Figure 5-2 demonstrates
  430.   use of the handler. (This code should be readily portable to other C
  431.   compilers.)
  432.  
  433.   ──────────────────────────────────────────────────────────────────────────
  434.           page    5s,132
  435.           title   Ctrl-C & Ctrl-Break Handlers
  436.           name    break
  437.  
  438.   ;
  439.   ; Ctrl-C and Ctrl-Break handler for Microsoft C
  440.   ; programs running on IBM PC compatibles
  441.   ;
  442.   ; by Ray Duncan
  443.   ;
  444.   ; Assemble with:  C>MASM /Mx BREAK;
  445.   ;
  446.   ; This module allows C programs to retain control
  447.   ; when the user enters a Ctrl-Break or Ctrl-C.
  448.   ; It uses Microsoft C parameter-passing conventions
  449.   ; and assumes the C small memory model.
  450.   ;
  451.   ; The procedure _capture is called to install
  452.   ; a new handler for the Ctrl-C and Ctrl-Break
  453.   ; interrupts (1bh and 23h).  _capture is passed
  454.   ; the address of a static variable, which will be
  455.   ; set to true by the handler whenever a Ctrl-C
  456.   ; or Ctrl-Break is detected.  The C syntax is:
  457.   ;
  458.   ;               static int flag;
  459.   ;               capture(&flag);
  460.   ;
  461.   ; The procedure _release is called by the C program
  462.   ; to restore the original Ctrl-Break and Ctrl-C
  463.   ; handler. The C syntax is:
  464.   ;               release();
  465.   ;
  466.   ; The procedure ctrlbrk is the actual interrupt
  467.   ; handler.  It receives control when a software
  468.   ; int 1bh is executed by the ROM BIOS or int 23h
  469.   ; is executed by MS-DOS.  It simply sets the C
  470.   ; program's variable to true (1) and returns.
  471.   ;
  472.  
  473.   args    equ     4               ; stack offset of arguments,
  474.                                   ; C small memory model
  475.  
  476.   cr      equ     0dh             ; ASCII carriage return
  477.   lf      equ     0ah             ; ASCII linefeed
  478.  
  479.   _TEXT   segment word public 'CODE'
  480.  
  481.           assume cs:_TEXT
  482.  
  483.  
  484.           public  _capture
  485.   _capture proc   near            ; take over Ctrl-Break
  486.                                   ; and Ctrl-C interrupt vectors
  487.  
  488.           push    bp              ; set up stack frame
  489.           mov     bp,sp
  490.  
  491.           push    ds              ; save registers
  492.           push    di
  493.           push    si
  494.  
  495.                                   ; save address of
  496.                                   ; calling program's "flag"
  497.           mov     ax,word ptr [bp+args]
  498.           mov     word ptr cs:flag,ax
  499.           mov     word ptr cs:flag+2,ds
  500.  
  501.                                   ; save address of original
  502.           mov     ax,3523h        ; int 23h handler
  503.           int     21h
  504.           mov     word ptr cs:int23,bx
  505.           mov     word ptr cs:int23+2,es
  506.           mov     ax,351bh        ; save address of original
  507.           int     21h             ; int 1bh handler
  508.           mov     word ptr cs:int1b,bx
  509.           mov     word ptr cs:int1b+2,es
  510.           push    cs              ; set DS:DX = address
  511.           pop     ds              ; of new handler
  512.           mov     dx,offset _TEXT:ctrlbrk
  513.  
  514.           mov     ax,02523h       ; set int 23h vector
  515.           int     21h
  516.  
  517.           mov     ax,0251bh       ; set int 1bh vector
  518.           int     21h
  519.  
  520.           pop     si              ; restore registers
  521.           pop     di
  522.           pop     ds
  523.  
  524.           pop     bp              ; discard stack frame
  525.           ret                     ; and return to caller
  526.  
  527.   _capture endp
  528.  
  529.  
  530.           public  _release
  531.   _release proc   near            ; restore original Ctrl-C
  532.                                   ; and Ctrl-Break handlers
  533.  
  534.           push    bp              ; save registers
  535.           push    ds
  536.           push    di
  537.           push    si
  538.  
  539.           lds     dx,cs:int1b     ; get address of previous
  540.                                   ; int 1bh handler
  541.  
  542.           mov     ax,251bh        ; set int 1bh vector
  543.           int     21h
  544.  
  545.           lds     dx,cs:int23     ; get address of previous
  546.                                   ; int 23h handler
  547.  
  548.           mov     ax,2523h        ; set int 23h vector
  549.           int     21h
  550.  
  551.           pop     si              ; restore registers
  552.           pop     di              ; and return to caller
  553.           pop     ds
  554.           pop     bp
  555.           ret
  556.   release endp
  557.  
  558.   ctrlbrk proc    far             ; Ctrl-C and Ctrl-Break
  559.                                   ; interrupt handler
  560.  
  561.           push    bx              ; save registers
  562.           push    ds
  563.  
  564.           lds     bx,cs:flag      ; get address of C program's
  565.                                   ; "flag variable"
  566.  
  567.                                   ; and set the flag "true"
  568.           mov     word ptr ds:[bx],1
  569.  
  570.           pop     ds              ; restore registers
  571.           pop     bx
  572.  
  573.           iret                    ; return from handler
  574.  
  575.   ctrlbrk endp
  576.  
  577.   flag    dd      0               ; far pointer to caller's
  578.                                   ; Ctrl-Break or Ctrl-C flag
  579.  
  580.   int23   dd      0               ; address of original
  581.                                   ; Ctrl-C handler
  582.  
  583.   int1b   dd      0               ; address of original
  584.                                   ; Ctrl-Break handler
  585.  
  586.   _TEXT   ends
  587.  
  588.           end
  589.   ──────────────────────────────────────────────────────────────────────────
  590.  
  591.   Figure 5-1.  BREAK.ASM: A Ctrl-C and Ctrl-Break interrupt handler that can
  592.   be linked with Microsoft C programs.
  593.  
  594.   ──────────────────────────────────────────────────────────────────────────
  595.   /*
  596.       TRYBREAK.C
  597.  
  598.       Demo of BREAK.ASM Ctrl-Break and Ctrl-C
  599.       interrupt handler, by Ray Duncan
  600.  
  601.       To create the executable file TRYBREAK.EXE, enter:
  602.  
  603.       MASM /Mx BREAK;
  604.       CL TRYBREAK.C BREAK.OBJ
  605.   */
  606.  
  607.   #include <stdio.h>
  608.  
  609.   main(int argc, char *argv[])
  610.   {
  611.       int hit = 0;                     /* flag for key press      */
  612.       int c = 0;                       /* character from keyboard */
  613.       static int flag = 0;             /* true if Ctrl-Break
  614.                                           or Ctrl-C detected      */
  615.  
  616.       puts("\n*** TRYBREAK.C running ***\n");
  617.       puts("Press Ctrl-C or Ctrl-Break to test handler,");
  618.       puts("Press the Esc key to exit TRYBREAK.\n");
  619.  
  620.       capture(&flag);                  /* install new Ctrl-C and
  621.                                           Ctrl-Break handler and
  622.                                           pass address of flag    */
  623.  
  624.       puts("TRYBREAK has captured interrupt vectors.\n");
  625.  
  626.       while(1)
  627.       {
  628.           hit = kbhit();               /* check for key press     */
  629.                                        /* (MS-DOS sees Ctrl-C
  630.                                            when keyboard polled)  */
  631.  
  632.           if(flag != 0)                /* if flag is true, an     */
  633.           {                            /* interrupt has occurred  */
  634.               puts("\nControl-Break detected.\n");
  635.               flag = 0;                /* reset interrupt flag    */
  636.           }
  637.           if(hit != 0)                 /* if any key waiting      */
  638.           {
  639.               c = getch();             /* read key, exit if Esc   */
  640.               if( (c & 0x7f) == 0x1b) break;
  641.               putch(c);                /* otherwise display it    */
  642.           }
  643.       }
  644.       release();                       /* restore original Ctrl-C
  645.                                           and Ctrl-Break handlers */
  646.  
  647.       puts("\n\nTRYBREAK has released interrupt vectors.");
  648.   }
  649.   ──────────────────────────────────────────────────────────────────────────
  650.  
  651.   Figure 5-2.  TRYBREAK.C: A simple Microsoft C program that demonstrates
  652.   use of the interrupt handler BREAK.ASM from Figure 5-1.
  653.  
  654.   In the example handler, the procedure named capture is called with the
  655.   address of an integer variable within the C program. It saves the address
  656.   of the variable, points the Int 1BH and Int 23H vectors to its own
  657.   interrupt handler, and then returns.
  658.  
  659.   When MS-DOS detects a Ctrl-C or Ctrl-Break, the interrupt handler sets the
  660.   integer variable within the C program to true (1) and returns. The C
  661.   program can then poll this variable at its leisure. Of course, to detect
  662.   more than one Ctrl-C, the program must reset the variable to zero again.
  663.  
  664.   The procedure named release simply restores the Int 1BH and Int 23H
  665.   vectors to their original values, thereby disabling the interrupt handler.
  666.   Although it is not strictly necessary for release to do anything about Int
  667.   23H, this action does give the C program the option of restoring the
  668.   default handler for Int 23H without terminating.
  669.  
  670.  
  671. Pointing Devices
  672.  
  673.   Device drivers for pointing devices are supplied by the hardware
  674.   manufacturer and are loaded with a DEVICE statement in the CONFIG.SYS
  675.   file. Although the hardware characteristics of the available pointing
  676.   devices differ greatly, nearly all of their drivers present the same
  677.   software interface to application programs: the Int 33H protocol used by
  678.   the Microsoft Mouse driver. Version 6 of the Microsoft Mouse driver (which
  679.   was current as this was written) offers the following functions:
  680.  
  681.  
  682.   Function           Meaning
  683.   ──────────────────────────────────────────────────────────────────────────
  684.   00H               Reset mouse and get status.
  685.   01H               Show mouse pointer.
  686.   02H               Hide mouse pointer.
  687.   03H               Get button status and pointer position.
  688.   04H               Set pointer position.
  689.   05H               Get button-press information.
  690.   06H               Get button-release information.
  691.   07H               Set horizontal limits for pointer.
  692.   08H               Set vertical limits for pointer.
  693.   09H               Set graphics pointer type.
  694.   0AH               Set text pointer type.
  695.   0BH               Read mouse-motion counters.
  696.   0CH               Install interrupt handler for mouse events.
  697.   0DH               Turn on light pen emulation.
  698.   0EH               Turn off light pen emulation.
  699.   0FH               Set mickeys to pixel ratio.
  700.   10H               Set pointer exclusion area.
  701.   13H               Set double-speed threshold.
  702.   14H               Swap mouse-event interrupt routines.
  703.   15H               Get buffer size for mouse-driver state.
  704.   16H               Save mouse-driver state.
  705.   17H               Restore mouse-driver state.
  706.   18H               Install alternate handler for mouse events.
  707.   19H               Get address of alternate handler.
  708.   1AH               Set mouse sensitivity.
  709.   1BH               Get mouse sensitivity.
  710.   1CH               Set mouse interrupt rate.
  711.   1DH               Select display page for pointer.
  712.   1EH               Get display page for pointer.
  713.   1FH               Disable mouse driver.
  714.   20H               Enable mouse driver.
  715.   21H               Reset mouse driver.
  716.   22H               Set language for mouse-driver messages.
  717.   23H               Get language number.
  718.   24H               Get driver version, mouse type, and IRQ number.
  719.   ──────────────────────────────────────────────────────────────────────────
  720.  
  721.  
  722.   Although this list of mouse functions may appear intimidating, the average
  723.   application will only need a few of them.
  724.  
  725.   A program first calls Int 33H Function 00H to initialize the mouse driver
  726.   for the current display mode and to check its status. At this point, the
  727.   mouse is "alive" and the application can obtain its state and position;
  728.   however, the pointer does not become visible until the process calls Int
  729.   33H Function 01H.
  730.  
  731.   The program can then call Int 33H Functions 03H, 05H, and 06H to
  732.   monitor the mouse position and the status of the mouse buttons.
  733.   Alternatively, the program can register an interrupt handler for mouse
  734.   events, using Int 33H Function 0CH. This latter technique eliminates the
  735.   need to poll the mouse driver; the driver will notify the program by
  736.   calling the interrupt handler whenever the mouse is moved or a button is
  737.   pressed or released.
  738.  
  739.   When the application is finished with the mouse, it can call Int 33H
  740.   Function 02H to hide the mouse pointer. If the program has registered an
  741.   interrupt handler for mouse events, it should disable further calls to the
  742.   handler by resetting the mouse driver again with Int 33H Function 00H.
  743.  
  744.   For a complete description of the mouse-driver functions, see Section
  745.   III of this book, "IBM ROM BIOS and Mouse Functions Reference." Figure
  746.   5-3 shows a small demonstration program that polls the mouse continually,
  747.   to display its position and status.
  748.  
  749.   ──────────────────────────────────────────────────────────────────────────
  750.   /*
  751.       Simple Demo of Int 33H Mouse Driver
  752.       (C) 1988 Ray Duncan
  753.  
  754.       Compile with: CL MOUDEMO.C
  755.   */
  756.  
  757.   #include <stdio.h>
  758.   #include <dos.h>
  759.  
  760.   union REGS regs;
  761.  
  762.   void cls(void);                     /* function prototypes       */
  763.   void gotoxy(int, int);
  764.  
  765.   main(int argc, char *argv[])
  766.   {
  767.       int x,y,buttons;                /* some scratch variables    */
  768.                                       /* for the mouse state       */
  769.  
  770.       regs.x.ax = 0;                  /* reset mouse driver        */
  771.       int86(0x33, ®s, ®s);      /* and check status          */
  772.  
  773.       if(regs.x.ax == 0)              /* exit if no mouse          */
  774.       {   printf("\nMouse not available\n");
  775.           exit(1);
  776.       }
  777.  
  778.       cls();                          /* clear the screen          */
  779.       gotoxy(45,0);                   /* and show help info        */
  780.       puts("Press Both Mouse Buttons To Exit");
  781.  
  782.       regs.x.ax = 1;                  /* display mouse cursor      */
  783.       int86(0x33, ®s, ®s);
  784.  
  785.       do {
  786.           regs.x.ax = 3;              /* get mouse position        */
  787.           int86(0x33, ®s, ®s);  /* and button status         */
  788.           buttons = regs.x.bx & 3;
  789.           x = regs.x.cx;
  790.           y = regs.x.dx;
  791.           gotoxy(0,0);                 /* display mouse position    */
  792.           printf("X = %3d  Y = %3d", x, y);
  793.  
  794.       } while(buttons != 3);           /* exit if both buttons down */
  795.  
  796.       regs.x.ax = 2;                   /* hide mouse cursor         */
  797.       int86(0x33, ®s, ®s);
  798.  
  799.       cls();                           /* display message and exit  */
  800.       gotoxy(0,0);
  801.       puts("Have a Mice Day!");
  802.   }
  803.  
  804.   /*
  805.       Clear the screen
  806.   */
  807.   void cls(void)
  808.   {
  809.       regs.x.ax = 0x0600;              /* ROM BIOS video driver     */
  810.       regs.h.bh = 7;                   /* int 10h function 06h      */
  811.       regs.x.cx = 0;                   /* initializes a window      */
  812.       regs.h.dh = 24;
  813.       regs.h.dl = 79;
  814.       int86(0x10, ®s, ®s);
  815.   }
  816.  
  817.   /*
  818.       Position cursor to (x,y)
  819.   */
  820.   void gotoxy(int x, int y)
  821.   {
  822.       regs.h.dl = x;                   /* ROM BIOS video driver     */
  823.       regs.h.dh = y;                   /* int 10h function 02h      */
  824.       regs.h.bh = 0;                   /* positions the cursor      */
  825.       regs.h.ah = 2;
  826.       int86(0x10, ®s, ®s);
  827.   }
  828.   ──────────────────────────────────────────────────────────────────────────
  829.  
  830.   Figure 5-3.  MOUDEMO.C: A simple Microsoft C program that polls the mouse
  831.   and continually displays the coordinates of the mouse pointer in the upper
  832.   left corner of the screen. The program uses the ROM BIOS video driver,
  833.   which is discussed in Chapter 6, to clear the screen and position the
  834.   text cursor.
  835.  
  836.  
  837.  
  838.