1bbc ; SPTSR Screen saver / Time display for Sequencer Plus ; .MODEL TINY .386 .CODE ORG 100h start: jmp main ;**************************** Resident data scan db ? refresh_st db 0 screen dd 0b8000000h org_int9 dd ? bg_save db 10 dup (?) time_str db ' ', 1fh, ' ', 1fh, ':', 1fh, ' ', 1fh, ' ', 1fh time_st db 0 ;**************************** NewInt9 -- New INT9 (key-press) proc. write_screen PROC NEAR les di, screen mov cx, 5 rep movsw ret write_screen ENDP scr_saver PROC NEAR push bx mov ah, 12h ;Disable/enable screen refresh xor cs:refresh_st, 1 mov al, cs:refresh_st mov bl,36h int 10h pop bx ret scr_saver ENDP store_ascii PROC mov al, bl shr al, 4 ;We want the high BCD nibble... and al, 0fh add al, 030h ; Convert BCD -> ASCII stosb ; Store in time string inc di ; Skip attribute byte mov al, bl and al, 0fh add al, 030h stosb inc di ret store_ascii ENDP show_time PROC pusha push ds push es push cs pop ds xor time_st, 1 jz remove_time mov ah, 02h ;Read real time clock time int 1ah cld push cs pop es mov di, offset time_str mov bl, ch call store_ascii ; Store hours add di, 2 ; Skip over ":" mov bl, cl call store_ascii ; Store minutes mov di, offset bg_save ; Backup screen area to write to push ds lds si, screen mov cx, 5 rep movsw pop ds mov si, offset time_str call write_screen jmp over_remove remove_time: mov si, offset bg_save ; Restore screen call write_screen over_remove: pop es pop ds popa ret show_time ENDP newint9 PROC FAR sti push ax in al, 60h ; Get scancode from keyboard processor cmp al, 03bh ; Check if F1 or F2 jz test_shift cmp al, 03ch jz test_shift jmp no_hotkey test_shift: mov cs:scan, al ; Save scan code push es ; look into BIOS data area sub ax, ax ; (segment 0) to check shift state mov es, ax mov ax, es:[417h] ; Get SHIFT-key flags test ax, 0000000000001000b ; Check if Alt-key pressed pop es jz no_hotkey cli ; Disable interrupts while resetting in al, 61h ; Get current port 61h state or al, 10000000b ; Turn on bit 7 to signal clear keybrd out 61h, al ; Send to port and al, 01111111b ; Turn off bit 7 to signal break out 61h, al ; Send to port cmp cs:scan, 3bh ; Alt-F1 = Show time jnz scr_sav ; Alt-F2 = Screen saver call show_time jmp ready scr_sav: call scr_saver ready: mov al, 20h ; Reset interrupt controller out 20h, al sti ; Reenable interrupts pop ax iret no_hotkey: pop ax ; Recover AX and fall through cli ; Interrupts cleared for service jmp cs:org_int9 ; jump to old Int 09 routine newint9 ENDP ;/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/ Transient Section ;**************************** Transient data header db 'SPTSR v1.0 Time display / Screen saver for Sequencer Plus', 13, 10, '$' hotkeys db 'Alt-F1 = Time display Alt-F2 = Screen saver', 13, 10, 13, 10, '$' uninstalled db 13, 10, 'Un' installed db 'Installed Successfully',13,10,'$' syntax db 'Syntax: SPTSR [/U]',13,10,'$' nomemory db 'Out of memory',13,10,'$' alreadyin db 'Already installed',13,10,'$' notfound db 'Resident copy not found',13,10,'$' cantunload db 'Can''t uninstall',13,10,'$' resname db 'SpTsr ' resseg dw 0 ;**************************** Main -- Main procedure main PROC mov ah, 9 ;Print install message mov dx, offset header int 21h call findres ;Find resident copy mov al, '/' ;Search for slash xor cx, cx ;in command line mov cl, byte ptr cs:[80h] mov di, 81h repne scasb jne nounload ;No slash, don't unload mov dx, offset syntax ;DX = 'Syntax:' string cmp byte ptr[di], 'U' ;/U or /u, unload je unload cmp byte ptr[di], 'u' je unload cmp byte ptr[di], '?' ;/?, print syntax je error nounload: mov dx, offset alreadyin ;Point DX to error string cmp resseg, 0 ;Already installed? jne error cld ;Clear direction flag mov ax, offset lastbyte ;AX = last byte + 256 inc ah cmp ax, sp ;Check for too little memory jbe memOK mov dx, offset nomemory ;Print 'Out of memory' string error: mov ah, 9 int 21h mov ax, 4C01h ;Exit with error int 21h memOK: mov sp, ax ;Shrink stack jmp load ;Jump to Load procedure main ENDP ;**************************** Load -- TSR loader procedure load PROC mov ah,49h ;Free environment segment mov es, cs:[2Ch] int 21h mov ax, 3509h ;Get and store old INT9 address int 21h mov word ptr[org_int9], bx mov word ptr[org_int9+2], es mov ax, 2509h ;Set new INT16 handler mov dx, offset newint9 int 21h mov ax, cs ;ES = MCB segment (CS - 1) dec ax mov es, ax mov si, offset resname ;Change resident name mov di, 8 mov cx, di rep movsb mov ah, 9 mov dx, offset hotkeys ;Print hot-key text int 21h mov ah, 9 ;Print 'Installed' string mov dx, offset installed int 21h mov dx, offset header ;Last byte of program lastbyte: int 27h ;DOS TSR service load ENDP ;**************************** Unload -- Uninstall procedure unload PROC mov cx, resseg ;CX = resident segment mov dx, offset notfound ;Point DX to error string test cx, cx ;Make sure it's in memory je error mov dx, offset cantunload ;Point DX to error string mov ax, 3509h ;Check to make sure that the int 21h ;interrupts still point to cmp bx, offset newint9 ;the resident copy... jne error mov es, resseg ;ES = resident segment mov ax, 2509h ;Reset INT9 vector mov dx, word ptr es:[org_int9] mov ds, word ptr es:[org_int9+2] int 21h mov ah, 49h ;Release memory segment int 21h push cs ;DS = CS pop ds mov byte ptr[installed], 'i' ;Fix 'Uninstalled' string mov ah,9 ;Print 'Uninstalled' string mov dx, offset uninstalled int 21h mov ax, 4C00h ;Quit program int 21h unload ENDP ;**************************** FindRes -- Find resident copy findres PROC pusha ;Save registers push es mov ax, 5802h ;Save UMB link status int 21h push ax mov ax, 5803h ;Link UMBs mov bx, 1 int 21h mov ah, 52h ;Get Internal Config Table int 21h sub bx, 2 ;BX = first MCB mov bx, es:[bx] fr_lp: mov es, bx ;ES = MCB segment cmp dword ptr es:[8], 73547053h ;Check for signature je fr_found add bx, es:[3] ;Step to next one inc bx cmp byte ptr es:[0],'Z' ;Last one in chain? jne fr_lp ;Loop back mov bx,-1 ;Return 0 (-1 + 1 = 0) fr_found: inc bx mov resseg, bx ;Return resident segment mov ax, 5803h ;Restore UMB link status pop bx int 21h pop es popa ret findres ENDP END start . 0