home *** CD-ROM | disk | FTP | other *** search
- {
- > I would like to include a clock in my current project which will be
- > updated once a minute. Instead of constantly checking the computer's clock
- > and waiting for it to change, I would like to use an interrupt.
-
- This one has even a hot key handler. If you want to update it once per
- minute, bump a counter within the interrupt 1Ch handler till it reaches the
- value 60*18.2. Then refresh the screen.
- }
-
- Program Clock;
-
- {$G+,R-,S-,M 1024, 0, 0 }
-
- uses
- Dos;
-
- Const
- x = 71; { x location on screen }
- y = 1; { y location on screen }
- Keyboard = 9; { Hardware keyboard interrupt }
- TimerTick = $1C; { Gets called 18.2 / second }
- VideoOffset = 160 * (y - 1) + 2 * x;{ Offset in display memory }
- yellow = 14;
- blue = 1;
- attribute = blue * 16 + yellow; { Clock colours }
- VideoBase : Word = $B800; { Segment of display memory }
- ActiveFlag : ShortInt = -1; { 0: on, -1: off }
-
- Var
- OrgInt9, { Saved interrupt 9 vector }
- OrgInt1Ch : Pointer; { Saved interrupt 1Ch vector }
- VideoMode : Byte absolute $0000:$0449;
-
- { Display a string using Dos services (avoid WriteLn, save memory) }
-
- Procedure DisplayString(s : String); Assembler;
-
- ASM
- PUSH DS
- XOR CX, CX
- LDS SI, s
- LODSB
- MOV CL, AL
- JCXZ @EmptyString
- CLD
- @NextChar:
- LODSB
- XCHG AX, DX
- MOV AH, 2
- INT 21h
- LOOP @NextChar
- @EmptyString:
- POP DS
- end;
-
- { Returns True if a real time clock could be found }
- Function HasRTClock : Boolean; Assembler;
-
- ASM
- XOR AL, AL
- MOV AH, 2
- INT 1Ah
- JC @NoRTClock
- INC AX
- @NoRTCLock:
- end;
-
- { Release Dos environment }
- Procedure ReleaseEnvironment; Assembler;
- ASM
- MOV ES, [PrefixSeg]
- MOV ES, ES:[002Ch]
- MOV AH, 49h
- INT 21h
- end;
-
- { INT 9 handler intercepting Alt-F11 }
- Procedure ToggleClock; Interrupt; Assembler;
- Const
- F11 = $57; { 'F11' make code }
- BiosSeg = $40; { Segment of BIOS data area }
- AltMask = $08; { Bitmask of Alt key }
- KbdFlags = $17; { Byte showing keyboard status }
-
- ASM
- STI
- IN AL, 60h
-
- { F11 pressed? }
- CMP AL, F11
- JNE @PassThru
-
- { Alt-key pressed? }
- PUSH BiosSeg
- POP ES
- MOV AL, ES:[KbdFlags]
- AND AL, AltMask
- CMP AL, AltMask
- JNE @PassThru
-
- { Flip status flag, force EOI and leave routine }
- NOT [ActiveFlag]
- IN AL, 61h
- MOV AH, AL
- OR AL, 80h
- OUT 61h, AL
- MOV AL, AH
- OUT 61h, AL
- CLI
- MOV AL, 20h
- OUT 20h, AL
- STI
- JMP @Exit
-
- @PassThru:
- CLI
- PUSHF
- CALL DWord Ptr [OrgInt9]
- @Exit:
- end; { ToggleClock }
-
- { Convert a packed BCD byte to ASCII character }
- Procedure Digit; Assembler;
- ASM
- PUSH AX
- CALL @HiNibble
- POP AX
- CALL @LoNibble
- RETN
-
- @HiNibble:
- SHR AL, 4
- JMP @MakeAscii
- @LoNibble:
- AND AL, 0Fh
- @MakeAscii:
- OR AL, '0'
- STOSW
- end;
-
- { INT 1Ch handler that displays a clock on the right hand side of the screen }
- Procedure DisplayClock; Interrupt; Assembler;
- ASM
- CMP [ActiveFlag], 0
- JNE @Exit
- CLD
- MOV AH, 2
- INT 1Ah
- MOV ES, [VideoBase]
- MOV DI, VideoOffset
- MOV AH, attribute
- MOV AL, CH
- CALL Digit
- MOV AL, ':'
- STOSW
- MOV AL, CL
- CALL Digit
- MOV AL, ':'
- STOSW
- MOV AL, DH
- CALL Digit
- PUSHF
- CALL DWord Ptr [OrgInt1Ch]
- @Exit:
- end;
-
- Begin
- If VideoMode = 7 Then
- VideoBase := $B000;
- GetIntVec(TimerTick, OrgInt1Ch);
- SetIntVec(TimerTick, @DisplayClock);
- GetIntVec(Keyboard, OrgInt9);
- SetIntVec(Keyboard, @ToggleClock);
- SwapVectors;
- ReleaseEnvironment;
- DisplayString('CLOCK installed. <Alt-F11> toggles on/off');
- Keep(0);
- end.