aboutsummaryrefslogtreecommitdiff
path: root/!tt.scrollbar.ahk
blob: c88f451d6877936b1b48a6c02c1a3485bb104388 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
;; 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 }
}