.macpack        generic
 
+IRQInd  = $2FD
+
 ; ------------------------------------------------------------------------
 ; Header. Includes jump table
 
 
 ; Library reference
 
+libref:
         .addr   $0000
 
 ; Jump table
         FIRE    = $10
 .endenum
 
+;----------------------------------------------------------------------------
+; data segment
+
+.data
+
+chainIRQ:
+        .byte   $4c                     ; JMP opcode
+        .word   0                       ; pointer to ROM IRQ handler (will be set at runtime)
+
 ;----------------------------------------------------------------------------
 ; Global variables. The bounding box values are sorted so that they can be
 ; written with the least effort in the SETBOX and GETBOX routines, so don't
 
 Temp:           .res    1
 
+; Keyboard buffer fill level at start of interrupt
+
+old_key_count:  .res    1
+
 .rodata
 
 ; Default values for above variables
         jsr     CMOVEY
         cli
 
+; Initialize our IRQ magic
+
+        lda     IRQInd+1
+        sta     chainIRQ+1
+        lda     IRQInd+2
+        sta     chainIRQ+2
+        lda     libref
+        sta     ptr3
+        lda     libref+1
+        sta     ptr3+1
+        ldy     #2
+        lda     (ptr3),y
+        sta     IRQInd+1
+        iny
+        lda     (ptr3),y
+        sta     IRQInd+2
+        iny
+        lda     #<(callback-1)
+        sta     (ptr3),y
+        iny
+        lda     #>(callback-1)
+        sta     (ptr3),y
+        iny
+        lda     #<(chainIRQ-1)
+        sta     (ptr3),y
+        iny
+        lda     #>(chainIRQ-1)
+        sta     (ptr3),y
+
 ; Done, return zero (= MOUSE_ERR_OK)
 
         ldx     #$00
 ; No return code required (the driver is removed from memory on return).
 
 UNINSTALL:
+
+        lda     chainIRQ+1
+        sta     IRQInd+1
+        lda     chainIRQ+2
+        sta     IRQInd+2
+
         jsr     HIDE                    ; Hide cursor on exit
         lda     INIT_save
         sta     INIT_STATUS
 ;
 
 IRQ:    jsr     CPREP
+        lda     KEY_COUNT
+        sta     old_key_count
         lda     #$7F
         sta     CIA1_PRA
         lda     CIA1_PRB                ; Read joystick #0
 @SkipY: jsr     CDRAW
         clc                             ; Interrupt not "handled"
         rts
+
+;----------------------------------------------------------------------------
+; Called after ROM IRQ handler has been run.
+; Check if there was joystick activity before and/or after the ROM handler.
+; If there was activity, discard the key presses since they are most
+; probably "phantom" key presses.
+
+callback:
+        ldx     old_key_count
+        cpx     KEY_COUNT
+        beq     @nokey
+
+        lda     Temp                    ; keypress before?
+        bne     @discard_key            ; yes, discard key
+
+        lda     #$7F
+        sta     CIA1_PRA
+        lda     CIA1_PRB                ; Read joystick #0
+        and     #$1F
+        eor     #$1F                    ; keypress after
+        beq     @nokey                  ; no, probably a real key press
+
+@discard_key:
+        stx     KEY_COUNT               ; set old keyboard buffer fill level
+
+@nokey: rts
 
 ; 2013-07-25, Greg King
 ;
 
+        .include        "c128.inc"
+
         .export         mouse_libref, _pen_adjuster
 
         .data
 ;
 _pen_adjuster:
         .addr   $0000
+        .addr   IRQStub2
+callback:                       ; callback into mouse driver after ROM IRQ handler has been run
+        .addr   $0000           ; (filled in by mouse driver)
+jmp_rom_hdlr:                   ; "trampoline" to jump to ROM IRQ handler
+        .addr   $0000           ; (filled in by mouse driver)
+
+
+.segment        "LOWCODE"
+
+; Called from irq.s when it thinks it chains to the original handler.
+; ROM is banked in again. In order to call the callback we have to
+; bank it out one more time.
+
+IRQStub2:
+
+; Call ROM handler and prepare stack so that it will return to us.
+
+        ; setup fake IRQ stack frame which will return to "IRQCont"
+        lda     #>@IRQCont
+        pha
+        lda     #<@IRQCont
+        pha
+        php
+
+        ; mimic the contents saved on the stack by the ROM IRQ entry handler
+        pha                     ; A
+        pha                     ; X
+        pha                     ; Y
+        lda     #MMU_CFG_CC65   ; MMU configuration which will be active after the ROM handler returns
+        pha
+
+        ; push address of ROM handler on stack and jump to it
+        lda     jmp_rom_hdlr+1
+        pha
+        lda     jmp_rom_hdlr
+        pha
+        rts                     ; jump to ROM handler
+
+        ; our MMU configuration byte we pushed on the stack before (MMU_CFG_CC65) is now active
+
+@IRQCont:
+
+        ; call mouse driver callback routine
+        lda     #>(@IRQCont2-1)
+        pha
+        lda     #<(@IRQCont2-1)
+        pha
+        lda     callback+1
+        pha
+        lda     callback
+        pha
+        rts                     ; jump to callback routine
+
+@IRQCont2:
+        
+        ; return from interrupt
+        ; We could just jump to $FF33, but since I don't know whether this address is valid in all
+        ; ROM versions, duplicate that code here.
+
+        pla
+        sta     MMU_CR          ; MMU configuration register
+        pla
+        tay
+        pla
+        tax
+        pla
+        rti