Jump to content

Setting Mouse Boundries and Window Borders


Christopher Blue
 Share

Recommended Posts

I am trying to run Warcraft 3 in Windowed mode. However it presented two problems:

Problem 1. The game window has the standard Windows XP borders and also, it doesn't set itself to my desktop resolution (1024x768). Since the taskbar is larger than 12 pixels, I could not simply increase its size and then move it a little off-screen to compensate although I tried. However, I was told of WinCheat which allowed me to manually remove the Window borders at runtime. While it *does* present a solution to my problem, I am curious is AutoIt could either (a)talk to WinCheat and therefore automate it, or (b)remove the borders itself thus eliminating the need for WinCheat. I was unsuccessful at finding anything about border removal when using the stable AutoIt version but I am curious: Is there a DLL I might call (thanks to the new DLLCall) that would allow me to do what WinCheat does?

Problem 2. I have dual monitors and anyone who has played Warcraft 3 knows that it involves alot of mouse scrolling. However, in Windowed mode Warcraft 3 doesn't trap the mouse within it's borders and thus the mouse can fly right outside the game window which is extremely disorienting and basically makes War3 unplayable. I have tried making my own mouse trapping script but it is slow and doesn't work well:

#cs

Algorithm:
Get Active Window
Find Window 
Get Window Dimensions
Check Mouse Location against window dimensions
Move Mouse to closest valid coordinate

#ce

Opt("WinTitleMatchMode", 3)
Opt("MouseCoordMode", 0)

Global $window_name = "Warcraft III"
Global $shrink = 7
Global $titlebar = 26
Global $rest = 5
Global $hotkey1 = "{F1}"
Global $hotkey2 = "{F2}"
Global $Paused = 0
Global $window_info = WinGetPos($window_name)

HotKeySet($hotkey1, "TogglePause")
HotKeySet($hotkey2, "RecalculateWindow")


while (1)
    CheckBoundries()
    Sleep($rest)
WEnd

Func CheckBoundries()
    If (WinActive($window_name)) Then
        $mouse_info = MouseGetPos()

        ; Left
        If ($mouse_info[0] < $shrink) Then
            MouseMove($shrink + 1, $mouse_info[1], 0)
        EndIf        

        ; Left-Up
        If (($mouse_info[0] < $shrink) AND ($mouse_info[1] < $shrink + $titlebar)) Then
            MouseMove($shrink + 1, $shrink + $titlebar + 1, 0)
        EndIf

        ; Up
        If ($mouse_info[1] < $shrink + $titlebar) Then
            MouseMove($mouse_info[0], $shrink + $titlebar + 1, 0)
        EndIf

        ; Right-Up
        If (($mouse_info[0] > $window_info[2] - $shrink) AND ($mouse_info[1] < $shrink + $titlebar)) Then
            MouseMove($window_info[2] - $shrink - 1, $shrink + $titlebar + 1, 0)
        EndIf

        ; Right
        If ($mouse_info[0] > $window_info[2] - $shrink) Then
            MouseMove($window_info[2] - $shrink - 1, $mouse_info[1], 0)
        EndIf

        ; Right-Down
        If (($mouse_info[0] > $window_info[2] - $shrink) AND ($mouse_info[1] > $window_info[3] - $shrink)) Then
            MouseMove($window_info[2] - $shrink - 1, $window_info[3] - $shrink - 1, 0)    
        EndIf

        ; Down
        If ($mouse_info[1] > $window_info[3] - $shrink) Then
            MouseMove($mouse_info[0], $window_info[3] - $shrink - 1, 0)
        EndIf

        ; Left-Down
        If (($mouse_info[0] < $shrink) AND ($mouse_info[1] > $window_info[3] - $shrink)) Then
            MouseMove($shrink + 1, $window_info[3] - $shrink - 1, 0)    
        EndIf

    EndIf
EndFunc

Func TogglePause()
    $Paused = NOT $Paused
    While $Paused
        Sleep(100)
    WEnd
EndFunc

Func RecalculateWindow()
    $window_info = WinGetPos($window_name)
EndFunc

The mouse is trapped, but it jumps around alot and isn't fully responsive near the screen edges. Is there a way to either improve my script or perhaps, redefine the mouse boundries at a very low-level so Window's traps the mouse instead of my crappy script?

Edited by Christopher Blue
Link to comment
Share on other sites

  • Administrators

I've just finishing changing the mouse/pixel commands so that in addition to the usual "screen" and "window" modes that are used for coordinate there is a "client" mode that uses coords relative to the window's client area (the bit inside the window frame). Will this make this problem go away?

Link to comment
Share on other sites

to DLLCalls

GetWindowLong

SetWindowLong

I can't remember how to remove styles from the result of GetWindowLong and apply it to SetWindowLong... I will research and try to answer before the more brainy (Valik, Jon) people get to it...

Lar.

<{POST_SNAPBACK}>

Use either BitNOT to remove it, or use BitAND to test to see if it exists and then if so, use BitXOR to remove it. In C, it looks like:

style = GetWindowLong();
if (style & StyleIWantToRemove)
    SetWindowLong(style ^ StyleIWantToRemove)

(It should go without saying that the code isn't valid, that its only concept code)

Link to comment
Share on other sites

Larry:

I will start reading about the Windows Classes Reference.

Jon:

That will help me simplify my code since I don't have to take the Window borders into consideration, but I suspect my code will still be as slow and jumpy as before and thus I am curious as to if there is a low-level solution to setting Mouse Boundries. I mean, if Windows can tell the mouse that 768 is the max Y and 1024 (2048 in my dual monitor situation) is the max X, perhaps there is a way to change those values and thus make the mouse run in a box of the programmer's choosing. It doesn't even have to be that specific for I am merely trying to get it to stay within the area of a client Window (Warcraft III's game screen).

Link to comment
Share on other sites

I am currently simplfying my mouse bounding script for when the window is bounded on three sides by the screen edges which is the case once I use WinCheat to take away the borders and then reposition the window in the upper left corner of my left-monitor. Since the borders are gone, I can easily resize War3 to 1024x768 using AutoIt.

I shall post the simplified mouse trap soon but I still believe it is just a bandaid until I find out something lower level.

Link to comment
Share on other sites

example I wrote...

@Valik: My implementation of Bit commands work... is there a simpler syntax?

#include <GUIConstants.au3>

Global $GWL_STYLE = -16

$hWnd = WinGetHandle("AutoIt Forums")

$OldStyle = DLLCall( "user32.dll", "long", "GetWindowLong", "hwnd", $hWnd, "int", $GWL_STYLE )
If @error Then Exit
$OldStyle = $OldStyle[0]

$NewStyle = BitAND($OldStyle,BitNOT($WS_CAPTION) )

DLLCall( "user32.dll", "long", "SetWindowLong", "hwnd", $hWnd, "int", $GWL_STYLE, "long", $NewStyle )

Sleep(2000)

DLLCall( "user32.dll", "long", "SetWindowLong", "hwnd", $hWnd, "int", $GWL_STYLE, "long", $OldStyle )
WinSetState($hWnd,"",@SW_MINIMIZE)
WinSetState($hWnd,"",@SW_RESTORE)

<{POST_SNAPBACK}>

I prefer wrapping DllCall() functions in functions to make them more "natural" (and reusable). As far as the bitwise stuff goes, Shouldn't that be BitOR and not BitAND?

Edit: Never mind, BitAND is correct, my brain is frazzled; I've been looking at COM way too much this morning. Is what you have the functional equivalent to:

If BitAND($Style, $WS_CAPTION) Then $Style = BitXOR($Style, $WS_CAPTION)

Edit2: Ignore me, my brain is taking a nap for a little while. Playing with vectors of pointers and COM does that to me.

Edited by Valik
Link to comment
Share on other sites

Absolutely incredible Larry! Your code works perfectly. I have implemented your suggestions and rolled the resulting script into my hide/unhide script:

#include <GUIConstants.au3>

Global $window_name = "Warcraft III"
Global $hidden = 0
Global $GWL_STYLE = -16

HotKeySet("^q", "ToggleWindowHide")

;Remove the window borders
$hWnd = WinGetHandle($window_name)

$OldStyle = DLLCall( "user32.dll", "long", "GetWindowLong", "hwnd", $hWnd, "int", $GWL_STYLE )
If @error Then Exit
$OldStyle = $OldStyle[0]

$NewStyle = BitAND($OldStyle,BitNOT($WS_DLGFRAME) )
$NewStyle = BitAND($NewStyle,BitNOT($WS_THICKFRAME) )
$NewStyle = BitAND($NewStyle,BitNOT($WS_BORDER) )

DLLCall( "user32.dll", "long", "SetWindowLong", "hwnd", $hWnd, "int", $GWL_STYLE, "long", $NewStyle )

; Move the Window into postion and resize it
WinMove($window_name, "", 0, 0, 1024, 768)

; Wait for hotkey input
while (1)
    Sleep (2147483647)
WEnd

; Hides/Unhides window
Func ToggleWindowHide()
    If ($hidden) Then
        WinSetState ($window_name, "", @SW_SHOW)
    ;WinMove($window_name, "", 0, 0, 1024, 768)
    ;MouseClick("left")
    Else    
        WinSetState ($window_name, "", @SW_HIDE)
    ;WinMove($window_name, "", -5000, -5000)
    ;MouseClick("left")
    EndIf
    $hidden = NOT $hidden
EndFun

Now all that is left to tackle is how to keep the mouse from flying out of the right side of the screen unless I want it to...

Link to comment
Share on other sites

I have refined my mouse trap script: it now only covers the right-hand side. It works but it is imperfect for the mouse, when moved quickly, will escape onto the second monitor for a split-second before it gets lassoed back in.

#cs

Algorithm:
Get Active Window
Find Window 
Get Window Dimensions
Check Mouse Location against window dimensions
Move Mouse to closest valid coordinate

#ce

Opt("WinTitleMatchMode", 3)
Opt("MouseCoordMode", 0)

Global $window_name = "Warcraft III"
Global $rest = 1
Global $hotkey = "{F1}"
Global $Paused = 0
Global $window_info = WinGetPos($window_name)

HotKeySet($hotkey, "TogglePause")

while (1)
    CheckBoundries()
    Sleep($rest)
WEnd

Func CheckBoundries()
    If (WinActive($window_name)) Then
        $mouse_info = MouseGetPos()

        ; Right
        If ($mouse_info[0] >= ($window_info[2] - 2)) Then
            MouseMove($window_info[2] - 2, $mouse_info[1], 0)
        EndIf

    EndIf
EndFunc

Func TogglePause()
    $Paused = NOT $Paused
    While $Paused
        Sleep(100)
    WEnd
EndFunc
Link to comment
Share on other sites

It appears that ClipCursor is reset as soon as another app gains focus. :) I will see if it sticks if I reapply it after the app has gained focus.

edit: Ah it appears that it does stick it reapplied after the app has gained focus. In light of that, I can probably work around it then.

Edited by Christopher Blue
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...