bits 16
org 100h
jmp init.tsr
int1c:
push ds
push ax
push cs
pop ds
call checkdos
jc int1c_e
cmp byte [hotkey_found], 1
jnz int1c_e
call tsrapp
int1c_e:
pop ax
pop ds
iret
int28:
push ds
push ax
push cs
pop ds
call checkdos
jc int28_e
cmp byte [hotkey_found], 1
jnz int28_e
call tsrapp
int28_e:
pop ax
pop ds
iret
checkdos:
push bx
push es
les bx, [InDOS]
mov al, 1
cmp al, byte [es:bx] ;InDos
jb checkdos_e
xor al, al
cmp al, byte [es:bx-1] ;crit-err
jb checkdos_e
checkdos_e:
pop es
pop bx
ret
InDOS dd 0
Orig_isr9 dd 0
in_isr9 db 0
hotkey_found db 0
hotkey_idx dw 0
hotseq db 0x1b
isr9:
push ds
push bx
push ax
push cs
pop ds
in al, 0x60
pushf
cli
call word far [Orig_isr9]
mov ah, [in_isr9]
or ah, [hotkey_found]
jnz isr9_e
inc byte [in_isr9]
cmp al, byte [hotseq]
jz isr9_foundkey
jmp isr9_exit
isr9_foundkey:
mov byte [hotkey_found], 1
isr9_exit:
dec byte [in_isr9]
isr9_e:
pop ax
pop bx
pop ds
iret
tsrapp:
push dx
mov ah, 0x2
mov dl, 0x41
int 0x21
pop dx
ret
pre equ $
init.tsr:
mov ax, 0x3509
int 0x21
mov [Orig_isr9], bx
mov [Orig_isr9+2], es
mov dx, isr9
mov ax, 0x2509
int 0x21
mov dx, int28
mov ax, 0x2528
int 0x21
mov dx, int1c
mov ax, 0x251c
int 0x21
mov ax, 0x3400
int 0x21
mov [InDOS], bx
mov [InDOS+2], es
mov dx, pre
add dx, 0xf
shr dx, 4
mov ax, 0x3100
int 0x21
Whew!!! Are you *sure* you want to delve this deeply into dos? :)
This is beyond me. If I ever knew it, I've forgotten... One thing...
You're checking for 1Bh, the ascii code for the ESCape key. I think, at
this point, what you're going to see is the scancode, not yet translated
to an ascii code (done by lookup table in int 9). I think the scancode
for ESC is 1.
Easy to try, if nothing else...
Best,
Frank
A couple of general things:
- It helps us if you submit commented code
- DOS is not re-entrant (if you aren't checking INDOS then you are
probably going to get in trouble)
- BIOS is not re-entrant
"wolf3y3" wrote:
> I have just got interested in active "pop-up" tsrs,
> and tried for the first time to make one, the code fails...
> Can someone help me to understand whats wrong,
> it is supposed to print a 'A' when the ESC key is pressed.
> What am I missing? What didn't I do right?
> When I remove the check for the hotkey_found it just
> causes the system to crash, I suspect this is because
> I probably didn't check the InDOS flag right...
[...]
it may not be a good idea to use timer event rated checks
on DOS for INKEY ... and ESC may not work as user definable
Hotkey anyway, DOS already made it HOT :)
For a TSR I'd direct hook the keyboard-IRQ and compare against
scan code(make codes only) and pass everthing else to the
original keybord handler. As Frank said: scan code ECS = 1.
But why a TSR for this ?
you could poll 'LastKey' scan code in a loop,
it's found in the 0400h..range (see RBIL for details).
__
wolfgang
I've posted source code to a number of TSRs that I wrote
some years ago:
http://www.scribd.com/doc/11452236/Dsmmonasm
http://www.scribd.com/doc/11451593/DparMonasm
http://www.scribd.com/doc/11448320/Diskmonasm
http://www.scribd.com/doc/11448319/DISKVUASM
http://www.scribd.com/doc/11478779/Fakedrivasm
The closest to what you are talking about is:
http://www.scribd.com/doc/14593795/NEWPRTSCASM
http://www.scribd.com/doc/14593633/EGRPRTSCASM
Now, if you want to explore technology even older
than DOS:
http://www.scribd.com/doc/8090945/RCA-1940-Vacuum-Tube-Design
HTH
Kevin
The code is fairly unintelligible as it stands. In answer to your
question about what you are missing the first thing that springs to
mind is adequate comments. You should document at least what all DOS
functions being called are for and what all your magic constants mean.
It's hard for people to help if they have to look up interrupt
functions and parameters.
I'm not sure if direct reading from port 0x60 is a good idea.
James
Here is a well documented TSR that you can study.
Andy
; saver.asm Com program Modified 6/13/2002 A.K.
;
; Screen saver (blanks screen) COM file..
; Only works in 80x25 screen modes (2,3,7) [could easily be adapted/
others]
; Uses F-8 key to activate, un-install by typing name of
program again
;
; **** ADJUSTABLE time interval to pop up
;
; Program can be
uninstalled
;
;
.SEQ ; store segment sequentially as they appear
.286 ; use 80286+ code
.MODEL tiny ; TINY model to make it a .COM program
;* Macros *
StAlloc MACRO sizew ; macro to allocate stack, size "sizew" words
MOV BX,((sizew*2)+15) SHR 4 ; BX =3D size in paragraphs
MOV AH,48h ; allocate memory function
INT 21h ; call DOS
CLI ; freeze interrupts
MOV SS,AX ; set stack segment to allocated segment returned
in AX
MOV SP,sizew*2-2 ; set stack pointer to end of segment (goes top
down)
STI ; restore interrupts
ENDM
StDeAlloc MACRO ; macro to deallocate stack
MOV AX,SS
MOV ES,AX
MOV AH,49h ; call DOS deallocate block function
INT 21h
ENDM
;* Code Segment *
code SEGMENT PARA PUBLIC 'CODE' ; code segment
ASSUME CS:code, DS:code, ES:code, SS:code ; assume CS->"code" etc.
ORG 100h ; start assembling at offset 0h
(default)
;* Program Start *
start: ; label for start of program
JMP init
;* Procedures *
; Save screen and display (init) screen saver logo
ScreenSaver PROC NEAR
MOV AX,CS
MOV ES,AX
MOV DI,OFFSET ScrData
MOV DS,CS:ScrAddress
XOR SI,SI
CLD
MOV CX,2000
REP MOVSW ; save screen
MOV CS:SSOn,1
MOV AH,0Fh
INT 10h ; get current page in BH
MOV AH,03h
INT 10h ; get old cursor size
MOV CS:OldCursor,CX
MOV AH,01h
MOV CX,0100h
INT 10h ; hide cursor
CALL RunSaver ; clear screen
CALL DrawSaver ; draw logo
RET
ENDP
; Restore screen and deinitialize screen saver
RemoveSaver PROC NEAR
MOV ES,CS:ScrAddress
XOR DI,DI
MOV AX,CS
MOV DS,AX
MOV SI,OFFSET ScrData
CLD
MOV CX,2000
REP MOVSW
MOV CS:SSOn,0
MOV AH,01h
MOV CX,CS:OldCursor
INT 10h ; restore cursor
RET
ENDP
; Re-hide screen to cover any writing
RunSaver PROC NEAR
MOV ES,CS:ScrAddress
XOR DI,DI
MOV CX,2000
XOR AX,AX
REP STOSW
RET
ENDP
; Find parts of screen that were changed and save to virtual screen
DeltaSaver PROC NEAR
CLD
MOV DS,CS:ScrAddress
XOR SI,SI ; DS:SI -> physical screen
MOV AX,CS
MOV ES,AX
MOV DI,OFFSET ScrData ; ES:DI -> virtual screen
XOR BH,BH ; row 0
ds_nextrow:
MOV CX,80
CMP BH,CS:Row
JZ ds_check ; if row of copyright string handle separately
ds_loop:
LODSW
CMP AX,0 ; check if still zero (as set by screen saver)
JZ ds_again
MOV ES:[DI],AX ; set to new value
ds_again:
INC DI
INC DI
LOOP ds_loop
ds_new:
INC BH
CMP BH,25
JNZ ds_nextrow
RET
ds_check:
MOV BP,OFFSET Copyright
MOV BL,CS:Color
ds_loop2:
LODSW
CMP AL,ES:[BP]
JNZ ds_delta
CMP AH,BL
JZ ds_ok
ds_delta:
MOV ES:[DI],AX
ds_ok:
INC DI
INC DI
INC BP
LOOP ds_loop2
JMP SHORT ds_new
ENDP
; Draw copyright string
DrawSaver PROC NEAR
MOV AX,WORD PTR CS:Row2
MOV WORD PTR CS:Row,AX ; now safe to copy incremented data
MOV AH,CS:Row
MOV AL,160
MUL AH
MOV DI,AX
MOV AX,CS
MOV DS,AX
MOV SI,OFFSET CS:Copyright
MOV AH,CS:Color
ds_write:
LODSB
OR AL,AL
JZ ds_donemsg
STOSW
JMP SHORT ds_write
ds_donemsg:
RET
ENDP
; move message and change color
IncSaver PROC NEAR
MOV AX,WORD PTR CS:Row2 ; AL =3D row, AH =3D attribute
ADD AX,101h ; increment both
CMP AL,25
JNZ is_rowset
XOR AL,AL
is_rowset:
CMP AH,16
JNZ is_colset
MOV AH,1
is_colset:
MOV WORD PTR CS:Row2,AX
RET
ENDP
; INT 09h interrupt handler
; checks for hotkey combinations and deinstalls or activates program
if found
Int09Handler PROC FAR
PUSHF
CALL CS:OldInt09 ; call old handler
PUSHA
PUSH DS
PUSH ES
MOV AX,40h
MOV ES,AX
MOV DI,ES:[1Ah]
CMP DI,ES:[1Ch] ; quit if no keys in keyboard buffer
JZ i9_exit
MOV CS:SSTimer,0 ; zero timer for screen saver
CMP CS:SSOn,0
JZ i9_skip
CALL RemoveSaver ; if screen saver active, restore screen
i9_skip:
MOV DI,ES:[DI] ; get key in keyboard buffer
CMP DI,4200h ; check for F8 , zeroes needed after scan code
JNZ i9_exit
PUSH DI
PUSH ES
CALL ScreenSaver ; startup screen saver
POP ES
POP DI
i9_remove:
INC WORD PTR ES:[1Ah]
INC WORD PTR ES:[1Ah] ; remove key from buffer
CMP WORD PTR ES:[1Ah],3Eh
JNZ i9_exit
MOV WORD PTR ES:[1Ah],1Eh ; wrap around if required
i9_exit:
POP ES
POP DS
POPA
IRET
ENDP
; INT 1Ch interrupt handler
; activates screen saver when timeout occurs
Int1CHandler PROC FAR
PUSHF
CALL CS:OldInt1C
PUSHA
PUSH DS
PUSH ES
CMP CS:SSOn,0
JZ i1c_off
CALL DeltaSaver ; store changes to virtual screen
CALL RunSaver ; blank screen
CALL DrawSaver ; draw message or graphic
i1c_off:
MOV AL,CS:Timer1
DEC AL
MOV CS:Timer1,AL
JNZ i1c_exit
MOV AH,18
MOV AL,CS:Timer2
DEC AL
JNZ i1c_not19
INC AH
MOV AL,5
i1c_not19:
MOV CS:Timer2,AL
MOV CS:Timer1,AH
CMP CS:SSOn,0
JZ i1c_count
CALL IncSaver
JMP SHORT i1c_exit
i1c_count:
MOV AX,CS:SSTimer
INC AX
MOV CS:SSTimer,AX
CMP AX,180 ; 3 minutes (min x 60 secs)
JNZ i1c_exit
XOR AX,AX
MOV CS:SSTimer,AX ; set to zero
CALL ScreenSaver ; startup screen saver
i1c_exit:
POP ES
POP DS
POPA
IRET
ENDP
; TSR data
ScrAddress DW 0
OldCursor DW 0
OldInt09 DD 0
OldInt1C DD 0
SSTimer DW 0
SSOn DB 0
Timer1 DB 18
Timer2 DB 5
ScrData DW 2000 DUP (?)
Row DB 0
Color DB 1
Row2 DB 0
Color2 DB 1
Copyright DB '=E8 The Kennedy Family',0
Sig DB 'VXSS'
TSR_end LABEL BYTE
; * Main Program *
init:
MOV AX,CS
MOV DS,AX
MOV ES,AX
MOV BX,OFFSET code_end
ADD BX,15
SHR BX,4
MOV AH,4AH
INT 21H ; free unneeded memory given to
program
StAlloc 50h ; allocate stack (saves memory on
disk)
XOR AX,AX
MOV ES,AX
PUSH DS
MOV DS,ES:[26h]
CMP WORD PTR DS:Sig,'XV'
JNZ i_skip
CMP WORD PTR DS:Sig+2,'SS'
JNZ i_skip
MOV AX,WORD PTR DS:OldInt09
MOV BX,WORD PTR DS:OldInt09+2
CLI
MOV ES:[24h],AX
MOV ES:[26h],BX
MOV AX,WORD PTR DS:OldInt1C
MOV BX,WORD PTR DS:OldInt1C+2
MOV ES:[70h],AX
MOV ES:[72h],BX
STI
MOV AX,DS
MOV ES,AX
MOV AH,49h
INT 21h
POP DS
MOV AH,09h
MOV DX,OFFSET Deinstall
INT 21h
StDeAlloc
MOV AX,4C00h
INT 21h
i_skip:
POP DS
MOV AX,0B800h
CMP BYTE PTR ES:[0449h],7 ; check if current mode @ 0:449 is 7
(mono)
JNZ i_gotmode
MOV AX,0B000h
i_gotmode:
MOV ScrAddress,AX ; store screen address
MOV AX,ES:[24h]
MOV BX,ES:[26h]
MOV WORD PTR OldInt09,AX
MOV WORD PTR OldInt09+2,BX ; save old interrupt 09h
MOV AX,OFFSET Int09Handler
MOV BX,CS
CLI
MOV ES:[24h],AX
MOV ES:[26h],BX
STI
MOV AX,ES:[70h]
MOV BX,ES:[72h]
MOV WORD PTR OldInt1C,AX
MOV WORD PTR OldInt1C+2,BX ; save old interrupt 1Ch
MOV AX,OFFSET Int1CHandler
MOV BX,CS
CLI
MOV ES:[70h],AX
MOV ES:[72h],BX
STI
MOV AH,49h
MOV ES,CS:[2Ch]
INT 21h ; deallocate environment block
MOV AH,09h
MOV DX,OFFSET Install
INT 21h ; display message
StDeAlloc ; deallocate stack
MOV DX,OFFSET TSR_end
ADD DX,15
SHR DX,4
MOV AX,3100h
INT 21h ; go TSR, exit with errorlevel 0
;* Data Area *
; main program data
Install DB 13,10,'Screen Saver now installed - press F8 to
activate.'
DB 13,10,'Type Saver again to un-install.',13,10,10,'$'
Deinstall DB 13,10,'Screen Saver un-installed Ok.',13,10,10,'$'
;* End Program *
code_end LABEL BYTE ; mark end of code segment (end of
program)
code ENDS ; end code segment "code"
END start ; end program, start execution at "start:"
> On 26 Oct, 01:48, wolf3y3 <wolf...@MUNGED.microcosmotalk.com> wrote:
> > I have just got interested in active "pop-up" tsrs,
> > and tried for the first time to make one, the code fails...
> > Can someone help me to understand whats wrong,
> > it is supposed to print a 'A' when the ESC key is pressed.
> > What am I missing? What didn't I do right?
> > When I remove the check for the hotkey_found it just
> > causes the system to crash, I suspect this is because
> > I probably didn't check the InDOS flag right...
[snip code which is available in earlier posts]
> The code is fairly unintelligible as it stands. In answer to your
> question about what you are missing the first thing that springs to
> mind is adequate comments. You should document at least what all DOS
> functions being called are for and what all your magic constants mean.
> It's hard for people to help if they have to look up interrupt
> functions and parameters.
Indeed -- comments are essential, not just for others but als for
oneself when revisiting the code a few months later...
> I'm not sure if direct reading from port 0x60 is a good idea.
>
> James
Perhaps not a good idea, but quite safe and if doing so you have
to take responsibility for all the stuff that int 9 does, like
checking for ctrl-alt-del, updating the keyboard buffer in the
BDA, clearing the interrupt etc. (I could post a small UK keyb
driver source if you're interested.)
But there's usually no need to do that; you can trap int 15h,
function 4Fh which is called internally but the int 9 handler.
Here's a small public domain example that does just this:
----------------------------------------
From: He...@MIT-Multics.ARPA
Subject: capsctrl.asm
; CapsCtrl.asm
;
; This tiny tsr makes the "caps-lock" key act like the "Ctrl" key on
; the IBM 101-key keyboards.
; To get a real caps-lock, type shift+caps-lock.
;
; Warning: this one MUST be loaded before any other TSR's that replace
; the keyboard BIOS call!
;
code_seg segment
assume CS:code_seg
org 100H
old_int label dword
begin: jmp short init
dw 0
upcode db 80H+3AH
; Int 15H points here:
bint: cmp AH,4FH ; is this the "bios" keyboard interrupt?
jnz bint0 ; no, act normal.
cmp AL,3AH ; is it the "caps-lock" key
je bint1
cmp AL,80H+3AH ; is it the "release" key?
jne bint0
xchg al,upcode
jmp short bint2
bint0: jmp [old_int]
bint1: push ES
push AX
xor AX,AX
mov ES,AX
test byte ptr ES:[417H],1011B ; see if Alt or Shift
pop AX
pop ES
jnz bint0
mov AL,1DH ; turn into ctrl key
mov upcode,80H+1DH
bint2: stc ; tell "bios" to use this new code
iret
;--- end of TSR portion ---
assume CS:code_seg,DS:code_seg
init: xor AX,AX
mov ES,AX
mov AX,ES:[54H]; copy old int pointer
mov word ptr old_int,AX
mov AX,ES:[56H]
mov word ptr old_int[2],AX
cli
mov AX,offset bint
mov ES:[54H],AX
mov AX,CS
mov ES:[56H],AX
sti
mov DX,offset init
int 27H
code_seg ends
end begin
----------------------------------------
It is very old code -- note the direct poking of replacement
vectors into the interrupt table -- but it works!
Pete
--
"We have not inherited the earth from our ancestors,
we have borrowed it from our descendants."
suggestion: make a preliminary version of your TSR which doesn't use
DOS for screen output. Once this version works ok, switch to DOS and
fight with the reentrancy problems.
tsrapp:
push dx
mov al,0x41
int 0x29
pop dx
ret
> mov byte [hotkey_found], 1
You probably have to reset this variable after the output is done?
I now need to know what scancodes will be sent
if a combination of keys is pressed like ALT+M,
so these won't be the same as the ASCI scancodes?
I got most of the stuff on capturing the ISR9 vector
from example code in a book, and for a
combination of keys it would read a byte at a time each
time ISR9 was called and check the KB flag in the BIOS
data area.
Thanks for all your help, will certainly study
the TSR code.
in al, 0x64 ; Status
test al, 1
jz short NOKEY
test al, 0x20
jnz short NOKEY ; PS2-Mouse
in al, 0x60
......
dec al ; Escape?
jz isr9_foundkey
NOKEY:
jmp isr9_exit
...
Ralf Browns Interrupt List(RBIL)
http://www.pobox.com/~ralf
http://www.pobox.com/~ralf/files.html
ftp://ftp.cs.cmu.edu/afs/cs.cmu.edu/user/ralf/pub/
RBIL->inter61d.zip->PORTS.A
--------K-P0060006F--------------------------
PORT 0060-006F - KEYBOARD CONTROLLER 804x (8041, 8042) (or PPI (8255) on
PC,XT)
0060 RW KB controller data port or keyboard input buffer (ISA, EISA)
should only be read from after status port bit0 = 1
should only be written to if status port bit1 = 0
0060 R- KeyBoard or KB controller data output buffer (via PPI on XT)
PC: input from port A of 8255, if bit7 in 61h set (see #P0396)
get scancodes, special codes (in PC: with bit7 in 61h cleared)
(see #P0390)
...
0064 R- keyboard controller read status (see #P0398,#P0399,#P0400)
...
Dirk
<snip>
>
>I now need to know what scancodes will be sent
>if a combination of keys is pressed like ALT+M,
>so these won't be the same as the ASCI scancodes?
You can download my tiny Keycode utility at:
http://www.daqarta.com/download.htm
It's at the very bottom of the page.
It will show all codes, including when a series of
codes are produced by a single keystroke
(like PrintScreen).
Best regards,
Bob Masta
DAQARTA v4.51
Data AcQuisition And Real-Time Analysis
www.daqarta.com
Scope, Spectrum, Spectrogram, Sound Level Meter
FREE Signal Generator
Science with your sound card!