;; Plan 9-like scrollbar for Windows XP --------------------------------------- ;; The following rules apply: ;; * Press/hold left mouse button to scroll down. ;; * Press/hold right mouse button to scroll up. ;; * The closer to the top of the scrollbar, the slower the speed. ;; * The closer to the bottom of the scrollbar, the faster the speed. ;; The scrolling is achieved by simulating the mouse wheel. ;; Windows without mousewheel support do not work. ;; To use the scrollbar normally, hold any modifier key while clicking the ;; mouse. Ctrl works well, as Ctrl-clicking a scrollbar does nothing special. ;; -> init GroupAdd, ScrollbarExceptions, ahk_class Shell_TrayWnd GroupAdd, ScrollbarExceptions, ahk_class #32768 ;; -> body #If (ScrollbarClip or WinActive("ahk_class MozillaWindowClass")) and (ScrollbarCurrent := CurrentScrollbar()) LButton:: MouseGetPos,, my s := ScrollbarCurrent r := ceil((my - s.a) / (s.b - s.a) * 10) ScrollbarAmount := r if (WinActive("ahk_class PuTTY")) ScrollbarDown = ^{PgDn} else ScrollbarDown = {WheelDown} ScrollbarNew := true if (not ScrollbarScrolling) SetTimer, ScrollbarScroll, 0 return RButton:: MouseGetPos,, my s := ScrollbarCurrent r := ceil((my - s.a) / (s.b - s.a) * 10) ScrollbarAmount := -r if (WinActive("ahk_class PuTTY")) ScrollbarUp = ^{PgUp} else ScrollbarUp = {WheelUp} ScrollbarNew := true if (not ScrollbarScrolling) SetTimer, ScrollbarScroll, 0 return #If <^>!§::SendInput, {Text}§ §:: global ScrollbarClip DllCall("ClipCursor", "Ptr", &0) WinGetPos, x,, w,, A MouseGetPos, mx, my s := CurrentScrollbar(w - 12, my) ScrollbarClip := !ScrollbarClip if (not ScrollbarClip or not s) return WinGetPos, x, y VarSetCapacity(r, 12, 0) NumPut(x + s.aa + 6, &r + 0) NumPut(y + s.a + 1, &r + 4) NumPut(x + s.bb + 6, &r + 8) NumPut(y + s.b, &r + 12) DllCall("ClipCursor", "UInt", &R) r = "" return ;; -> library ScrollbarScroll: SetTimer, ScrollbarScroll, Off ScrollbarScrolling := true ScrollbarNew := false i := 0 j := abs(ScrollbarAmount) while (i < j or GetKeyState(ScrollbarAmount > 0 ? "LButton" : "RButton", "P")) { i += 1 if (ScrollbarNew) { i := 0 j := abs(ScrollbarAmount) ScrollbarNew := false } MouseGetPos,, my s := ScrollbarCurrent if (my < s.a) r := 1 else r := ceil((my - s.a) / (s.b - s.a) * 10) ScrollbarAmount := ScrollbarAmount > 0 ? r : -r if (ScrollbarAmount > 0) SendInput, %ScrollbarDown% else SendInput, %ScrollbarUp% Sleep, % 100 / abs(ScrollbarAmount) if (not (i < j or GetKeyState(ScrollbarAmount > 0 ? "LButton" : "RButton", "P"))) break if (i = j) Sleep, 150 } ScrollbarScrolling := false return CurrentScrollbar(mx = "", my = "") { static size := 17 static GA_ROOT := 2 old := A_BatchLines SetBatchLines, -1 goto begin end: SetBatchLines, % A_BatchLines return false begin: ;; Because this function is run whenever the left mouse button is pressed, it ;; is important to return false as early as possible. CoordMode, Mouse, Window if (mx = "" and my = "") MouseGetPos, mx, my, hwnd if (mx = "" and my != "") MouseGetPos,, my, hwnd if (mx != "" and my = "") MouseGetPos, mx,, hwnd if (mx != "" and my != "") MouseGetPos,,, hwnd WinGet, id, id, ahk_id %hwnd% ahk_group ScrollbarExceptions if (hwnd = id) goto end if (not ScrollbarScrolling and hwnd != WinActive("A")) goto end tmp := A_CoordModePixel CoordMode, Pixel, Window ImageSearch,, wy, % mx - size, % my - size, % mx + size, % my + size, whitesection.bmp ImageSearch,, by, % mx - size, % my - size, % mx + size, % my + size, *50 bluesection.bmp if (wy = "" and by = "") goto end WinGetPos,,,, h, A quit := false if (my > h / 2) { gosub ScrollbarFindDownBelow if (quit) goto end gosub ScrollbarFindUpAbove if (quit) goto end } else { gosub ScrollbarFindUpAbove if (quit) goto end gosub ScrollbarFindDownBelow if (quit) goto end } goto ScrollbarFindRest ScrollbarFindUpAbove: y := 20 Loop { ImageSearch, uax, uay, % mx - size, % my - y, % mx + size, % my, arrowup.bmp y += 20 } until (uay != "" or my - y <= 0) if (uay = "") { CoordMode, Pixel, % tmp quit := true } return ScrollbarFindDownBelow: ImageSearch, dbx, dby, % mx - size, % my, % mx + size, % h, arrowdown.bmp if (dby = "") { CoordMode, Pixel, % tmp quit := true } return ScrollbarFindRest: y := 20 ; Find down arrow above Loop { ImageSearch, dax, day, % mx - size, 0, % mx + size, % h, arrowdown.bmp ; above y += 20 } until (day != "" or my - y <= 0) ; Find up arrow below ImageSearch, ubx, uby, % mx - size, % my, % mx + size, % h, arrowup.bmp ; In the middle of two scrollbars if (day != "" and uby != "" and day > uay and uby < dby) { CoordMode, Pixel, % tmp goto end } CoordMode, Pixel, % tmp SetBatchLines, % A_BatchLines return { a: uay + size + 1, b: dby - 1, aa: uax, bb: dbx } }