那设置里可不可以写通配符,就算穿一层也允许任意软件都可以穿吧?
你直接用原版的 winhole 就好了。
https://www.autohotkey.com/boards/viewtopic.php?f=6&t=30622
谢了,原版没有编译的版本。。
昨天花了6个小时尝试理解代码,重写一个最小可用版本,让AHK按键映射工具能调用,结果失败了,整个软件的行为完全不可控
早上再次尝试洞洞波,发现其实也有很多问题,只是之前快速试用没发现,这个功能其实挺有用,但从winhole开始的实现方式就不是很好,很难进行适配
后面有时间再尝试了,暂时放弃这个好东西
这个应用超级 nice.我已经用了很久了.目前重度使用中.目前最多只能做到二次穿透对吗?能不能多次穿透呢?比如说按住alt后滚动滚轮一次就穿透一次,滚动两次就穿透两次,滚动三次就穿透三次,直到最终穿透到桌面.因为我一次打开好多个窗口,急需多次穿透.大佬能不能给一下指点该怎么做?
你说的这个功能我倒是有想到方法实现,简单来说就是不搞真实穿透了,而是假装穿洞。类似我之前写的desktoptop原理, 把目标窗口置顶且只显示圆形局部,就会有一种穿洞的感觉。
不过那样也会带来很多问题。
如果真实穿透的话,每穿一次,cpu都会增高一截、卡顿感增高一大截,基本上除非微软自己弄个支持,不然很难优雅地多次穿透。
有时候,按~,会出现圆,但在chrome下一闪一闪的,可以看到桌面包括浏览器后面的内容。但在资源管理器下,圆里面显示好像是资源管理器的皮肤颜色,全是一个颜色,并没有穿透的下面的什么颜色之类的东西。win11 23h2系统。
参考这个人说的
另外,有些窗口是显卡渲染的,也不能穿透。
我倒是安装使用了start11工具,不知道是不是这个影响到了,但是好像有时候还能正常使用。
不管怎么说,应该继续优化一下。
狗哥,.ahk文件要使用什么版本的autohotkey运行啊,我把autohotkey1.1.37.02的unicode32、64、ansi和autohotkey2都试了一下都不行……单独运行你编译好的.exe版就行,主要是我想改个快捷键
就是 autohotkey1.1.37.02 啊?你报的什么错?
以下是代码:
#InstallKeybdHook
#UseHook
DetectHiddenWindows On
IniRead,radius,setting.ini,radius,radius
IniRead,winlist,setting.ini,winlist
; Note: Exit script with Esc::
OnExit("exit")
; Settings
;radius:=500 ; Starting radius of the hole.
;increment:=25 ; Amount to decrease/increase radius of circle when turning scroll wheel
inverted:=false ; If false, the region is see-throughable.
rate:=40 ; The period (ms) of the timer. 40 ms is 25 "fps"
running:=0
running2:=0
Toggle:=0
StartTime:=0
; Make the region
region:=makeCircle(radius)
; Script settings
SetWinDelay,-1
ListLines, off ; Remove when debugging.
$`::
{
ElapsedTime := A_TickCount - StartTime
if ElapsedTime<400
return
KeyWait,``,T0.4
if A_TimeSinceThisHotkey<400
{
;·tooltip,hh
if ElapsedTime>2000
SendInput,``
return
}
if ! running
{
{
MouseGetPos, , ,nowid
arr := EnumerateAltTabWindows()
altTabWindows:=""
for k, v in arr
{
WinGetClass, winClass, ahk_id %v%
if nowid=%v%
continue
WinGet, MMstate, MinMax , ahk_id %v%
if (MMstate>0.5) or (!MMstate)
altTabWindows .= v "`n"
}
WinGet, exename, ProcessName, ahk_id %nowid%
loop, Parse, winlist, `n, `r
{
if exename=%A_LoopField%
altTabWindows:=""
}
loop, Parse, altTabWindows, `n, `r
{
WinGet, exename, ProcessName, ahk_id %A_LoopField%
loop, Parse, winlist, `n, `r
{
if exename=%A_LoopField%
continue,2
}
WinMinimize, ahk_id %A_LoopField%
}
}
timer(1,region,inverted,rate)
Toggle:=!Toggle
Pause:=0
running:=!running
}
}
return
#if Toggle
return
1::
if ! running2
{
timer2(1,region,inverted,rate)
running2:=1
}
return
1 Up::
timer2(0)
running2:=0
return
$`::
return
$` up::
{
;msgbox,% altTabWindows
if altTabWindows
{
Array := StrSplit(altTabWindows, "`n", "`r")
loop, % array.length()
{
thiswin:=array[array.length()-A_Index+1]
WinRestore, ahk_id %thiswin%
WinGet, exename, ProcessName, ahk_id %thiswin%
loop, Parse, winlist, `n, `r
{
if exename=%A_LoopField%
{
WinMinimize, ahk_id %thiswin%
WinRestore, ahk_id %thiswin%
}
}
}
}
Toggle:=!Toggle
timer2(0)
timer(0)
Pause:=0
running:=!running
running2:=0
StartTime := A_TickCount
WinActivate,ahk_id %nowid%
}
return
#if
exit(){
timer(0) ; For restoring the window if region applied when script closes.
timer2(0)
ExitApp
return
}
timer(state,region:="",inverted:=false,rate:=100){
; Call with state=0 to restore window and stop timer, state=-1 stop timer but do not restore
; region, inverted, see WinSetRegion()
; rate, the period of the timer.
static timerFn, paused, hWin, aot
if (state=0) { ; Restore window and turn off timer
if timerFn
SetTimer,% timerFn, Off
if !hWin
return
WinSet, Region,, % "ahk_id " hWin
if !aot ; Restore not being aot if appropriate.
WinSet, AlwaysOnTop, off, % "ahk_id " hWin
hWin:="",timerFn:="",aot:="",paused:=0
return
} else if (timerFn) { ; Pause/unpause or...
if (state=-1) {
SetTimer,% timerFn, Off
return paused:=1
} else if paused {
SetTimer,% timerFn, On
return paused:=0
} else { ; ... stop timer before starting a new one.
SetTimer,% timerFn, Off
}
}
if !hWin { ; Get the window under the Mouse.
MouseGetPos,,,hWin
WinGet, aot, ExStyle, % "ahk_id " hWin ; Get always-on-top state, to preserve it.
aot&=0x8
if !aot
WinSet, AlwaysOnTop, On, % "ahk_id " hWin
}
timerFn:=Func("timerFunction").Bind(hWin,region,inverted) ; Initialise the timer.
timerFn.Call(1) ; For better responsiveness, 1 is for reset static
SetTimer, % timerFn, % rate
return
}
timer2(state,region:="",inverted:=false,rate:=100){
; Call with state=0 to restore window and stop timer, state=-1 stop timer but do not restore
; region, inverted, see WinSetRegion()
; rate, the period of the timer.
static timerFn, paused, hWin, aot
if (state=0) { ; Restore window and turn off timer
if timerFn
SetTimer,% timerFn, Off
if !hWin
return
WinSet, Region,, % "ahk_id " hWin
if !aot ; Restore not being aot if appropriate.
WinSet, AlwaysOnTop, off, % "ahk_id " hWin
hWin:="",timerFn:="",aot:="",paused:=0
return
} else if (timerFn) { ; Pause/unpause or...
if (state=-1) {
SetTimer,% timerFn, Off
return paused:=1
} else if paused {
SetTimer,% timerFn, On
return paused:=0
} else { ; ... stop timer before starting a new one.
SetTimer,% timerFn, Off
}
}
if !hWin { ; Get the window under the Mouse.
MouseGetPos,,,hWin
WinGet, aot, ExStyle, % "ahk_id " hWin ; Get always-on-top state, to preserve it.
aot&=0x8
if !aot
WinSet, AlwaysOnTop, On, % "ahk_id " hWin
}
timerFn:=Func("timerFunction").Bind(hWin,region,inverted) ; Initialise the timer.
timerFn.Call(1) ; For better responsiveness, 1 is for reset static
SetTimer, % timerFn, % rate
return
}
timerFunction(hWin,region,inverted,resetStatic:=0){
; Get mouse position and convert coords to win coordinates, for displacing the circle
static px,py
WinGetPos,wx,wy,,, % "ahk_id " hWin
CoordMode, Mouse, Screen
MouseGetPos,x,y
x-=wx,y-=wy
if (x=px && y=py && !resetStatic)
return
else
px:=x,py:=y
WinSetRegion(hWin,region,x,y,inverted)
return
}
WinSetRegion(hWin,region,dx:=0,dy:=0,inverted:=false){
; hWin, handle to the window to apply region to.
; Region should be on the form, region:=[{x:x0,y:y0},{x:x1,y:y1},...,{x:xn,y:yn},{x:x0,y:y0}]
; dx,dy is displacing the the region by fixed amount in x and y direction, respectively.
; inverted=true, make the region the only part visible, vs the only part see-throughable for inverted=false
if !inverted {
WinGetPos,,,w,h, % "ahk_id " hWin
regionDefinition.= "0-0 0-" h " " w "-" h " " w "-0 " "0-0 "
}
for k, pt in region
regionDefinition.= dx+pt.x "-" dy+pt.y " "
WinSet, Region, % regionDefinition, % "ahk_id " hWin
}
; Function for making the circle
makeCircle(r:=100,n:=-1){
; r is the radius.
; n is the number of points, let n=-1 to set automatically (highest quality).
static pi:=ATan(1)*4
pts:=[]
n:= n=-1 ? Ceil(2*r*pi) : n
n:= n>=1994 ? 1994 : n ; There is a maximum of 2000 points for WinSet,Region,...
loop, % n+1
t:=2*pi*(A_Index-1)/n, pts.push({x:Round(r*Cos(t)),y:Round(r*Sin(t))})
return pts
}
heart4tidbit(r:=100)
{
n:=r*4
n:= n>=997 ? 997 : n ; There is a maximum of 2000 points for WinSet,Region,... Edit: Changed to 997, since there are two loops
region:=[]
oY:=-r//2
loop, % n
{
x:=-2+4*(A_Index-1)/(n-1)
y:=-Sqrt(1-(Abs(x)-1)**2)
region.push({x:x*r, y:y*r+oY})
}
loop, % n
{
x:=2-4*(A_Index-1)/(n-1)
y:=3*Sqrt(1-Sqrt(Abs(x/2)))
region.push({x:x*r, y:y*r+oY})
}
return region
}
makeTriangle(side:=100){
heigth:=Round(side*Sqrt(3)/2)
region:=[{x:0,y:0}, {x:side//2,y:heigth}, {x:-side//2,y:heigth}, {x:0,y:0}]
oY:=-heigth//2 ; Make center, note: oX:=0
for k, pt in region
pt.y+=oY ; Make correction for center, note: pt.x+=oX
return region
}
EnumerateAltTabWindows()
{
AltTabList := []
WinGet, list, List
loop % list
{
if IsAltTabWindow(list%A_Index%)
AltTabList.Push(list%A_Index%)
}
return AltTabList
}
IsAltTabWindow(hWnd)
{
static WS_EX_APPWINDOW := 0x40000, WS_EX_TOOLWINDOW := 0x80, DWMWA_CLOAKED := 14, DWM_CLOAKED_SHELL := 2, WS_EX_NOACTIVATE := 0x8000000, GA_PARENT := 1, GW_OWNER := 4, MONITOR_DEFAULTTONULL := 0, VirtualDesktopExist, PropEnumProcEx := RegisterCallback("PropEnumProcEx", "Fast", 4)
if (VirtualDesktopExist = "")
{
OSbuildNumber := StrSplit(A_OSVersion, ".")[3]
if (OSbuildNumber < 14393)
VirtualDesktopExist := 0
else
VirtualDesktopExist := 1
}
if !DllCall("IsWindowVisible", "uptr", hWnd)
return
DllCall("DwmApi\DwmGetWindowAttribute", "uptr", hWnd, "uint", DWMWA_CLOAKED, "uint*", cloaked, "uint", 4)
if (cloaked = DWM_CLOAKED_SHELL)
return
if (realHwnd(DllCall("GetAncestor", "uptr", hwnd, "uint", GA_PARENT, "ptr")) != realHwnd(DllCall("GetDesktopWindow", "ptr")))
return
WinGetClass, winClass, ahk_id %hWnd%
if (winClass = "Windows.UI.Core.CoreWindow")
return
if (winClass = "ApplicationFrameWindow")
{
VarSetCapacity(ApplicationViewCloakType, 4, 0)
DllCall("EnumPropsEx", "uptr", hWnd, "ptr", PropEnumProcEx, "ptr", &ApplicationViewCloakType)
if (NumGet(ApplicationViewCloakType, 0, "int") = 1) ; https://github.com/kvakulo/Switcheroo/commit/fa526606d52d5ba066ba0b2b5aa83ed04741390f
return
}
; if !DllCall("MonitorFromWindow", "uptr", hwnd, "uint", MONITOR_DEFAULTTONULL, "ptr") ; test if window is shown on any monitor. alt-tab shows any window even if window is out of monitor.
; return
WinGet, exStyles, ExStyle, ahk_id %hWnd%
if (exStyles & WS_EX_APPWINDOW)
{
if DllCall("GetProp", "uptr", hWnd, "str", "ITaskList_Deleted", "ptr")
return
if (VirtualDesktopExist = 0) or IsWindowOnCurrentVirtualDesktop(hwnd)
return true
else
return
}
if (exStyles & WS_EX_TOOLWINDOW) or (exStyles & WS_EX_NOACTIVATE)
return
loop
{
hwndPrev := hwnd
hwnd := DllCall("GetWindow", "uptr", hwnd, "uint", GW_OWNER, "ptr")
if !hwnd
{
if DllCall("GetProp", "uptr", hwndPrev, "str", "ITaskList_Deleted", "ptr")
return
if (VirtualDesktopExist = 0) or IsWindowOnCurrentVirtualDesktop(hwndPrev)
return true
else
return
}
if DllCall("IsWindowVisible", "uptr", hwnd)
return
WinGet, exStyles, ExStyle, ahk_id %hwnd%
if ((exStyles & WS_EX_TOOLWINDOW) or (exStyles & WS_EX_NOACTIVATE)) and !(exStyles & WS_EX_APPWINDOW)
return
}
}
GetLastActivePopup(hwnd)
{
static GA_ROOTOWNER := 3
hwnd := DllCall("GetAncestor", "uptr", hwnd, "uint", GA_ROOTOWNER, "ptr")
hwnd := DllCall("GetLastActivePopup", "uptr", hwnd, "ptr")
return hwnd
}
IsWindowOnCurrentVirtualDesktop(hwnd)
{
static IVirtualDesktopManager
if !IVirtualDesktopManager
IVirtualDesktopManager := ComObjCreate(CLSID_VirtualDesktopManager := "{AA509086-5CA9-4C25-8F95-589D3C07B48A}", IID_IVirtualDesktopManager := "{A5CD92FF-29BE-454C-8D04-D82879FB3F1B}")
DllCall(NumGet(NumGet(IVirtualDesktopManager+0), 3*A_PtrSize), "ptr", IVirtualDesktopManager, "uptr", hwnd, "int*", onCurrentDesktop) ; IsWindowOnCurrentVirtualDesktop
return onCurrentDesktop
}
PropEnumProcEx(hWnd, lpszString, hData, dwData)
{
if (StrGet(lpszString, "UTF-16") = "ApplicationViewCloakType")
{
NumPut(hData, dwData+0, 0, "int")
return false
}
return true
}
realHwnd(hwnd)
{
VarSetCapacity(var, 8, 0)
NumPut(hwnd, var, 0, "uint64")
return NumGet(var, 0, "uint")
}
很奇怪,使用原版WinHole就没问题,我先调试下看看
原来是.ahk文件需要和setting.ini放同一目录下,单独下载的.ahk文件我就没放在一起