-
Notifications
You must be signed in to change notification settings - Fork 74
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Feature Request: Relative window focus movement shortcuts #465
Comments
In case anyone else really wants this, and is as frustrated as I was about the lack of options out there, I've written an Autohotkey script that can do it. #Requires AutoHotkey v2.0
calc_padding := 20 ; minimum direction/alignment overlap for target windows
#h::FocusWin("left")
#l::FocusWin("right")
#k::FocusWin("up")
#j::FocusWin("down")
; ==== DEVELOPMENT SHORTCUTS ====
; Reload this script
; #+r:: {
; Reload
; }
; Get active window position data
; #+t:: {
; aID := WinGetID("A")
; WinGetFullPos(&aXL, &aXR, &aYT, &aYB, &aW, &aH, aID)
; discounted := WinIsDiscounted(aID, &visible, &desktop, &taskbar, &startmenu)
; MsgBox(
; "XL: " aXL "`n"
; "XR: " aXR "`n"
; "YT: " aYT "`n"
; "YB: " aYB "`n"
; "W: " aW "`n"
; "H: " aH "`n"
; "`n"
; "ID: " aID "`n"
; "`n"
; "Visible: " visible "`n"
; "Desktop: " desktop "`n"
; "Taskbar: " taskbar "`n"
; "Startmenu: " startmenu "`n"
; "`n"
; "Discounted: " discounted
; )
; }
WinGetFullPos(&xl, &xr, &yt, &yb, &w, &h, id) {
WinGetPos(&xl, &yt, &w, &h, id)
xr := xl + w
yb := yt + h
return
}
OverlapAxis(axis, padding, aXL, aXR, aYT, aYB, tXL, tXR, tYT, tYB) {
if (axis = "Y" && (tYB >= (aYT + padding) && (tYT + padding) <= aYB))
return true
if (axis = "X" && (tXR >= (aXL + padding) && (tXL + padding) <= aXR))
return true
return false
}
WinIsDiscounted(id, &visible, &desktop, &taskbar, &startmenu) {
wclass := WinGetClass(id)
wstyle := WinGetStyle("ahk_id" id)
WS_VISIBLE := 0x10000000
visible := (wstyle & WS_VISIBLE) ? true : false
desktop := (wclass = "Progman" || wclass = "WorkerW")
taskbar := (wclass = "Shell_TrayWnd" || wclass = "Shell_SecondaryTrayWnd")
startmenu := (wclass = "DV2ControlHost" || wclass = "Windows.UI.Core.CoreWindow")
return !visible || desktop || taskbar || startmenu
}
FocusWin(direction) {
aID := WinGetID("A") ; get ID of active window
WinGetFullPos(&aXL, &aXR, &aYT, &aYB, &aW, &aH, aID) ; get pos/size of active window
ids_arr := WinGetList() ; get all window IDs (returns array of id strings)
; values to update during the loop
closest_id := ""
closest_distance := 999999999
; loop through all windows
; validity checks are made early as possible for performance
for (tID in ids_arr) {
is_active_win := tID == aID
if (is_active_win)
continue
is_discounted_win := WinIsDiscounted(tID, &visible, &desktop, &taskbar, &startmenu)
if (is_discounted_win)
continue
WinGetFullPos(&tXL, &tXR, &tYT, &tYB, &tW, &tH, tID) ; get pos/size of target window
switch direction
{
case "left": is_direction := aXL - tXL >= calc_padding
case "right": is_direction := tXR - aXR >= calc_padding
case "up": is_direction := aYT - tYT >= calc_padding
case "down": is_direction := tYB - aYB >= calc_padding
}
if (!is_direction)
continue
switch direction
{
case "left": is_aligned := OverlapAxis("Y", calc_padding, aXL, aXR, aYT, aYB, tXL, tXR, tYT, tYB)
case "right": is_aligned := OverlapAxis("Y", calc_padding, aXL, aXR, aYT, aYB, tXL, tXR, tYT, tYB)
case "up": is_aligned := OverlapAxis("X", calc_padding, aXL, aXR, aYT, aYB, tXL, tXR, tYT, tYB)
case "down": is_aligned := OverlapAxis("X", calc_padding, aXL, aXR, aYT, aYB, tXL, tXR, tYT, tYB)
}
if (!is_aligned)
continue
switch direction
{
case "left": distance := aXL - tXR
case "right": distance := tXL - aXR
case "up": distance := aYT - tYB
case "down": distance := tYT - aYB
}
; update closest values if window is closer and to the left
if (distance < closest_distance) {
closest_id := tID
closest_distance := distance
}
}
; activate closest window
if (closest_id)
WinActivate("ahk_id" closest_id)
return
} |
This would be a nice addition indeed, I will investigate This... |
Here is a first test build I wrote in an hour this morning. AltSnap1.62test1_i386.zip Of course as usual replace AltSnap.exe and hooks.dll with the versions above and in the Keyboard tab you will have the option to configure the Focus left/right/top/bottom window in the Shortcut for action: drop list. |
I'll give this a test later, thank you! |
@RamonUnch, I was trying to play with using command line L/R direction change the focus fine. However, when I try to move focus up/down -afFocusT and -afFocusB, it does not change focus. Actually, it is hard to tell where the focus is after these commands in up/down direction. |
For me it works relyably. Also here is a visual description on how it should work: |
also those actions were designed for keyboard shortcuts in mind. You can setup those shortcuts directly in AltSnap. |
I tried with keyboard and also with the latest release (test5) and still cannot navigate in T/B direction. I attached my config in the comment. Can you please check? By the way, I am using external monitor with 150% DPI and grid 2x2 layout. I tried with 4 notepad window laid out neatly using Altsnap. There is no other layout manager such as FancyZone in the play. |
I still cannot reproduce but I see some problems with the current system. |
AltSnap1.62test5_LOG_x64.zip |
Currently, seems, pretty unreliable in which window gets focused. |
This version removes overlap between directions and prioritize the pure cardinal position over diagonals. Also let me know if you see strange windows appear in the |
It is better than before. It can still get focused the wrong window. I initially focused on TL and issued to focusB. It moved down currectly. I issued focusT and it focused top window correctly. I then move the focus to the right top window. It got the TR (top right) window correctly. But now when I issued focusB, and tried to move the focus to BR (bottom right) it moves focus to the BL (bottom left). Now if I move the focus to T or B, it switches the focus between TR and BL (diagonally) all the time. ad.log is attached. |
Thanks for the log file, so it seems the only problem comes from bad selection algorithm. hooks1.62test7_2_3rd_beam_x64.zip It is a two step process, first AltSnap tries to find the closest window inside the beam, then if it was unable to find any window, it create 45 degree regions and selects the next closest window within those regions. thus covering the whole space. |
@RamonUnch, thank you for additional dlls. I found the hooks1.6test7_x64 version works better than 1/3, 1/2, and 2/3. Actually, I have a very reliable way to reproduce this issue with the layout below. I found that I can focus on all 3 of them reliably, if I move focus from TL(left top) -> BL (left-bottom) -> TL (left top) -> TR (top right). But the problem happens when I try to move focus from TR to BL (focusB), it found the BL diagonally. After that, BL can only move focus to TR (focusT), it will ignore the TL window that is directly above. This is reproducible every time for me. I think the order of scanning diagonally versus straight can be improved. |
You mean that you would like to be able to go from BL to TR by using the |
Actually the above is already possible so it would be going from TR to BL with the |
However using the the window diagonals as cone is not necessary a very good idea because it means that each window would have a different cones based on its dimentions which would be confusing. Would be nice only in this specific case. Also monitor's diagonal angle could be used, not sure as well it it is a good idea. Maybe I can add a third step that tries with an even larger cone if it fails in the 45° cone but I am not sure it is a good idea either. Because it would go back to the first problem that if you have overlap in the regions then you may have windows that become impossible to select in some cases. |
The current implementation with hooks1.62test7_x64.zip can move focus between BL and TR using focusT or focusB. However, after that, while in BL, I issued the focusT to try to focus the window TL that is directly above, it focused the TR instead. When the focus moved from TR to BL. The BL can only move focus to back TR instead of TL when issuing focusT from it. This is confusing. |
@RamonUnch , there is a demo of this issue. Keys about bound with Ctrl+Win+Alt+H, J, K, L for left, down, top, and right. |
That is very strange, I am unable to reproduce: When I hit Ctrl+Win+Alt+K from BL, I only get TL selected and never TR. Try with opening in notepad files with different names so that we can check in the ad.log file which one AltSnap tries to focus. |
Here are the screenshot and log file. To reproduce, I toggled the between TL and BL a few times. Then I move to TR from TL. Then focusB forces TR to BL as there is no other window directly under it. After that, FocusB/T will only move focus between BL and TR. I named the files in notepad with the windows location they represent. So the log file will be more helpful. |
Try again with this build? At this point math seems to be non-reproducible because it SocusT should not be able to do BL->TR and FocusB should not even be able to do TR->BL. |
@RamonUnch, the test8 works as intended as I tried with no overlapping windows and windows overlapped a little bit. The algorithms is what I intended to have to be able to move the focus to. I don't find any odd behavior so far. Thank you so much! |
A feature I sorely miss from many linux distros is the ability to move window focus in a direction relative to the currently focused window with keyboard shortcuts. The following image illustrates what I mean (shortcuts shown are just an example):
I haven't been able to find anything out there for windows that does it, and I think it would be an amazing addition to the (already fantastic) AltSnap feature set - especially when combined with snap layouts.
The text was updated successfully, but these errors were encountered: