diff --git a/src/inc/mouse.plh b/src/inc/mouse.plh
new file mode 100644
index 0000000..3466b93
--- /dev/null
+++ b/src/inc/mouse.plh
@@ -0,0 +1,31 @@
+import mouse
+    //
+    // Status bits
+    //
+    const BUTTON_DOWN      = $80
+    const BUTTON_LAST_DOWN = $40
+    const MOUSE_MOVED      = $20
+    const VBL_INT          = $08
+    const BUTTON_INT       = $04
+    const MOVE_INT         = $02
+    //
+    // Mode bits
+    //
+    const VBL_INT_ENABLE   = $08
+    const BUTTON_INT_ENABLE= $04
+    const MOVE_INT_ENABLE  = $02
+    //
+    // Mouse API
+    //
+    struc t_mouse
+        word chkVbl
+        word chkMouse
+        word readMouse  // readMouse()#3
+        word setMouse   // setMouse(mode)
+        word clearMouse
+        word posMouse   // posMouse(x, y)
+        word clampMouse // clampMouse(xMin, xMax, yMin, yMax)
+        word homeMouse
+        word detachMouse
+    end
+end
diff --git a/src/libsrc/apple/mouse.pla b/src/libsrc/apple/mouse.pla
index b2bedd9..31e5fbc 100644
--- a/src/libsrc/apple/mouse.pla
+++ b/src/libsrc/apple/mouse.pla
@@ -1,27 +1,14 @@
 include "inc/cmdsys.plh"
 //
-// Status bits
-//
-const BUTTON_DOWN      = $80
-const BUTTON_LAST_DOWN = $40
-const MOUSE_MOVED      = $20
-const VBL_INT          = $08
-const BUTTON_INT       = $04
-const MOVE_INT         = $02
-//
-// Mode bits
-//
-const VBL_INT_ENABLE   = $08
-const BUTTON_INT_ENABLE= $04
-const MOVE_INT_ENABLE  = $02
-//
-// Mouse driver
+// Mouse driver interface
 //
+predef chkVbl, chkMouse, readMouse#3, setMouse(mode), clearMouse, posMouse(x, y), clampMouse(xMin, xMax, yMin, yMax), homeMouse, detachMouse
+word = @chkVbl, @chkMouse, @readMouse, @setMouse, @clearMouse, @posMouse, @clampMouse, @homeMouse, @detachMouse
 word rom
-byte slot, index, page, vblDiv, vblInt, mouInt
 byte params[]
-word setMouseFW, serveMouseFW, readMouseFW, clearMouseFW, posMouseFW, clampMouseFW, homeMouseFW, initMouseFW
-word minClamp, maxClamp, xMouse, yMouse, statMouse, modeMouse
+byte slot, index, page
+word setMouseFW
+byte vblDiv, vblInt, mouInt
 asm equates
     !SOURCE "vmsrc/plvmzp.inc"
 end
@@ -49,12 +36,29 @@ end
 asm mouseEvent
 +       INC     MOUINT          ; INC MOUSE EVENT
 end
-asm updateMouse#0
+asm updateMouse
         LDX     #$C4
         LDY     #$40
         JMP     $C400           ; IIGS REQUIRES THIS HAPPEN IN IRQ
 end
-export asm readMouse#3
+//
+// Check for VBL (timer) and Mouse events (atomic read and reset)
+//
+asm chkEvt(addr)
+        LDA     ESTKL,X
+        STA     ESTKH-1,X
+        PHP
+        SEI
+        LDA     (ESTKH-1,X)     ; READ INT COUNT
+        TAY
+        LDA     #$00
+        STA     (ESTKH-1,X)     ; CLEAR INT COUNT
+        PLP
+        STY     ESTKL,X         ; RETURN INT COUNT
+        STA     ESTKH,X
+        RTS
+end
+asm readMouse#3
         LDY     #$04
         DEX
         DEX
@@ -77,45 +81,79 @@ export asm readMouse#3
         RTS
 end
 //
-// Check for VBL (timer) and Mouse events
-//
-asm chkEvt(addr)
-        LDA     ESTKL,X
-        STA     ESTKH-1,X
-        PHP
-        SEI
-        LDA     (ESTKH-1,X)     ; READ INT COUNT
-        TAY
-        LDA     #$00
-        STA     (ESTKH-1,X)     ; CLEAR INT COUNT
-        PLP
-        STY     ESTKL,X         ; RETURN INT COUNT
-        STA     ESTKH,X
-        RTS
-end
-//
 // Convert VBL interrupts into millisecond timer increment
 //
-def chkTimer
+def chkVblTimer
     byte count
     word msec
     
     msec  = 0
     count = chkEvt(@vblInt)
     while count
-        msec   = msec + (vblDiv & 2 ?? 16 :: 17)
-        vblDiv = (vblDiv + 1) % 3
+        if vblDiv & 2
+            msec   = msec + 16
+            vblDiv = 0
+        else
+            msec = msec + 17
+            vblDiv++
+        fin
         count--
     loop
     return msec
 end
 //
-// Check for mouse interrupt events
+// Check for VBL/Mouse interrupt events
 //
+def chkVbl
+    return chkEvt(@vblInt)
+end
 def chkMouse
     return chkEvt(@mouInt)
 end
 //
+// Mouse routines
+//
+def setMouse(mode)
+    return call(setMouseFW, mode, slot, page, $04)
+end
+def clearMouse
+    return call(rom + rom->$15, $00, slot, page, $04) // clearMouseFW
+end
+def posMouse(x, y)
+    //
+    // Fill screen holes
+    //
+    ^($0478 + index) = x
+    ^($0578 + index) = x >> 8
+    ^($04F8 + index) = y
+    ^($05F8 + index) = y >> 8
+    return call(rom + rom->$16, $00, slot, page, $04) // posMouseFW
+end
+def clampMouse(xMin, xMax, yMin, yMax)
+    ^$0478 = xMin
+    ^$0578 = xMin >> 8
+    ^$04F8 = xMax
+    ^$05F8 = xMax >> 8
+    call(rom + rom->$17, $00, slot, page, $04) // clampMouseFW
+    ^$0478 = yMin
+    ^$0578 = yMin >> 8
+    ^$04F8 = yMax
+    ^$05F8 = yMax >> 8
+    return call(rom + rom->$17, $01, slot, page, $04)) // clampMouseFW
+end
+def homeMouse
+    return call(rom + rom->$18, $00, slot, page, $04) // homeMouseFW
+end
+//
+// Detach mouse from interrupts
+//
+def detachMouse
+    setMouse(0)
+    params.0 = 1
+    params.1 = 0
+    return syscall($41, @params)
+end
+//
 // Identify Mouse card/slot and initialize
 //
 for rom = $C100 to $C700 step $0100
@@ -134,32 +172,19 @@ for rom = $C100 to $C700 step $0100
         slot           = rom >> 8
         index          = slot & $07
         page           = index << 4
-        minClamp       = $0478
-        maxClamp       = $04F8
-        xMouse         = $0478 + index
-        yMouse         = $04F8 + index
-        statMouse      = $0778 + index
-        modeMouse      = $07F8 + index
         setMouseFW     = rom + rom->$12
-        serveMouseFW   = rom + rom->$13
-        readMouseFW    = rom + rom->$14
-        clearMouseFW   = rom + rom->$15
-        posMouseFW     = rom + rom->$16
-        clampMouseFW   = rom + rom->$17
-        homeMouseFW    = rom + rom->$18
-        initMouseFW    = rom + rom->$19
         //
         // Fix-up IRQ routine
         //
-        serviceMouse:2 = serveMouseFW
-        serviceMouse:7 = statMouse
+        serviceMouse:2 = rom + rom->$13 // serveMouseFW
+        serviceMouse:7 = $0778+index
         vblEvent.1     = @vblInt
         mouseEvent.1   = @mouInt
         updateMouse.1  = slot
         updateMouse.3  = page
-        updateMouse:5  = readMouseFW
+        updateMouse:5  = rom + rom->$14 // readMouseFW
         readMouse.1    = index
-        call(initMouseFW, $00, slot, page, $04)
+        call(rom + rom->$19, $00, slot, page, $04) // initMouseFW
         return modkeep
     fin
 next
diff --git a/src/mkrel b/src/mkrel
index 6c535ab..10ad8c1 100755
--- a/src/mkrel
+++ b/src/mkrel
@@ -88,6 +88,7 @@ cp samplesrc/dgrtest.pla prodos/bld/DGRTEST.PLA.TXT
 cp samplesrc/hello.pla prodos/bld/HELLO.PLA.TXT
 cp samplesrc/hgr1test.pla prodos/bld/HGR1TEST.PLA.TXT
 cp samplesrc/fibertest.pla prodos/bld/FIBERTEST.PLA.TXT
+cp samplesrc/mousetest.pla prodos/bld/MOUSETEST.PLA.TXT
 cp samplesrc/mon.pla prodos/bld/MON.PLA.TXT
 cp samplesrc/memtest.pla prodos/bld/MEMTEST.PLA.TXT
 cp samplesrc/rod.pla prodos/bld/ROD.PLA.TXT
@@ -113,6 +114,7 @@ cp inc/fiber.plh prodos/bld/inc/FIBER.PLH.TXT
 cp inc/fileio.plh prodos/bld/inc/FILEIO.PLH.TXT
 cp inc/fpstr.plh prodos/bld/inc/FPSTR.PLH.TXT
 cp inc/fpu.plh prodos/bld/inc/FPU.PLH.TXT
+cp inc/mouse.plh prodos/bld/inc/MOUSE.PLH.TXT
 cp inc/inet.plh prodos/bld/inc/INET.PLH.TXT
 cp inc/longjmp.plh prodos/bld/inc/LONGJMP.PLH.TXT
 cp inc/memmgr.plh prodos/bld/inc/MEMMGR.PLH.TXT
diff --git a/src/samplesrc/mousetest.pla b/src/samplesrc/mousetest.pla
new file mode 100644
index 0000000..1a5a1b2
--- /dev/null
+++ b/src/samplesrc/mousetest.pla
@@ -0,0 +1,11 @@
+include "inc/cmdsys.plh"
+include "inc/mouse.plh"
+
+var count
+
+mouse:setmouse(VBL_INT_ENABLE)
+while count < 100
+  count = count + mouse:chkVBL()
+  puti(count); putln
+loop
+done