简短的回答
对于Adobe Reader X中的水平滚动,请将滚动消息发送到滚动条的父级,如 sendscrolltoscrollbarparent
在代码中。许多其他方法无法正常工作。这种方法以某种方式提供非常快速的滚动,甚至比我原来的鼠标驱动器更好。
答案很长
我找到了自己的答案,却忘记了这个问题。基本上我为每个疯狂的应用程序使用了一种特殊的方法。由于篇幅太多,我为整个问题创建了一个单独的问答( AutoHotkey滚动&中间点击&鼠标加速度 ),这里只给出与Adobe Reader相关的部分。
这个过程应该是这样的。首先你打电话 gettarget
假定鼠标位置存储在 mx,my
并根据当前鼠标下的内容找到滚动事件的正确目标。然后你反复打电话 scroll
添加金额后滚动到 sx,sy
。
对于Adobe Reader,即使垂直滚动依赖于将轮子消息发送到正确的位置,这是不一致的,因此我最终硬编码两个主要情况,即滚动文档显示区域和滚动书签区域。为了找出它是哪种情况,我检查鼠标下控件的父控件是否有一个后代 AVL_AVView4
或不。如果确实如此,那么这是发送垂直轮消息的正确方法 sendwheel
。但是对于水平滚动,事实证明将滚动消息发送到正确滚动条的父控件可以在两个地方都可以执行 sendscrolltoscrollbarparent
。正确的滚动条是一个叫做的滚动条 scrollbar1
这是鼠标下控件的父级的后代。
码
#commentflag // ; Change to C++ comment style
global mx,my
global sx:=0
global sy:=0
global ctrl,window,parent
global methodx
global methody
global scrollbarx
global scrollbary
global max16bit:=32767
gettarget()
{
ctrl:=getctrlat(mx,my)
window:=getwindow(ctrl)
class:=getclass(window)
parent:=getparent(ctrl)
parentname:=getnameatroot(parent)
if( class=="AcrobatSDIWindow" )
{
if( regexmatch(parentname,"AVL_AVView")==1 )
{
ctrl:=getdescendant(parent,"AVL_AVView4")
if( ctrl=="" )
{
ctrl:=getdescendant(parent,"AVL_AVView1")
}
methodx:="scrolltoscrollbarparent"
scrollbarx:="scrollbar1"
methody:="wheel"
}
}
}
scroll:
critical on
tx:=sx
ty:=sy
sx-=tx
sy-=ty
rx:=0
ry:=0
if( tx!=0 )
{
txi:=rtoz(tx)
rx:=tx-txi
if( txi!=0 )
{
if( methodx=="scrolltoscrollbarparent" )
{
sendscrolltoscrollbarparent(scrollbarx,"h",txi)
}
}
}
if( ty!=0 )
{
if( methody=="wheel" )
{
sendwheel("v",-ty)
}
}
sx:=rx
sy:=ry
return
sendwheel(dir,amount)
{
t:=a_tickcount
msg:=( dir=="v" ? 0x20a : 0x20e )
flags:=getkeystate("Ctrl")<<3|getkeystate("Shift")<<2
amount*=120
while( amount>max16bit )
{
sendmessage msg,max16bit<<16|flags,mx|my<<16,,ahk_id %ctrl%,,,,timelimit
amount-=max16bit
if( a_tickcount-t>=timelimit )
{
return
}
}
while( amount<-max16bit )
{
sendmessage msg,-max16bit<<16|flags,mx|my<<16,,ahk_id %ctrl%,,,,timelimit
amount+=max16bit
if( a_tickcount-t>=timelimit )
{
return
}
}
sendmessage msg,round(amount)<<16|flags,mx|my<<16,,ahk_id %ctrl%,,,,timelimit
}
sendscrolltoscrollbarparent(name,dir,amount)
{
sb:=getdescendant(parent,name)
sbp:=getparent(sb)
t:=a_tickcount
msg:=( dir=="v" ? 0x115 : 0x114 )
flag:=( amount<0 ? 0 : 1 )
loop % abs(amount)
{
sendmessage msg,flag,sb,,ahk_id %sbp%,,,,timelimit
if( a_tickcount-t>=timelimit )
{
return
}
}
}
rtoz(r)
{
return ( r>0 ? floor(r) : ceil(r) )
}
getparent(handle)
{
return dllcall("GetParent","uint",handle)
}
getname(root,handle)
{
local CH,CN,S,P
WinGet, CH, ControlListHwnd, ahk_id %root%
WinGet, CN, ControlList, ahk_id %root%
setformat integerfast,h
handle+=0
handle.=""
setformat integerfast,d
LF:= "`n", CH:= LF CH LF, CN:= LF CN LF, S:= SubStr( CH, 1, InStr( CH, LF handle LF ) )
StringReplace, S, S,`n,`n, UseErrorLevel
StringGetPos, P, CN, `n, L%ErrorLevel%
Return SubStr( CN, P+2, InStr( CN, LF, 0, P+2 ) -P-2 )
}
getdescendant(handle,name)
{
local CH,CN,S,P
WinGet, CH, ControlListHwnd, ahk_id %handle%
WinGet, CN, ControlList, ahk_id %handle%
setformat integerfast,h
handle+=0
handle.=""
setformat integerfast,d
LF:= "`n", CH:= LF CH LF, CN:= LF CN LF, S:= SubStr( CN, 1, InStr( CN, LF name LF ) )
StringReplace, S, S,`n,`n, UseErrorLevel
StringGetPos, P, CH, `n, L%ErrorLevel%
Return SubStr( CH, P+2, InStr( CH, LF, 0, P+2 ) -P-2 )*1
}
getnameatroot(handle)
{
return getname(dllcall("GetAncestor","uint",handle,"uint",2),handle)
}
getnameaschild(handle)
{
return getname(getparent(handle),handle)
}
getclass(handle)
{
local class
wingetclass class,ahk_id %handle%
return class
}
getwindow(handle)
{
return dllcall("GetAncestor","uint",handle,"uint",2)
}
getctrlat2(x,y,first,current)
{
/*
Pushes the following invisible container controls to the back because they are in front of their contents for no reason
SysTabControl32 : The usual class that contains tabbed panes ( Mouse properties , ... )
Static : A class occasionally used to contain tabbed panes ( Programmer's Notepad Options > Fonts and Colours > Advanced , ... )
Button : A typical class used to contain a List Box ( Outlook Contact > Properties > General > Members , ... )
Executes WindowFromPoint again to access the contents of such container controls
*/
local handle,class,style
class:=getclass(current)
winget style,style,ahk_id %current%
if( class=="SysTabControl32" or class=="Static" or ( class=="Button" and (style&0x7)==0x7 ) )
{
dllcall("SetWindowPos","uint",current,"uint",1,"int",0,"int",0,"int",0,"int",0,"uint",0x3) // push it to the back where it belongs
handle:=dllcall("WindowFromPoint","int",x,"int",y)
//handle:=DllCall( "WindowFromPoint", "int64", (my << 32) | (mx & 0xFFFFFFFF), "Ptr") // for negative 64-bit
if( handle==first )
{
return first
}
return getctrlat2(x,y,first,handle)
}
return current
}
getctrlat(x,y)
{
local handle
handle:=dllcall("WindowFromPoint","int",x,"int",y)
//handle:=DllCall( "WindowFromPoint", "int64", (my << 32) | (mx & 0xFFFFFFFF), "Ptr") // for negative 64-bit
return getctrlat2(x,y,handle,handle)
}