Jump to content

Focus Follows Mouse


WideBoyDixon
 Share

Recommended Posts

Just wrote this as a proof of concept at the moment but I thought I'd share. This script forces the focus to follow the mouse. When the mouse leaves the window then it attempts to restore the previous z-order of the window, based on the order they were retrieved by WinList() in the first place.

#include <Constants.au3>
#include <WinAPI.au3>

Opt("MustDeclareVars", 1)

Global $aWin, $i, $aMousePos, $aWinPos, $hCurrent = 0, $hAfter = 0, $hLast

While True
    $aWin = WinList()
    $aMousePos = MouseGetPos()
    $hLast = 0
    For $i = 1 To $aWin[0][0]
        If BitAND(WinGetState($aWin[$i][1]), 2) Then
            $aWinPos = WinGetPos($aWin[$i][1])
            If ($aMousePos[0] >= $aWinPos[0]) And ($aMousePos[0] < $aWinPos[0] + $aWinPos[2]) And ($aMousePos[1] >= $aWinPos[1]) And ($aMousePos[1] < $aWinPos[1] + $aWinPos[3]) Then
                If Not WinActive($aWin[$i][1]) Then
                    If ($aWin[$i][1] <> $hCurrent) Then
                        If IsHwnd($hCurrent) And ($hAfter <> 0) Then
                            _WinAPI_SetWindowPos($hCurrent, $hAfter, 0, 0, 0, 0, BitOR($SWP_NOMOVE, $SWP_NOSIZE))
                        EndIf
                        $hCurrent = $aWin[$i][1]
                        $hAfter = $hLast
                        WinActivate($hCurrent)
                    EndIf
                EndIf
                ExitLoop
            EndIf
            $hLast = $aWin[$i][1]
        EndIf
    Next
WEnd

I have seen some strange behaviour with it so it's probably not 100% right but it's a start at least. Have fun.

WBD

Link to comment
Share on other sites

Nice work!

I modified it by adding a delay and a sleep function:

#include <Constants.au3>
#include <WinAPI.au3>

Opt("MustDeclareVars", 1)

Global $aWin, $i, $aMousePos, $aWinPos, $hCurrent = 0, $hAfter = 0, $hLast, $timer, $delay = 0.005

While True
    $aWin = WinList()
    $aMousePos = MouseGetPos()
    $hLast = 0
    For $i = 1 To $aWin[0][0]
        If BitAND(WinGetState($aWin[$i][1]), 2) Then
            $aWinPos = WinGetPos($aWin[$i][1])
            If ($aMousePos[0] >= $aWinPos[0]) And ($aMousePos[0] < $aWinPos[0] + $aWinPos[2]) And ($aMousePos[1] >= $aWinPos[1]) And ($aMousePos[1] < $aWinPos[1] + $aWinPos[3]) Then
                If Not WinActive($aWin[$i][1]) Then
                    $timer = TimerInit()
                    If ($aWin[$i][1] <> $hCurrent) Then
                        If IsHwnd($hCurrent) And ($hAfter <> 0) Then
                            _WinAPI_SetWindowPos($hCurrent, $hAfter, 0, 0, 0, 0, BitOR($SWP_NOMOVE, $SWP_NOSIZE))
                        EndIf
                        $hCurrent = $aWin[$i][1]
                        $hAfter = $hLast
                        If TimerDiff($timer) > $delay Then WinActivate($hCurrent)
                    EndIf
                EndIf
                ExitLoop
            EndIf
            $hLast = $aWin[$i][1]
        EndIf
        Sleep(10)
    Next
WEnd

UEZ

Please don't send me any personal message and ask for support! I will not reply!

Selection of finest graphical examples at Codepen.io

The own fart smells best!
Her 'sikim hıyar' diyene bir avuç tuz alıp koşma!
¯\_(ツ)_/¯  ٩(●̮̮̃•̃)۶ ٩(-̮̮̃-̃)۶ૐ

Link to comment
Share on other sites

Also, after I closed the script when I select a window from the tasklist it don't get the top most again. One window is fixed to be the top most. :P

UEZ

Please don't send me any personal message and ask for support! I will not reply!

Selection of finest graphical examples at Codepen.io

The own fart smells best!
Her 'sikim hıyar' diyene bir avuç tuz alıp koşma!
¯\_(ツ)_/¯  ٩(●̮̮̃•̃)۶ ٩(-̮̮̃-̃)۶ૐ

Link to comment
Share on other sites

That's the strange behaviour I had! Some windows seem to get fixed as topmost so I couldn't see windows underneath them unless they were minimised (or moved). I was hoping someone could figure it out - it must be to do with SetWindowPos but I tried to avoid it by checking for a zero $hAfter :P

I like the idea of having a delay and a sleep in there; thanks for your input.

WBD

Link to comment
Share on other sites

There's still something not quite right here but I've made this a little better. I've also allowed configuration of the options to try and match the X-Mouse functionality in TweakUI.

#include <ButtonConstants.au3>
#include <Constants.au3>
#include <EditConstants.au3>
#include <File.au3>
#include <GUIConstantsEx.au3>
#include <Misc.au3>
#include <StaticConstants.au3>
#include <WinAPI.au3>
#include <WindowsConstants.au3>

#NoTrayIcon

Opt("MustDeclareVars", 1)

Global $aNow, $hNext = 0, $hLast = 0, $iTimer = 0
Global $fActivate, $iDelay

_ReadIniFile()
_WriteIniFile()
_CreateTrayMenu()

While True
    $aNow = _GetMouseWindow()
    If ($aNow[0] <> 0) And (WinActive($aNow[0]) = 0) Then
        If ($hNext = $aNow[0]) Then
            If TimerDiff($iTimer) > $iDelay Then
                WinActivate($hNext)
                If ($fActivate = 0) And ($aNow[0] <> 0) Then
                    _WinAPI_SetWindowPos($hNext, $aNow[1], 0, 0, 0, 0, BitOR($SWP_NOSIZE, $SWP_NOMOVE))
                EndIf
                $hNext = 0
                $iTimer = 0
            EndIf
        Else
            $hNext = $aNow[0]
            $hLast = $aNow[1]
            $iTimer = TimerInit()
        EndIf
    EndIf
    Sleep(50)
WEnd

Func _GetMouseWindow()
    Local $i, $aWin = WinList(), $aMousePos = MouseGetPos(), $aWinPos, $aRet[2] = [0, 0]
    For $i = 1 To $aWin[0][0]
        If (BitAND(WinGetState($aWin[$i][1]), 18) = 2) And ($aWin[$i][0] <> "Program Manager") And (_WinAPI_GetClassName($aWin[$i][0]) <> "Shell_TrayWnd") Then
            $aWinPos = WinGetPos($aWin[$i][1])
            If ($aMousePos[0] >= $aWinPos[0]) And ($aMousePos[0] < $aWinPos[0] + $aWinPos[2]) And ($aMousePos[1] >= $aWinPos[1]) And ($aMousePos[1] < $aWinPos[1] + $aWinPos[3]) Then
                $aRet[0] = $aWin[$i][1]
                ExitLoop
            EndIf
            $aRet[1] = $aWin[$i][1]
        EndIf
    Next
    Return SetError(0, 0, $aRet)
EndFunc   ;==>_GetMouseWindow

Func _CreateTrayMenu()
    Opt("TrayOnEventMode", 1)
    Opt("TrayMenuMode", 1)
    TraySetClick(16)
    TrayCreateItem("&Settings...")
    TrayItemSetOnEvent(-1, "_ChangeSettingsGUI")
    TrayItemSetState(-1, $TRAY_DEFAULT)
    TrayCreateItem("E&xit")
    TrayItemSetOnEvent(-1, "_ExitApplication")
    TraySetToolTip("X-11 Mouse")
    TraySetState()
EndFunc   ;==>_CreateTrayMenu

Func _ChangeSettingsGUI()
    GUICreate("X-11 Mouse Settings", 229, 130, -1, -1)
    GUICtrlCreateGroup("General settings", 10, 6, 209, 81)
    Local $chkAutoraise = GUICtrlCreateCheckbox("Autoraise when activating", 26, 30, 209, 17)
    GUICtrlCreateLabel("Activation delay (ms):", 26, 54, 104, 17)
    Local $txtDelay = GUICtrlCreateInput("", 130, 51, 41, 21)
    GUICtrlCreateGroup("", -99, -99, 1, 1)
    Local $btnOK = GUICtrlCreateButton("OK", 152, 96, 65, 25, 0)
    GUICtrlSetState($chkAutoraise, _Iif($fActivate = 1, $GUI_CHECKED, $GUI_UNCHECKED))
    GUICtrlSetData($txtDelay, String($iDelay))
    GUISetState(@SW_SHOW)

    Local $nMsg
    While 1
        $nMsg = GUIGetMsg()
        Switch $nMsg
            Case $GUI_EVENT_CLOSE, $btnOK
                ExitLoop
        EndSwitch
    WEnd

    $iDelay = Int(GUICtrlRead($txtDelay))
    $fActivate = _Iif(GUICtrlRead($chkAutoraise) = $GUI_CHECKED, 1, 0)
    _WriteIniFile()

    GUIDelete()
EndFunc   ;==>_ChangeSettingsGUI

Func _ExitApplication()
    Exit
EndFunc   ;==>_ExitApplication

Func _ReadIniFile()
    $iDelay = Int(IniRead(_GetIniFile(), "Settings", "Delay", "250"))
    $fActivate = Int(IniRead(_GetIniFile(), "Settings", "Activate", "1"))
EndFunc   ;==>_ReadIniFile

Func _WriteIniFile()
    IniWrite(_GetIniFile(), "Settings", "Delay", String($iDelay))
    IniWrite(_GetIniFile(), "Settings", "Activate", String($fActivate))
EndFunc   ;==>_WriteIniFile

Func _GetIniFile()
    Local $szDrive, $szDir, $szFName, $szExt, $sIniPath
    _PathSplit(@ScriptFullPath, $szDrive, $szDir, $szFName, $szExt)
    $sIniPath = _PathMake($szDrive, $szDir, $szFName, "ini")
    Return SetError(0, 0, $sIniPath)
EndFunc   ;==>_GetIniFile

Then again, maybe I'll just use TweakUI (although it's not portable) as it obviously has a sneaky advantage up it's sleeve of being able to activate a window without bringing it to the front. :P

WBD

Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...