home *** CD-ROM | disk | FTP | other *** search
/ Simtel MSDOS 1992 December / simtel1292_SIMTEL_1292_Walnut_Creek.iso / msdos / keyboard / kbuf11.arc / KBUF.ASM next >
Assembly Source File  |  1988-11-19  |  11KB  |  454 lines

  1.  title KBUF -- extend keyboard buffer
  2.  
  3. comment #
  4.  
  5. KBUF version 1.1  Copyright (C) 1988  Mark Adler
  6. All rights reserved.
  7.  
  8. Version history -
  9.  
  10. 1.0     26 May 1988     First public version
  11. 1.1     18 Nov 1988     Added queue stuff call (AH=0FFh)
  12.  
  13. kbuf.com -
  14.  
  15.  kbuf maintains a 127 entry (vs. 15 entry) typeahead buffer.  Also the
  16.  original 15 character buffer is retained so a maximum of 142 characters
  17.  are buffered.
  18.  
  19.  The following assumptions are made about the behavior of the keyboard
  20.  scan and support interrupts:
  21.  
  22.  1. The shift status is a byte stored at location 0:417h.
  23.  
  24.  2. The support routine is not re-entrant.
  25.  
  26.  kbuf also adds a new function to interrupt 16h---if AH is 0FFh, then
  27.  the scan code in DX is put into the queue, behind what is already
  28.  there (i.e., as if it were just typed).  This is different from
  29.  stacking, which puts the keystroke at the front of the queue.  On
  30.  return, AL=0 indicates success, AL=1 indicates failure (no room in
  31.  queue).
  32.  
  33. #
  34.  
  35.  
  36.  
  37. ;
  38. ; Interrupt vector segment definitions.
  39. ;
  40.  
  41. ints segment at 0
  42.  org 4*8h               ;Timer interrupt.
  43. int8 label word
  44.  org 4*9h               ;Scan interrupt.
  45. int9 label word
  46.  org 4*16h              ;Keyboard BIOS interrupt.
  47. int16 label word
  48.  org 417h
  49. KB_FLAG db ?            ;Keyboard shift status.
  50. ints ends
  51.  
  52.  
  53.  
  54. ;
  55. ; Program segment.
  56. ;
  57.  
  58. kbuf segment
  59.  assume CS:kbuf,DS:kbuf,ES:kbuf,SS:kbuf
  60.  
  61.  
  62.  
  63. ;
  64. ; Put data as low as DOS will allow.
  65.  org 5Ch
  66.  
  67. oldtv label dword
  68. oldt dw ?,?             ;Old timer routine address.
  69. oldsv label dword
  70. olds dw ?,?             ;Old keyboard scan routine address.
  71. oldkv label dword
  72. oldk dw ?,?             ;Old keyboard service routine address.
  73.  
  74. ink db ?,?              ;In kcopy--don't call it again.
  75.  
  76. kqs dw ?                ;Queue size in bytes.
  77. kqf dw ?                ;Queue front.
  78. kqr dw ?                ;Queue rear.
  79. kq label word           ;Queue.
  80. kqsz equ 128            ;Queue size in entries plus one.
  81.  
  82.  
  83.  
  84. ;
  85. ; Start of .COM code - jump to installation.
  86.  org 100h
  87. start:
  88.   jmp install
  89.  
  90.   db 13,'KBUF version 1.1  Copyright (C) 1988  Mark Adler',13,10
  91.   db 'All rights reserved.',13,10,'Z'-64
  92.  
  93.   org kq+kqsz*2         ;Start at end of queue.
  94.  
  95.  
  96.  
  97. ;
  98. ; Traps and their subroutines -
  99.  
  100.  assume CS:kbuf,SS:nothing      ;For all traps and subroutines.
  101.  
  102.  
  103.  
  104. timer proc near
  105.  
  106.   assume DS:nothing,ES:nothing
  107.  
  108.         ; save registers.
  109.   push AX
  110.   push BX
  111.   push DI
  112.   push DS
  113.   push ES
  114.  
  115.         ; enqueue keyboard data.
  116.   call kcopy
  117.   assume DS:kbuf,ES:kbuf
  118.  
  119.         ; restore registers and drop to next guy in chain.
  120.   pop ES
  121.   pop DS
  122.   assume DS:nothing,ES:nothing
  123.   pop DI
  124.   pop BX
  125.   pop AX
  126.   jmp oldtv
  127.  
  128. timer endp
  129.  
  130.  
  131.  
  132. kscan proc near
  133.  
  134.   assume DS:nothing,ES:nothing
  135.  
  136.         ; save registers.
  137.   push AX
  138.   push BX
  139.   push DI
  140.   push DS
  141.   push ES
  142.  
  143.         ; call normal service routine.
  144.   pushf                 ;(simulate interrupt)
  145.   call oldsv            ;Call original service routine.
  146.  
  147.         ; enqueue keyboard data.
  148.   call kcopy
  149.   assume DS:kbuf,ES:kbuf
  150.  
  151.         ; restore registers and return from interrupt.
  152.   pop ES
  153.   pop DS
  154.   assume DS:nothing,ES:nothing
  155.   pop DI
  156.   pop BX
  157.   pop AX
  158.   iret
  159.  
  160. kscan endp
  161.  
  162.  
  163.  
  164. ksupp proc near
  165.  
  166.   assume DS:nothing,ES:nothing
  167.  
  168.         ; save registers, set data segment.
  169.   sti                   ;Allow interrupts.
  170.   push BX
  171.   push SI
  172.   push DS
  173.   mov BX,CS             ;Set data segment.
  174.   mov DS,BX
  175.   assume DS:kbuf
  176.  
  177.         ; do function in AH.
  178.   cmp AH,0FFh           ;See if key stuff.
  179.   je kstuff             ;If so, stuff one.
  180.   test AH,AH            ;See if read.
  181.   jz kread              ;If so, wait for key data.
  182.   dec AH                ;See if status.
  183.   jz kstat              ;If so, get status.
  184.   dec AH                ;See if shift status.
  185.   jnz kdone             ;If not, just return.
  186.  
  187.         ; get shift status from original routine.
  188.   sub BX,BX             ;Get shift status in AL.
  189.   mov DS,BX
  190.   assume DS:ints
  191.   mov AL,KB_FLAG
  192.   jmp short kdone       ;Return AX.
  193.   assume DS:kbuf
  194.  
  195.         ; peek at queue for status.
  196.  kstat:
  197.   mov BX,offset kq      ;Point to queue.
  198.   cli                   ;Freeze queue.
  199.   call pkq              ;Get entry if any, set Z.
  200.   sti                   ;Set interrupts back.
  201.  
  202.         ; return, restore registers except AX, F.
  203.   pop DS
  204.   assume DS:nothing
  205.   pop SI
  206.   pop BX
  207.   retf 2                ;Discard flags on stack.
  208.   assume DS:kbuf
  209.  
  210.         ; stuff - try to stuff the scan code in DX.
  211.  kstuff:
  212.   push ES
  213.   push DI
  214.   mov ES,BX             ;Point ES to data area also.
  215.   assume ES:kbuf
  216.   mov BX,offset kq      ;Point to queue.
  217.   mov AX,DX             ;Get code to stuff.
  218.   cli                   ;Freeze queue.
  219.   call enq              ;Enqueue code.
  220.   sti                   ;Unfreeze.
  221.   mov AX,0FF00h         ;Restore AH, zero AL -> ok.
  222.   jnz ksok
  223.    inc AX               ;AL = 1 -> failure (no room to stuff).
  224.  ksok:
  225.   pop DI
  226.   pop ES
  227.   assume ES:nothing
  228.   jmp short kdone
  229.  
  230.         ; read - try to dequeue until successful.
  231.  kread:
  232.   mov BX,offset kq      ;Point to queue.
  233.   cli                   ;Freeze queue.
  234.   call deq              ;Try to get entry.
  235.   sti                   ;Allow scan interrupt.
  236.   jz kread              ;Wait until something there.
  237.  
  238.         ; return, restore registers except AX.
  239.  kdone:
  240.   pop DS
  241.   assume DS:nothing
  242.   pop SI
  243.   pop BX
  244.   iret
  245.  
  246. ksupp endp
  247.  
  248.  
  249.  
  250. kcopy proc near
  251.  
  252.  assume DS:nothing,ES:nothing
  253.  
  254.  ; kcopy - copy data from old queue to new queue.
  255.  ; Hits DS, ES, DI, BX, AX, and F.
  256.  
  257.         ; set up segments.
  258.   mov AX,CS
  259.   mov DS,AX
  260.   mov ES,AX
  261.   assume DS:kbuf,ES:kbuf
  262.  
  263.         ; lock out use of this routine.
  264.   mov AL,1              ;Try to lock out this routine.
  265.   xchg AL,ink           ;(Indivisible operation.)
  266.   test AL,AL            ;See if already locked out.
  267.   jnz nogo              ;If so, do nothing.
  268.  
  269.         ; check for data in old queue.
  270.  kloop:
  271.    mov AH,1             ;See if any data there.
  272.    pushf                ;(Simulate interrupt.)
  273.    call oldkv           ;Call original support routine.
  274.    jz kfin              ;If queue is empty, then done.
  275.    mov BX,offset kq     ;Point to keyboard queue.
  276.    test AX,AX           ;See if Ctrl Break.
  277.    jnz knbrk            ;If not, go on.
  278.  
  279.         ; empty queue on break (before enqueueing 0).
  280.     mov AX,kqsz         ;Queue size.
  281.     call mtq            ;Empty queue.
  282.     sub AX,AX           ;Restore AX.
  283.   knbrk:
  284.  
  285.         ; try to enqueue data.
  286.    cli                  ;Freeze queue.
  287.    call enq             ;Enqueue code.
  288.    sti                  ;Unfreeze.
  289.    jz kfin              ;If failure, leave the code in the old queue.
  290.    mov AH,0             ;Delete the code from the old queue.
  291.    pushf                ;(Simulate interrupt.)
  292.    call oldkv           ;Call original support routine.
  293.    jmp short kloop      ;See if there is more.
  294.  
  295.         ; finished---unlock this routine.
  296. kfin:
  297.  mov ink,0
  298.  
  299.         ; return.
  300. nogo:
  301.  ret
  302.  
  303. kcopy endp
  304.  
  305.  
  306.  
  307. mtq proc near
  308.  
  309.  assume DS:kbuf,ES:kbuf
  310.  
  311.  ; Initialize and empty queue.
  312.  ; ES:BX points to queue, AX is ring size in words.
  313.  ; F, AX, DI hit.
  314.   cld
  315.   lea DI,[BX-6]         ;Point to queue size.
  316.   shl AX,1              ;Convert size to bytes.
  317.   stosw                 ;Set size.
  318.   mov AX,BX             ;Set pointers equal.
  319.   stosw                 ;Set front.
  320.   stosw                 ;Set rear.
  321.   ret
  322.  
  323. mtq endp
  324.  
  325.  
  326.  
  327. enq proc near
  328.  
  329.  assume DS:kbuf,ES:kbuf
  330.  
  331.  ; Put entry in queue if possible.
  332.  ; DS/ES:BX points to queue, AX is value to enqueue.
  333.  ; On return Z reset indicates success, Z set failure.
  334.  ; F, DI hit.
  335.   std                   ;Set reverse direction.
  336.   mov DI,[BX-2]         ;Get rear pointer.
  337.   cmp DI,BX             ;See if pointer will underflow.
  338.   stosw                 ;Store word in queue.
  339.   ja enq1               ;If pointer not underflowed go on.
  340.    add DI,[BX-6]        ;Else, add size of queue in bytes.
  341.  enq1:
  342.   cmp DI,[BX-4]         ;See if queue full.
  343.   je enq2               ;If so, return zero set.
  344.    mov [BX-2],DI        ;Else, update rear pointer.
  345.  enq2:                  ;Zero reset indicates success.
  346.   ret
  347.  
  348. enq endp
  349.  
  350.  
  351.  
  352. deq proc near
  353.  
  354.  assume DS:kbuf,ES:nothing
  355.  
  356.  ; Remove entry from queue if possible.
  357.  ; DS:BX points to queue.
  358.  ; On return Z reset indicates success and AX contains
  359.  ; the queue entry, else Z is set and AX is unchanged.
  360.  ; F, SI hit.
  361.   std                   ;Set reverse direction.
  362.   mov SI,[BX-4]         ;Get front pointer.
  363.   cmp SI,[BX-2]         ;See if queue empty.
  364.   je deq2               ;If so, return zero set.
  365.    cmp SI,BX            ;See if pointer will underflow.
  366.    lodsw                ;Get word from queue.
  367.    ja deq1              ;If pointer not underflowed, go on.
  368.     add SI,[BX-6]       ;Else, add size of queue.
  369.   deq1:
  370.    mov [BX-4],SI        ;Update front pointer.
  371.  deq2:                  ;Zero reset indicates success.
  372.   ret
  373.  
  374. deq endp
  375.  
  376.  
  377.  
  378. pkq proc near
  379.  
  380.  assume DS:kbuf,ES:nothing
  381.  
  382.  ; Peek at entry in queue, if any.
  383.  ; DS:BX points to queue.
  384.  ; On return Z set if queue empty.  Else, AX contains next entry
  385.  ; to be dequeued.  SI, F hit.
  386.   mov SI,[BX-4]         ;Get front pointer.
  387.   cmp SI,[BX-2]         ;See if queue empty.
  388.   lodsw                 ;Get entry (if any).
  389.   ret
  390.  
  391. pkq endp
  392.  
  393.  
  394.  
  395. ;
  396. ; Installation code - all segment registers set.
  397.  
  398. install:
  399.  
  400.  assume CS:kbuf,DS:kbuf,ES:kbuf,SS:kbuf
  401.  
  402.         ; initialize new keyboard queue.
  403.    mov BX,offset kq     ;Point to queue.
  404.    mov AX,kqsz          ;Queue size.
  405.    call mtq             ;Empty queue.
  406.  
  407.         ; initialize flag.
  408.    mov ink,0            ;Not currently in support routine.
  409.  
  410.         ; insert trap in timer interrupt vector.
  411.    sub AX,AX
  412.    mov ES,AX            ;Point to interrupt area.
  413.    assume ES:ints
  414.    cli                  ;Disable interrupts during change.
  415.    mov AX,int8          ;Save old pointer.
  416.    mov oldt,AX
  417.    mov AX,int8+2
  418.    mov oldt+2,AX
  419.    mov int8,offset timer        ;Set new interrupt.
  420.    mov int8+2,CS
  421.  
  422.         ; insert trap in scan interrupt vector.
  423.    mov AX,int9          ;Save old pointer.
  424.    mov olds,AX
  425.    mov AX,int9+2
  426.    mov olds+2,AX
  427.    mov int9,offset kscan        ;Set new interrupt.
  428.    mov int9+2,CS
  429.  
  430.         ; insert trap in keyboard BIOS interrupt vector.
  431.    mov AX,int16         ;Save old pointer.
  432.    mov oldk,AX
  433.    mov AX,int16+2
  434.    mov oldk+2,AX
  435.    mov int16,offset ksupp       ;Set new interrupt.
  436.    mov int16+2,CS
  437.    sti                  ;Interrupts OK now.
  438.  
  439.         ; copy data from old queue to new queue.
  440.    call kcopy
  441.    assume DS:kbuf,ES:kbuf
  442.  
  443.         ; tell DOS to keep the traps in memory and exit.
  444.    mov DX,offset install        ;Amount to keep.
  445.    int 27h              ;Exit and remain resident.
  446.  
  447.  
  448.  
  449. kbuf ends
  450.  
  451.  
  452. end start
  453.  
  454.