home *** CD-ROM | disk | FTP | other *** search
- ;-------------------------------------------------------------------------------
- ;
- ; keywait.asm
- ; ===========
- ;
- ; Waits a few seconds for a keystroke. If ESC is pressed then sets
- ; errorlevel to 27. If a function key F1-F10 is pressed then sets
- ; errorlevel to a value in the range 1-10 corresponding to the function
- ; key. If time expires or any other key is pressed then errorlevel
- ; is set to zero. Can be useful in .CMD files.
- ;
- ; A public domain program by Jon Saxton. Please distribute source
- ; code and not just the object code.
- ;
- ;-------------------------------------------------------------------------------
-
- include os2.inc
-
- COLON equ ':'
- CR equ 0Dh
- LF equ 0Ah
- ETX equ 03h
- ESCk equ 1Bh
- SPACE equ ' '
- TAB equ 9
- F1 equ 59
- F10 equ 68
-
- THREAD_STACK_SIZE equ 512
- THREAD_STACK_OFFSET equ THREAD_STACK_SIZE-2
-
- .model small
-
- .data
-
- keyData KBDKEYINFO <>
-
- ticks dw 10 ;Default number of seconds
- stkPtr dd ?
- org stkPtr
- stkOff dw ?
- stkSeg dw ?
- tid dw ?
- kid dw ?
-
- keyboardInput dd ? ; Keyboard input semaphore
- timeExpired dd ? ; Timer semaphore
-
- semaphoreList dw 2 ; Number of elements
- dw 0
- dw offset keyboardInput
- dw seg keyboardInput
- dw 0
- dw offset timeExpired
- dw seg timeExpired
-
- key dw 0
- blankRet db CR
- blanks db ' '
- timerHandle dd ?
- timerSemHandle dd ?
- timerSemName db '\SEM\TICKER',0
- eventNumber dw -1
- kiMessage db 'Key pressed: exit code '
- toMessage db 'Timed out: exit code '
- msgLen equ $-toMessage
- pointers dw kiMessage,toMessage
-
- .code
- .286C
-
- start:
- mov es,ax ; Point at environment segment
- mov di,bx ; Point at command name
- xor ax,ax
- repne scasb ; Skip to end of command name
- mov cx,0
- skipLeadingBlanks:
- mov al,es:[di] ; Get command-line character
- inc di ; Point at the next one
- or al,al ; Check if anything there
- jz setTicks
- cmp al,SPACE ; Skip leading white space
- je skipLeadingBlanks
- cmp al,TAB
- je skipLeadingBlanks
- convertNumber:
- xor ah,ah
- cmp al,'0'
- jb setTicks
- cmp al,'9'
- ja setTicks
- sub al,'0'
- add cx,cx ;*2
- mov dx,cx
- add cx,cx ;*4
- add cx,cx ;*8
- add cx,dx ;*10
- add cx,ax
- mov al,es:[di]
- inc di
- jmp convertNumber
- setTicks:
- mov ax,cx
- or ax,ax
- jz default
- cmp ax,100
- ja default
- mov ticks,ax
- default:
-
- ; At this point we have analysed the command line and interpreted a single
- ; number as the number of seconds to wait for a keystroke. If the number
- ; of seconds was not specified or is unreasonably large then it has been
- ; forced to a value of 10.
- ;
- ; The next step is to initiate the timer and keyboard threads. This is
- ; real OS/2 stuff.
-
- @DosSemSet keyboardInput ; Set the semaphores which are going
- @DosSemSet timeExpired ; to be used by the two threads
-
- @DosAllocSeg THREAD_STACK_SIZE,stkSeg,0 ; Get a stack
- or ax,ax ; Check that it worked
- jz first
- jmp error100
- first:
- mov ax,THREAD_STACK_OFFSET ; Create the timer thread
- mov stkOff,ax
- @DosCreateThread ticker,tid,[stkPtr]
-
- @DosAllocSeg THREAD_STACK_SIZE,stkSeg,0 ; Get a stack
- or ax,ax ; Check that it worked
- jz second
- jmp error100
- second:
- @DosCreateThread keyin,kid,[stkPtr] ; Create the keyin thread
-
- ; Now wait for one of the two threads to signal an event
-
- @DosMuxSemWait eventNumber,semaphoreList,-1
- mov bx,eventNumber
- add bx,bx
- mov ax,pointers[bx]
- push ds
- push ax
- push msgLen
- push 0
- call far ptr VioWrtTTy
- mov si,offset blanks
- mov ax,' '
- mov [si],ax
- mov ax,key
- call decimal
- @VioWrtTTy blanks,3,0
- @DosExit 1,[key]
-
- error100:
- @DosExit 1,100
-
- ;-----------------------------------------------------------------------------
- ;
- ; Keyboard input handler. Waits for a keystroke and returns a value
- ; in the range 1-10 if a function key was pressed, 27 if the ESC key
- ; was pressed, 0 if anything else was pressed.
- ;
- ;-----------------------------------------------------------------------------
-
- keyin proc
-
- @KbdCharIn keyData,0,0 ; Get character
- mov al,keyData.kbci_chChar
- or al,al ; Extended key code?
- jnz simple ; No, check for ESC etc
- mov al,keyData.kbci_chScan ; Fetch second byte
- cmp al,F1 ; Check for F1 - F10
- jb sig0
- cmp al,F10
- ja sig0
- sub al,F1-1
- jmp sig
- simple:
- cmp al,ESCk ; ESC causes return value
- jz sig ; to be set to 27
- sig0:
- xor al,al
- sig:
- mov byte ptr key,al
- @DosSemClear keyboardInput
- @DosExit 0,0
-
- keyin endp
-
- ;------------------------------------------------------------------------------
- ;
- ; Countdown timer. Displays the number of ticks remaining. Stops
- ; at zero.
- ;
- ;------------------------------------------------------------------------------
-
- ticker proc
-
- @DosCreateSem 1,timerSemHandle,timerSemName
- @DosSemSet [timerSemHandle]
- @DosTimerStart 1000,[timerSemHandle],timerHandle
- tick:
- @DosSemWait [timerSemHandle],-1
- @DosSemSet [timerSemHandle]
- mov si,offset blankRet+1
- mov ax,' '
- mov word ptr [si],ax
- mov ax,ticks
- dec ax
- mov ticks,ax
- pushf
- call decimal ; seconds remaining
- @VioWrtTTY blankRet,4,0
- popf
- jnz tick
- @DosSemClear timeExpired
- ; @DosTimerStop [timerHandle]
- @DosExit 0,0
-
- ticker endp
-
- ;-----------------------------------------------------------------------------
- ;
- ; DECIMAL
- ;
- ; Converts an unsigned decimal number from AX into ASCII in the
- ; buffer addressed by SI.
- ;
- ; Destroys contents of AX, CX, DX
- ;
- ;-----------------------------------------------------------------------------
-
- decimal proc
- xor dx,dx ; Clear high-order 16 bits of dividend
- mov cx,10 ; Load divisor
- div cx ; Quotient to AX, remainder to DX
- or ax,ax ; Test quotient
- jz remain ; If zero then just display the remainder
- push dx ; Otherwise save the remainder while we
- call decimal ; deal with the quotient
- pop dx ; Recover the remainder
- remain:
- add dl,'0' ; Convert remainder to a decimal digit
- mov [si],dl
- inc si
- ret
-
- decimal endp
-
- .stack 160
-
- end start
-