Autohotkey script for mouse movement in W&G

edited July 2009 in Wallace & Gromit
I wrote an AutoHotkey script that will help users control the movement in W&G with the mouse instead of the keyboard.

There are 2 methods of movement when using this script. Both are accessed by pressing either the left or right mouse button. You may find that when you use the left button for moving, you may accidentally click and trigger a selectable object. That is why I also allow for using the right button to move. It will not trigger the items, so I highly recommend using it instead of the left button.

Method 1:
When you click on the edge of the screen, it will simulate the arrow key for as long as you hold the mouse button down. The corners of the screen will press 2 arrows for diagonal movement.

Method 2:
When the cursor is not at the edges of the screen, you can press and hold the mouse button for movement. After a short user specified delay, the mouse movement will be limited to a small box. Moving to the edges and diagonals of this box will cause the corresponding arrow keys to be pressed. You can use this method anywhere on the screen as long as it is 1 movement box in size from the edge of the screen. The box defaults to 100 pixels, but you can change that.

When the game is running in a window instead of fullscreen, the movement works the same. When you click the mouse in the window it will lock itself into the window so you can easily use Movement Method 1. The mouse will free itself to the full window by pressing the 'F' key or by [Alt][Tab]ing to another running program.

To get this running you will need to install AutoHotkey available here:
www.autohotkey.com

Then download the attached script. Unzip the file some where. When you run it, it will launch the game and you are good to go. When you quit the game, the script will quit so mouse clicks are no longer remapped as arrow keys.

You can also right click on the script file and compile it if you like. Then it can be run on other computers without installing AutoHotkey.

You can edit settings in the script file by right clicking on it and picking Edit Script. Then at the start of the file, look for the following lines to change as you like:

How to change the game:
set episode to 0 for the demo. 1, 2, 3, 4 for the corresponding episode. Other values will give you an error and quit the script.
As of writing this, episodes 3&4 have not been released so I can not test them. I believe it should work fine.
; Set this to the W&G episode you want to run with this script
; 0 = Demo
episode := 1

How to change the button functions:
* Remember using the left button for movement can cause triggerable items to be selected.
set the following values to 0 to disable and 1 to enable.
useEdgesL - enables Movement Method 1 for the left mouse button.
useCenterL - enables Movement Method 2 for the left mouse button.
useEdgesR - enables Movement Method 1 for the right mouse button.
useCenterR - enables Movement Method 2 for the right mouse button.
; set options to 0=disable 1=enable
; Left Button options
useEdgesL  := 1
useCenterL := 1

; Right Button options
useEdgesR  := 1
useCenterR := 1

How to change the delay before Movement Method 2 is activated:
buttonDelayL - time in milliseconds to press the left mouse button.
buttonDelayR - time in milliseconds to press the right mouse button.
; how long in milliseconds to press mouse button in center screen before movement is controlled by mouse dragging
; left move delay
buttonDelayL := 150

; right move delay
buttonDelayR := 50

How to change the Movement Method 2 box size:
boxSize - height and width in pixels of the restricted mouse movement for Movement Method 2
; movement box size in pixels
boxSize := 100

How to change how wide of a selection area at the edge of the game view window that can be pressed for Movement Method 1:
borderPixels - number of pixels in from the edge
; pixels at edge used to select movement
; must be 1 to 25
borderPixels := 5

Have fun. Hopefully TTG does not delete this. If they feel the need to, then please p-mail me with the reason for removing this thread/info.

If for some reason the download is corrupt, you can just copy and paste the following code into a new script file called wg.ahk
; Script Function:
;	Map mouse clicks at the edges of the screen as arrow keys
;   You can also move by holding down the button and dragging the mouse
;   The script will time out after 2 minutes if game is not launched
;   Press 'F' in windowed mode to free the cursor


; Set this to the W&G episode you want to run with this script
; 0 = Demo
episode := 1

; set options to 0=disable 1=enable
; Left Button options
useEdgesL  := 1
useCenterL := 1

; Right Button options
useEdgesR  := 1
useCenterR := 1

; how long in milliseconds to press mouse button in center screen before movement is controlled by mouse dragging
; left move delay
buttonDelayL := 150

; right move delay
buttonDelayR := 50

; movement box size in pixels
boxSize := 100

; pixels at edge used to select movement
; must be 1 to 25
borderPixels := 5


; ==================================
; only change values above this line
; ==================================

#NoEnv  ; Recommended for performance and compatibility with future AutoHotkey releases.
SendMode Input  ; Recommended for new scripts due to its superior speed and reliability.
#SingleInstance ignore ; only allow 1 running script
SetTitleMatchMode, 3  ; Names must be exact

; check values
if (borderPixels < 1 OR borderPixels > 25)
{
  MsgBox, borderPixels value out of range
  ExitApp
}

timeDelayL  := buttonDelayL // 10
timeDelayR  := buttonDelayR // 10
movePixels := boxSize // 2
edgeMargin := movePixels * 2 + borderPixels
border := borderPixels
mouseLocked := 0

; setup paths and file
if (episode = 0)
{
gameFile = WallaceGromitDemo.exe
launcherName = Wallace & Gromit Demo
}
else if (episode = 1)
{
gameFile = WallaceGromit101.exe
launcherName = Fright of the Bumblebees
}
else if (episode = 2)
{
gameFile = WallaceGromit102.exe
launcherName = The Last Resort
}
else if (episode = 3)
{
gameFile = WallaceGromit103.exe
launcherName = Muzzled!
}
else if (episode = 4)
{
gameFile = WallaceGromit104.exe
launcherName = The Bogey Man
}
else
{
  MsgBox, Invalid Episode #
  ExitApp
}
gameReg  = SOFTWARE\Telltale Games\%gameFile%
RegRead, gameDir, HKEY_LOCAL_MACHINE, %gameReg% , Install Location

; this is the name of the game as shown on the task bar
; Demo, Ep1 and Ep2 all use the same name, so I assume all episodes will
gameName = Telltale Games


; launch game
Run, %gameFile%, %gameDir%, UseErrorLevel
if ErrorLevel = ERROR
{
  MsgBox, Episode %episode% could not be found
  ExitApp
}
winwait, %gameName%, , 120
if ErrorLevel
{
  ExitApp
}
gameID := WinExist(gameName)
WinActivate, ahk_id %gameID%
SetTimer, gameCheck  ; check every 250ms
; setup rect variable for DLL call
VarSetCapacity(rect, 16)
return


gameCheck:
;------------------------------
; quit script on game exit
;------------------------------
if ((mouseLocked AND isFullScreen()) OR !WinActive("ahk_id" . gameID))
{
  ; free the mouse if we switched modes or window no longer active
  DllCall("ClipCursor")
  mouseLocked := 0
}
IfWinNotExist, ahk_id %gameID%
{
  ; free the mouse just in case
  DllCall("ClipCursor")
  ExitApp
}
return


~LButton::
useEdges  := useEdgesL
useCenter := useCenterL
timeDelay := timeDelayL
testButton = LButton
Gosub, mouseToArrows
return


~RButton::
useEdges  := useEdgesR
useCenter := useCenterR
timeDelay := timeDelayR
testButton = RButton
Gosub, mouseToArrows
return


mouseToArrows:
;------------------------------
; process mouse movement
;------------------------------
usingCenterMove := 0
if (isFullScreen())
{
  ; fullscreen
  CoordMode, Mouse, Screen
  width  := A_ScreenWidth
  height := A_ScreenHeight
  winXpos := 0
  winYpos := 0
  winXoffset := 0
  winYoffset := 0
}
else
{
  ; only do mouse to key conversion in game window
  IfWinNotActive, ahk_id %gameID%
    Return,

  ; get window information
  CoordMode, Mouse, Relative
  WinGetPos, winXpos, winYpos, winWidth, winHeight, ahk_id %gameID%

  ; calculate border info from client window
  ; we do it at every mouse press because the size could change
  DllCall("GetClientRect", "UInt", gameID, "UInt", &rect)
  width  := NumGet(rect,  8, "int")
  height := NumGet(rect, 12, "int")
  winBorderPixels := (winWidth - width) // 2
  winBarPixels := winHeight - height - winBorderPixels

  ; free up mouse if on top bar
  MouseGetPos, , curY
  if (curY < winBarPixels)
    Return,

  winXoffset := winBorderPixels
  winYoffset := winBarPixels
  ; set top left of game window
  ; keep locking the window so the mouse does not get free
  mouseLocked := 1
  Gosub, lockWindow
}

; check aspect ratio and adjust
if (width * 9 // height < 16)
{
  ; top and bottom letterboxed
  newHeight := width * 9 // 16
  edgeLeft  := 0
  edgeRight := width
  edgeUp    := (height - newHeight) // 2
  edgeDown  := edgeUp  + newHeight
}
else
{
  ; sides letterboxed
  newWidth  := height * 16 // 9
  edgeLeft  := (width   - newWidth) // 2
  edgeRight := edgeLeft + newWidth
  edgeUp    := 0
  edgeDown  := height
}

; bottom corner is one pixel in
edgeRight--
edgeDown--

if (useCenter = 1)
{
  timePressed := 0
  ; the valid center movement area
  centerLeft  := edgeLeft  + edgeMargin
  centerRight := edgeRight - edgeMargin
  centerUp    := edgeUp    + edgeMargin
  centerDown  := edgeDown  - edgeMargin
}

While GetKeyState(testButton)
{
  MouseGetPos, curX, curY
  if (!usingCenterMove)
  {
    ; adjust for window border
    curX -= winXoffset
    curY -= winYoffset
  }

  ; remap mouse to arrow keys
  ; only press the down key once
  if (useEdges = 1 OR usingCenterMove = 1)
  {
    if (curX < edgeLeft + border)
    {
      if (!downL)
      {
        Send {Left Down}
        downL := 1
      }
    }
    else
    {
      if (downL)
      {
        Send {Left Up}
        downL := 0
      }
    }

    if (curX > edgeRight - border)
    {
      if (!downR)
      {
        Send {Right Down}
        downR := 1
      }
    }
    else
    {
      if (downR)
      {
        Send {Right Up}
        downR := 0
      }
    }

    if (curY < edgeUp + border)
    {
      if (!downU)
      {
        Send {Up Down}
        downU := 1
      }
    }
    else
    {
      if (downU)
      {
        Send {Up Up}
        downU := 0
      }
    }

    if (curY > edgeDown - border)
    {
      if (!downD)
      {
        Send {Down Down}
        downD := 1
      }
    }
    else
    {
      if (downD)
      {
        Send {Down Up}
        downD := 0
      }
    }
  }

  if (useCenter AND !usingCenterMove)
  {
    ; start counting if in center of screen
    if (curX > centerLeft AND curX < centerRight AND curY > centerUp AND curY < centerDown)
    {
      timePressed++
      if (timePressed > timeDelay)
      {
        ; button down long enough, start using center move
        ; readjust mousepos to real and setup movement box
        curX += winXoffset
        curY += winYoffset
        edgeLeft  := curX - movePixels
        edgeUp    := curY - movePixels
        edgeRight := curX + movePixels
        edgeDown  := curY + movePixels
        ; fill the RECT structure with UInt values
        NumPut(winXpos + edgeLeft     , &rect +  0)
        NumPut(winYpos + edgeUp       , &rect +  4)
        NumPut(winXpos + edgeRight + 1, &rect +  8)
        NumPut(winYpos + edgeDown  + 1, &rect + 12)
        DllCall("ClipCursor", UInt, &rect)
        usingCenterMove := 1
        border := 1
      }
    }
    else
    {
      ; reset count when not in center
      timePressed := 0
    }
  }
Sleep, 10
}

if (usingCenterMove)
{
  ; free the cursor
  if (mouseLocked)
    Gosub, lockWindow
  else
    DllCall("ClipCursor")
  ; reset to view border
  border := borderPixels
}

; unpress any keys that are down
if (downL)
{
  Send {Left Up}
  downL := 0
}
if (downR)
{
  Send {Right Up}
  downR := 0
}
if (downU)
{
  Send {Up Up}
  downU := 0
}
if (downD)
{
  Send {Down Up}
  downD := 0
}
Return,


isFullScreen()
;------------------------------
; check to see if fullscreen
;------------------------------
{
  Global gameID
  WinGet, style, Style, ahk_id %gameID%
  ; 0x800000 is WS_BORDER.
  ; 0x20000000 is WS_MINIMIZE.
  ; no border and not minimized
  Return, (style & 0x20800000) ? 0 : 1
}


~f::
;------------------------------
; free mouse from window
;------------------------------
if (mouseLocked)
{
  IfWinActive, ahk_id %gameID%
  {
    ; free the cursor
    DllCall("ClipCursor")
    mouseLocked := 0
  }
}
Return,


lockWindow:
;------------------------------
; lock mouse to window
;------------------------------
; fill the RECT structure with UInt values
NumPut(winXpos + winBorderPixels,          &rect +  0)
NumPut(winYpos + winBarPixels,             &rect +  4)
NumPut(winXpos + winBorderPixels + width,  &rect +  8)
NumPut(winYpos + winBarPixels    + height, &rect + 12)
DllCall("ClipCursor", UInt, &rect)
Return,

Comments

  • edited May 2009
    Hm. An interesting script. But already when I fired up the game and played through the first couple puzzles, walking around in a small room was a bit unwieldy. Perhaps it was the size of the dining room, or the movement speed being meant for keyboards, but I think I'm going to have to stick with WASD+Mouse with the scroll wheel.
  • edited May 2009
    It says 0 views for the script. Did you download the wg.zip file in the first post?

    There should be no difference in speed from using the keyboard. If you hold the right mouse button down at the edge of the screen it holds the corresponding arrow key down. Or 2 keys at the corners of the screen.

    Of course if you want to move left, then right, you do have to move the mouse from one side of the screen to the other.

    Myself, I just can't get used to using WASD. I do all my gaming from the couch on my HTPC. So it is too much of a pain to use the keyboard on my lap. I remapped my joystick to what I liked, but did not like selecting on-screen items by toggling through them. Which means I still needed a mouse/joystick combo. With this script I can now use only the mouse. I click on selectable items to move, but if I get to a spot when I need to use WASD, now I can just press and hold the right mouse button at the edge of the screen.

    My other thought is to make a script so that if you hold the right mouse button down for a half a second, then it limits the mouse movement to 20 pixels or so, then as you move the mouse around while holding the right button down, the corresponding arrow keys are pressed. I'll probably try that on a rainy day this week.
  • edited May 2009
    Derrick wrote: »
    It says 0 views for the script. Did you download the wg.zip file in the first post?
    I'm quite sure. It's sitting on my desktop as wg.ahk, and it opens up my game and my mouse works and everything.
    There should be no difference in speed from using the keyboard. If you hold the right mouse button down at the edge of the screen it holds the corresponding arrow key down. Or 2 keys at the corners of the screen.
    Yes, I understand that. Which was my POINT, in a way...because the move speed was set for the keyboard, and not for this kind of movement, and so I think the speed feels "off" even though it's exactly the same.

    If I'm making any sense.
    Of course if you want to move left, then right, you do have to move the mouse from one side of the screen to the other.
    Yep. One of the reasons I consider it unwieldy, though interesting.
    Myself, I just can't get used to using WASD. I do all my gaming from the couch on my HTPC. So it is too much of a pain to use the keyboard on my lap. I remapped my joystick to what I liked, but did not like selecting on-screen items by toggling through them. Which means I still needed a mouse/joystick combo. With this script I can now use only the mouse. I click on selectable items to move, but if I get to a spot when I need to use WASD, now I can just press and hold the right mouse button at the edge of the screen.
    And I do need to try it in that capacity sometime. So far I've only used it in small areas full of objects the real point of it would be for places like the hallway. I haven't exactly fully tested it, just made sure it worked. Then I proceeded to dick around for a bit and assess it within a few minutes.
    My other thought is to make a script so that if you hold the right mouse button down for a half a second, then it limits the mouse movement to 20 pixels or so, then as you move the mouse around while holding the right button down, the corresponding arrow keys are pressed. I'll probably try that on a raining day this week.
    That's another interesting solution. I'd like to see what comes of that.
  • edited May 2009
    Gotta love creative people :)

    I was about to replay FotBB before the next episode, so your script came right on time. I played through the game with no major problems - hats off!

    Two things to note:
    - I tried the original script, but I went for the left mouse button after a few minutes, and that worked out much better for me
    - It often happened that the Y-edge of the screen wasn't detected. I had to start moving to either side, and then up or down, and then it worked. It wasn't too bad, just a bit inconvenient at times.

    So, definitely an interesting idea for p&c die-hards, and though not perfect, it works much better thank one would initially expect. Kudos!
  • edited May 2009
    Well, this seems to completely anihilate the excuse tossed around the forums by the staff, that the reason Wallace & Gromit had a keyboard interface is because it just couldn't be done with a mouse, try as they might.

    Ah, well...

    Cheers!
  • edited May 2009
    Well, this seems to completely anihilate the excuse tossed around the forums by the staff, that the reason Wallace & Gromit had a keyboard interface is because it just couldn't be done with a mouse, try as they might.

    Let's not diss TTG too much in this thread please. They will just end up banning the thread like some of my previous threads. cough..S&M-S1@1920x1080..cough...

    TTG are correct in that there is a problem when using the mouse and the screen changes it's view. With my mouse movement script, if you move off the the screen rightclicking at the edge, if the character if facing a different direction in the next view, he will keep moving relative to him and not neccessarily the position still pressed on the screen.
  • edited May 2009
    Derrick wrote: »
    My other thought is to make a script so that if you hold the right mouse button down for a half a second, then it limits the mouse movement to 20 pixels or so, then as you move the mouse around while holding the right button down, the corresponding arrow keys are pressed..
    That's another interesting solution. I'd like to see what comes of that.

    The new version with that feature has been added. Wallace seems to walk like a bit of a drunkard in the new mode, but he still gets around. :)

    You can easily turn on/off right mouse button presses on the edge of screen for movement or the new pressing the right mouse button for 300ms in the center of the screen for movement. Or change how long it takes for a right mouse press in the center of the screen to remap to the arrows.

    When I say center of the screen, I just mean anywhere far enough from the edge of the screen to allow for the movement box size specified.


    The delay in the script is set to 300ms before a right click starts working as move. Myself I set the right click delay to 50ms so you can start moving right away. Seems to work fine.
    Update: I changed the script to default to 50mS.
    buttonDelay := 50
    
  • edited May 2009
    Well, this seems to completely anihilate the excuse tossed around the forums by the staff, that the reason Wallace & Gromit had a keyboard interface is because it just couldn't be done with a mouse, try as they might.

    With this, I disagree. This is an interim solution that works for people who want the mouse based controls so bad that they're willing to put up with some inconveniences. However, it's not a solution I'd put in the retail version of my game.
  • edited May 2009
    With this, I disagree. This is an interim solution that works for people who want the mouse based controls so bad that they're willing to put up with some inconveniences. However, it's not a solution I'd put in the retail version of my game.

    Just curious if you have tried my newer version of the script that lets you hold down the right mouse button to move.

    The combination of the 2 modes has finally made me want to try the game for more then 5 minutes. But the batteries in the mouse died, so I have not completed the game yet. :rolleyes:

    I do have thoughts on how TTG could do the mouse control, but I don't beleive they care. They have made up their minds and will not change.
  • edited May 2009
    Not sure why the download is currupt now. I tried re-uploading it and even tried attaching it to this post, but it still is currupt for me.

    So I added the script text to the initial post. Just create a blank text file. Copy and paste the script text into it. Then rename the file to: wg1.ahk
  • edited May 2009
    Derrick wrote: »
    Just curious if you have tried my newer version of the script that lets you hold down the right mouse button to move.

    I'll try it this or next evening, but I'm quite sure what the result will be - it won't feel natural to me. The exact reason why I liked your original script (modded to the left button) is that it's very close to the point-and-click method - keeping the button pressed is intuitive enough, and the game has a rich environment which means it's always easy to find objects to interact with when I'm not moving towards the edge of the screen. I did have minor navigation problems (most notably, it was a bit painful to reach the front door from the outside), but on the other hand, I was able to assume my usual ultra-comfortable adventure gaming position, and it is more than worth a few minor troubles :D
    Derrick wrote: »
    I do have thoughts on how TTG could do the mouse control, but I don't beleive they care. They have made up their minds and will not change.

    To be honest, I quite understand them. They had to come up with a control scheme that fits both the XBox and the PC, and the way the scenes are shot, a direct control approach certainly seems more obvious.
    As for not offering a secondary, mouse based control scheme: I'd do the same in their place, and would undertake the extra fuss for maintaining a secondary scheme only if the market response would force me to.
  • edited May 2009
    I'll try it this or next evening, but I'm quite sure what the result will be - it won't feel natural to me. The exact reason why I liked your original script (modded to the left button) is that it's very close to the point-and-click method - keeping the button pressed is intuitive enough

    I just updated the script, hopefully for the last time.

    You can now select to use the left/right mouse button for either of the 2 movement types.

    You can now also easily change the episode number. Or even use the demo. It will find the game path from the registry.

    The first post in this thread has been updated with all the info.

    Also... Could someone tell me if the script downloads corrupted for them? Ever since I modified the first post, it now seems to pad the file with a few extra bytes at the beginning, corrupting the file.
  • edited May 2009
    Derrick wrote: »
    I just updated the script, hopefully for the last time.

    You can now select to use the left/right mouse button for either of the 2 movement types.

    You can now also easily change the episode number. Or even use the demo. It will find the game path from the registry.

    The first post in this thread has been updated with all the info.

    Also... Could someone tell me if the script downloads corrupted for them? Ever since I modified the first post, it now seems to pad the file with a few extra bytes at the beginning, corrupting the file.

    I'll try it - now with The Last Resort :)
    The file download works fine for me, there's no corruption!
  • edited May 2009
    Well atm the Keyboard arent working 100% either, quite alot of time, it makes the same problems are people say with this script, that you walk in wrong direction or doesnt move at all.

    So atm no solution is 100%, i would still prefer the mouse, i must say, im not gonna buy another season if the control scheme doesnt change. Just ruins the game for me. :(

    Atleast this script will make Season 1 work for me.
  • [TTG] Yare[TTG] Yare Telltale Alumni
    edited May 2009
    Cool beans.

    I've never used AutoHotKey before. How does the "screen edge" stuff cope with the game in windowed mode, or with multiple monitors?
  • edited May 2009
    I'll try it - now with The Last Resort :)
    The file download works fine for me, there's no corruption!

    OK, I tried the mouse movement solution - it works pretty well, but as I predicted, it's not my automatic choice for movement. It's nice however when the edge detection has difficulties.

    Good stuff! :)
  • edited May 2009
    [TTG] Yare wrote: »
    Cool beans.

    Thanks for trying it out. I found myself using Movement Method 2 mostly.
    [TTG] Yare wrote: »
    I've never used AutoHotKey before. How does the "screen edge" stuff cope with the game in windowed mode, or with multiple monitors?

    I just started playing with AutoHotkey myself. I've used it for a few keystroke macros in the past, but this is the first fancy thing I've used it for.

    First let me mention my goal is not to diss TTG's design decision. You guys have been playing with the new controls longer then us and have probably got used to them. For me I could not get past the issue long enough to play. Even after re-mapping my joystick. It worked great with a joystick, but then I missed how easy it is to select on-screen items with the mouse.

    The only way I could play the game long enough to enjoy it was to write this script. And for better or worse, I thought I would share it.

    Anyways....
    I did not attempt, or even thought about making this script compatible with either Windowed mode or Multi-Monitors. But as I am really just hacking into the mouse movement, anything other then full screen would be a pain to do. While I'm trying to work out something, here are some thoughts:

    Windowed Mode:
    Currently you have the mouse get sticky when you move to the top of the window. You have to move the mouse harder to get it out of the view window. Very nice and that makes it easy to click for movement on the top edge. Unfortunately the same is not true for the other 3 sides. Actually the bottom is sticky in game but not when the menu panel is on-screen.

    I could probably force the mouse to be a bit sticky myself. But for the sake of argument, here is how I would handle it if it was coded in the game.

    First, when in windowed mode, I would get rid of the resolution selection and just make the window resizeable. It would be a fixed 16:9 resize, that way there is no black area like when you use 800x600 windowed. Now the edges of the view are defined by the program window. Then we make the mouse sticky when it is in the window on all four edges. Probably even a bit stickier then you have it set at the top now. This would make it so you can easily click at the edge of the window for movement.

    Of course if it was programed in game, you could easily use the left mouse button. If the edges are clicked and pressed, it would ignore any selectable item. But with the script, all I can do is recommend to use the right button so items are not triggered.

    From a script POV based on the current game workings, I would have to calculate the aspect ratio, fudge up some data and do a best guess where the game view window is. Then make it sticky to that.

    Multi-Monitor Mode: would probably be easier to do. But I have no way of testing it. To be honest, I have never even tried the script in a mode other then 16:9. So I will have to try that after dinner and a trip to the last resort.

    Movement Mode 1. Just some thoughts how this would work if used in a future game. The cursor would change to the arrow of the direction at the edge of the screen acknowledging you will be pressing the button for movement. Obviously in game code it would be easy to ignore selecting on-screen items while moving with the left mouse button pressed.

    Movement Mode 2. Just like mode 1, but you could draw an arrow in the movement box that follows the 8 directions. The neat thing about this movement mode is that if you drag left for instance, and W/G moves left in the current view, then the screen changes and he is moving down the screen, as long as you don't move the mouse, W&G will keep moving in the original direction. At that point any future game code can change the direction of the on-screen arrow, move the the mouse position in the movement box to compensate and things will remain smooth.

    Well, enough rambling for now.
  • edited May 2009
    OK, I tried the mouse movement solution - it works pretty well, but as I predicted, it's not my automatic choice for movement. It's nice however when the edge detection has difficulties.

    Thanks for trying and giving feedback.

    FWIW, I have not had any selection problems with the edge movement. I know in Ep1 when you are in the front yard trying to go to the front door, it can be tricky to get to. But I had the same problems with the keyboard and joystick. Remember, you can always click on the corners for diagonals. Also like I mentioned, there can be problems with using the left button for moving due to it activating any selectable items during movement. Which is why I use the right button. I do tend to use the left for edge movement because that seems more natural after years playing adventure games. But my brain is surprisingly happy with the right button for the new Movement Mode 2.

    Just out of curiosity, what video resolution are you using? I have only tried 16:9 modes. I imagine you are not trying a windowed mode. I never even thought about that until [TTG] Yare mentioned it.

    EDIT: I think I see what you mean. I tried 1024x768 and it seemed harder to select at the bottom. I'll look into adding a border size option to give more selection area.
  • edited May 2009
    however when the edge detection has difficulties.

    Try this test version. It compensates for aspect ratios that are not exactly 16x9. Also it seems that even though the mouse looks like it stops at any letter-boxing, it really goes into it. So you can push past the border making the mouse slow to come out of it. I now select the whole area as the movement click.

    There is also a new borderPixels setting that be changed so the mouse does not have to be exactly at the edge.

    EDIT: The top post has been updated to the newest version.

    Here is the script in case the download is corrupt:
    ; Script Function:
    ;	Map mouse clicks at the edges of the screen as arrow keys
    ;   You can also move by holding down the button and dragging the mouse
    ;   The script will time out after 2 minutes if game is not launched
    
    
    ; Set this to the W&G episode you want to run with this script
    ; 0 = Demo
    episode := 1
    
    ; set options to 0=disable 1=enable
    ; Left Button options
    useEdgesL  := 1
    useCenterL := 1
    
    ; Right Button options
    useEdgesR  := 1
    useCenterR := 1
    
    ; how long in milliseconds to press mouse button in center screen before movement is controlled by mouse dragging
    ; left move delay
    buttonDelayL := 150
    
    ; right move delay
    buttonDelayR := 50
    
    ; movement box size in pixels
    boxSize := 100
    
    ; pixels at edge used to select movement
    ; must be 1 to 25
    borderPixels := 5
    
    ; ==================================
    ; only change values above this line
    ; ==================================
    
    #NoEnv  ; Recommended for performance and compatibility with future AutoHotkey releases.
    SendMode Input  ; Recommended for new scripts due to its superior speed and reliability.
    #SingleInstance ignore ; only allow 1 running script
    SetTitleMatchMode, 3  ; Names must be exact
    CoordMode, Mouse, Screen
    
    ; check values
    if (borderPixels < 1 OR borderPixels > 25)
    {
      MsgBox, borderPixels value out of range
      ExitApp
    }
    
    timeDelayL  := buttonDelayL // 10
    timeDelayR  := buttonDelayR // 10
    movePixels := boxSize // 2
    edgeMargin := movePixels * 2 + borderPixels
    
    ; setup paths and file
    if (episode = 0)
    {
    gameFile = WallaceGromitDemo.exe
    launcherName = Wallace & Gromit Demo
    }
    else if (episode = 1)
    {
    gameFile = WallaceGromit101.exe
    launcherName = Fright of the Bumblebees
    }
    else if (episode = 2)
    {
    gameFile = WallaceGromit102.exe
    launcherName = The Last Resort
    }
    else if (episode = 3)
    {
    gameFile = WallaceGromit103.exe
    launcherName = Muzzled!
    }
    else if (episode = 4)
    {
    gameFile = WallaceGromit104.exe
    launcherName = The Bogey Man
    }
    else
    {
      MsgBox, Invalid Episode #
      ExitApp
    }
    gameReg  = SOFTWARE\Telltale Games\%gameFile%
    RegRead, gameDir, HKEY_LOCAL_MACHINE, %gameReg% , Install Location
    
    ; this is the name of the game as shown on the task bar
    ; Demo and Ep1 both use the same name, so I assume all episodes will
    gameName = Telltale Games
    
    
    ; launch game
    Run, %gameFile%, %gameDir%, UseErrorLevel
    if ErrorLevel = ERROR
    {
      MsgBox, Episode %episode% could not be found
      ExitApp
    }
    winwait, %gameName%, , 120
    Gosub, gameCheck
    WinActivate, %gameName%
    SetTimer, gameCheck
    return
    
    
    ; quit script if game is not running
    gameCheck:
    IfWinNotExist, %gameName%
    {
      ExitApp
    }
    return
    
    
    ~LButton::
    useEdges  := useEdgesL
    useCenter := useCenterL
    timeDelay := timeDelayL
    testButton = LButton
    Gosub, mouseToArrows
    return
    
    
    ~RButton::
    useEdges  := useEdgesR
    useCenter := useCenterR
    timeDelay := timeDelayR
    testButton = RButton
    Gosub, mouseToArrows
    return
    
    
    mouseToArrows:
    timePressed := 0
    usingCenterMove := 0
    border := borderPixels
    ; This would be how you get the multi-screen size
    ; but the values seem to change
    ;SysGet, screenWidth, 78
    ;SysGet, screenHeight, 79
    
    ; check aspect ratio and adjust
    if (A_ScreenWidth * 9 // A_ScreenHeight < 16)
    {
      ; top and bottom letterboxed
      newHeight := A_ScreenWidth * 9 // 16
      edgeUp := (A_ScreenHeight - newHeight) // 2
      edgeDown := edgeUp + newHeight
      edgeLeft := 0
      edgeRight := A_ScreenWidth
    
    }
    else
    {
      ; sides letterboxed
      newWidth := A_ScreenHeight * 16 // 9
      edgeLeft := (A_ScreenWidth - newWidth) // 2
      edgeRight := edgeLeft + newWidth
      edgeUp := 0
      edgeDown := A_ScreenHeight
    }
    
    ; bottom corner is one pixel in
    edgeRight--
    edgeDown--
    
    While GetKeyState(testButton)
    {
      MouseGetPos, curX, curY
    
      if (useEdges = 1 OR usingCenterMove = 1)
      {
        if (curX < edgeLeft + border)
        {
          downL := 1
          Send {Left Down}
        }
        else
        {
          if (downL = 1)
          {
            Send {Left Up}
          }
          downL := 0
        }
    
        if (curX > edgeRight - border)
        {
          downR := 1
          Send {Right Down}
        }
        else
        {
          if (downR = 1)
          {
            Send {Right Up}
          }
          downR := 0
        }
    
        if (curY < edgeUp + border)
        {
          downU := 1
          Send {Up Down}
        }
        else
        {
          if (downU = 1)
          {
            Send {Up Up}
          }
          downU := 0
        }
    
        if (curY > edgeDown - border)
        {
          downD := 1
          Send {Down Down}
        }
        else
        {
          if (downD = 1)
          {
            Send {Down Up}
          }
          downD := 0
        }
      }
    
      if (useCenter = 1 AND usingCenterMove = 0)
      {
        ; start counting if in center of screen
        if (curX > edgeLeft + edgeMargin AND curX < edgeRight - edgeMargin AND curY > edgeUp + edgeMargin AND curY < edgeDown - edgeMargin)
        {
          timePressed++
          if (timePressed > timeDelay)
          {
            ; button down long enough, start using center move
            edgeLeft  := curX - movePixels
            edgeUp    := curY - movePixels
            edgeRight := curX + movePixels
            edgeDown  := curY + movePixels
            border := 1
            VarSetCapacity(R, 16, 0), NumPut(edgeLeft, &R+0), NumPut(edgeUp, &R+4), NumPut(edgeRight+1, &R+8), NumPut(edgeDown+1, &R+12)
            DllCall( "ClipCursor", UInt, &R )
            usingCenterMove := 1
          }
        }
        else
        {
          ; reset count when not in center
          timePressed := 0
        }
      }
    Sleep, 10
    }
    
    if (usingCenterMove = 1)
    {
      ; free the cursor
      DllCall( "ClipCursor")
    }
    
    ; unpress any keys that are down
    if (downL = 1)
    {
      Send {Left Up}
    }
    downL := 0
    if (downR = 1)
    {
      Send {Right Up}
    }
    downR := 0
    if (downU = 1)
    {
      Send {Up Up}
    }
    downU := 0
    if (downD = 1)
    {
      Send {Down Up}
    }
    downD := 0
    return
    
  • edited May 2009
    Derrick wrote: »
    Try this test version. It compensates for aspect ratios that are not exactly 16x9. Also it seems that even though the mouse looks like it stops at any letter-boxing, it really goes into it. So you can push past the border making the mouse slow to come out of it. I now select the whole area as the movement click.

    Hmmm, interesting. You got the problem right - I was playing at 1280x1024. The aspect ratio problem did cross my mind, but I thought then I wouldn't be able to move towards the Y-edges at all, and dissed the idea :)

    I'll try the new version after work.

    Cheers!
  • edited May 2009
    Derrick wrote: »
    Try this test version.

    Yes, it works now! Great!
  • edited May 2009
    [TTG] Yare wrote: »
    How does the "screen edge" stuff cope with the game in windowed mode, or with multiple monitors?

    Here is a test version with windowed support. Because I don't have good direct access to the mouse in a DX game from outside it, the best I can do is this.

    If you click in the game window, the mouse will lock to the window. The movement modes will then behave exactly like full screen. To move the mouse out of the window you must first press the 'F' key to Free the mouse.

    Depending on you system, you may have to change theses values:
    ; windowed mode info
    ; I need to see if this can be read automatically
    ; you may have to change these to suit your computer
    winBarPixels := 29    ; top bar
    winBorderPixels := 3  ; other 3 edges
    

    This version also incudes a fix where I keep sending down keystrokes when the mouse is pressed. You won't notice the difference in game, but it technically cleans up and speeds up the code.
    ; Script Function:
    ;	Map mouse clicks at the edges of the screen as arrow keys
    ;   You can also move by holding down the button and dragging the mouse
    ;   The script will time out after 2 minutes if game is not launched
    ;   Press 'F' in windowed mode to free the cursor
    
    
    ; Set this to the W&G episode you want to run with this script
    ; 0 = Demo
    episode := 1
    
    ; set options to 0=disable 1=enable
    ; Left Button options
    useEdgesL  := 1
    useCenterL := 1
    
    ; Right Button options
    useEdgesR  := 1
    useCenterR := 1
    
    ; how long in milliseconds to press mouse button in center screen before movement is controlled by mouse dragging
    ; left move delay
    buttonDelayL := 150
    
    ; right move delay
    buttonDelayR := 50
    
    ; movement box size in pixels
    boxSize := 100
    
    ; pixels at edge used to select movement
    ; must be 1 to 25
    borderPixels := 5
    
    
    ; ==================================
    ; only change values above this line
    ; ==================================
    
    ; windowed mode info
    ; I need to see if this can be read automatically
    ; you may have to change these to suit your computer
    winBarPixels := 29    ; top bar
    winBorderPixels := 3  ; other 3 edges
    
    #NoEnv  ; Recommended for performance and compatibility with future AutoHotkey releases.
    SendMode Input  ; Recommended for new scripts due to its superior speed and reliability.
    #SingleInstance ignore ; only allow 1 running script
    SetTitleMatchMode, 3  ; Names must be exact
    
    ; check values
    if (borderPixels < 1 OR borderPixels > 25)
    {
      MsgBox, borderPixels value out of range
      ExitApp
    }
    
    timeDelayL  := buttonDelayL // 10
    timeDelayR  := buttonDelayR // 10
    movePixels := boxSize // 2
    edgeMargin := movePixels * 2 + borderPixels
    border := borderPixels
    mouseLocked := 0
    
    ; setup paths and file
    if (episode = 0)
    {
    gameFile = WallaceGromitDemo.exe
    launcherName = Wallace & Gromit Demo
    }
    else if (episode = 1)
    {
    gameFile = WallaceGromit101.exe
    launcherName = Fright of the Bumblebees
    }
    else if (episode = 2)
    {
    gameFile = WallaceGromit102.exe
    launcherName = The Last Resort
    }
    else if (episode = 3)
    {
    gameFile = WallaceGromit103.exe
    launcherName = Muzzled!
    }
    else if (episode = 4)
    {
    gameFile = WallaceGromit104.exe
    launcherName = The Bogey Man
    }
    else
    {
      MsgBox, Invalid Episode #
      ExitApp
    }
    gameReg  = SOFTWARE\Telltale Games\%gameFile%
    RegRead, gameDir, HKEY_LOCAL_MACHINE, %gameReg% , Install Location
    
    ; this is the name of the game as shown on the task bar
    ; Demo, Ep1 and Ep2 all use the same name, so I assume all episodes will
    gameName = Telltale Games
    
    
    ; launch game
    Run, %gameFile%, %gameDir%, UseErrorLevel
    if ErrorLevel = ERROR
    {
      MsgBox, Episode %episode% could not be found
      ExitApp
    }
    winwait, %gameName%, , 120
    if ErrorLevel
    {
      ExitApp
    }
    gameID := WinExist(gameName)
    WinActivate, ahk_id %gameID%
    SetTimer, gameCheck
    return
    
    
    gameCheck:
    ;------------------------------
    ; quit script on game exit
    ;------------------------------
    if (mouseLocked AND isFullScreen())
    {
      ; free the mouse if we switched modes
      DllCall("ClipCursor")
      mouseLocked := 0
    }
    IfWinNotExist, ahk_id %gameID%
    {
      ; free the mouse just in case
      DllCall("ClipCursor")
      ExitApp
    }
    return
    
    
    ~LButton::
    useEdges  := useEdgesL
    useCenter := useCenterL
    timeDelay := timeDelayL
    testButton = LButton
    Gosub, mouseToArrows
    return
    
    
    ~RButton::
    useEdges  := useEdgesR
    useCenter := useCenterR
    timeDelay := timeDelayR
    testButton = RButton
    Gosub, mouseToArrows
    return
    
    
    mouseToArrows:
    ;------------------------------
    ; process mouse movement
    ;------------------------------
    usingCenterMove := 0
    if (isFullScreen())
    {
      ; fullscreen
      CoordMode, Mouse, Screen
      width  := A_ScreenWidth
      height := A_ScreenHeight
      winXpos := 0
      winYpos := 0
      winXoffset := 0
      winYoffset := 0
    }
    else
    {
      ; only do mouse to key conversion in game window
      IfWinNotActive, ahk_id %gameID%
        Return,
      CoordMode, Mouse, Relative
      ; get window information
      WinGetPos, winXpos, winYpos, width, height, ahk_id %gameID%
      ; free up mouse if on bar
      MouseGetPos, , curY
      if (curY < winBarPixels)
        Return,
      ; remove window border pixels
      width  -= winBorderPixels * 2
      height -= winBarPixels + winBorderPixels
      winXoffset := winBorderPixels
      winYoffset := winBarPixels
      ; set top left of game window
      ; keep locking the window so the mouse does not get free
      mouseLocked := 1
      Gosub, lockWindow
    }
    
    ; check aspect ratio and adjust
    if (width * 9 // height < 16)
    {
      ; top and bottom letterboxed
      newHeight := width * 9 // 16
      edgeLeft  := 0
      edgeRight := width
      edgeUp    := (height - newHeight) // 2
      edgeDown  := edgeUp  + newHeight
    }
    else
    {
      ; sides letterboxed
      newWidth  := height * 16 // 9
      edgeLeft  := (width   - newWidth) // 2
      edgeRight := edgeLeft + newWidth
      edgeUp    := 0
      edgeDown  := height
    }
    
    ; bottom corner is one pixel in
    edgeRight--
    edgeDown--
    
    if (useCenter = 1)
    {
      timePressed := 0
      ; the valid center movement area
      centerLeft  := edgeLeft  + edgeMargin
      centerRight := edgeRight - edgeMargin
      centerUp    := edgeUp    + edgeMargin
      centerDown  := edgeDown  - edgeMargin
    }
    
    While GetKeyState(testButton)
    {
      MouseGetPos, curX, curY
      if (!usingCenterMove)
      {
        ; adjust for window border
        curX -= winXoffset
        curY -= winYoffset
      }
    
      if (useEdges = 1 OR usingCenterMove = 1)
      {
        if (curX < edgeLeft + border)
        {
          if (!downL)
          {
            Send {Left Down}
            downL := 1
          }
        }
        else
        {
          if (downL)
          {
            Send {Left Up}
          }
          downL := 0
        }
    
        if (curX > edgeRight - border)
        {
          if (!downR)
          {
            Send {Right Down}
            downR := 1
          }
        }
        else
        {
          if (downR)
          {
            Send {Right Up}
          }
          downR := 0
        }
    
        if (curY < edgeUp + border)
        {
          if (!downU)
          {
            Send {Up Down}
            downU := 1
          }
        }
        else
        {
          if (downU)
          {
            Send {Up Up}
          }
          downU := 0
        }
    
        if (curY > edgeDown - border)
        {
          if (!downD)
          {
            Send {Down Down}
            downD := 1
          }
        }
        else
        {
          if (downD)
          {
            Send {Down Up}
          }
          downD := 0
        }
      }
    
      if (useCenter AND !usingCenterMove)
      {
        ; start counting if in center of screen
        if (curX > centerLeft AND curX < centerRight AND curY > centerUp AND curY < centerDown)
        {
          timePressed++
          if (timePressed > timeDelay)
          {
            ; button down long enough, start using center move
            ; re-djust mousepos to real and setup movement box
            curX += winXoffset
            curY += winYoffset
            edgeLeft  := curX - movePixels
            edgeUp    := curY - movePixels
            edgeRight := curX + movePixels
            edgeDown  := curY + movePixels
            VarSetCapacity(R, 16, 0), NumPut(winXpos + edgeLeft, &R+0), NumPut(winYpos + edgeUp, &R+4), NumPut(winXpos + edgeRight + 1, &R+8), NumPut(winYpos + edgeDown + 1, &R + 12)
            DllCall("ClipCursor", UInt, &R)
            usingCenterMove := 1
            border := 1
          }
        }
        else
        {
          ; reset count when not in center
          timePressed := 0
        }
      }
    Sleep, 10
    }
    
    if (usingCenterMove)
    {
      ; free the cursor
      if (mouseLocked)
        Gosub, lockWindow
      else
        DllCall("ClipCursor")
      ; reset to view border
      border := borderPixels
    }
    
    ; unpress any keys that are down
    if (downL)
    {
      Send {Left Up}
    }
    downL := 0
    if (downR)
    {
      Send {Right Up}
    }
    downR := 0
    if (downU)
    {
      Send {Up Up}
    }
    downU := 0
    if (downD)
    {
      Send {Down Up}
    }
    downD := 0
    Return,
    
    
    isFullScreen()
    ;------------------------------
    ; check to see if fullscreen
    ;------------------------------
    {
      Global gameID
      WinGet, style, Style, ahk_id %gameID%
      ; 0x800000 is WS_BORDER.
      ; 0x20000000 is WS_MINIMIZE.
      ; no border and not minimized
      Return, (style & 0x20800000) ? 0 : 1
    }
    
    
    ~f::
    ;------------------------------
    ; free mouse from window
    ;------------------------------
    if (mouseLocked)
    {
      IfWinActive, ahk_id %gameID%
      {
        ; free the cursor
        DllCall("ClipCursor")
        mouseLocked := 0
      }
    }
    Return,
    
    
    lockWindow:
    ;------------------------------
    ; lock mouse to window
    ;------------------------------
    VarSetCapacity(R, 16, 0), NumPut(winXpos + winBorderPixels, &R+0), NumPut(winYpos + winBarPixels, &R+4), NumPut(winXpos + winBorderPixels + width, &R+8), NumPut(winYpos + winBarPixels + height, &R + 12)
    DllCall("ClipCursor", UInt, &R)
    Return,
    
  • edited May 2009
    [TTG] Yare wrote: »
    How does the "screen edge" stuff cope with the game in windowed mode, or with multiple monitors?

    I'm not sure about multi-monitor, but I think it should work just like W&G.

    I can't imagine W&G supports spanning a game across multiple monitors in fullscreen without using Dual/TripleHead. At that point my script would work fine. In windowed mode it should also work fine if the window spans multiple monitors.

    I can't test either setup though.
  • edited May 2009
    Ok, this should be the final last version. It adds full windowed support for mouse movement and takes into account varying window border sizes. The first post in this thread has been updated with the info and the new script file.

    Enjoy.
  • edited June 2009
    Derrick wrote: »

    Myself, I just can't get used to using WASD. I do all my gaming from the couch on my HTPC. So it is too much of a pain to use the keyboard on my lap. I remapped my joystick to what I liked, but did not like selecting on-screen items by toggling through them. Which means I still needed a mouse/joystick combo. With this script I can now use only the mouse. I click on selectable items to move, but if I get to a spot when I need to use WASD, now I can just press and hold the right mouse button at the edge of the screen.

    If you use a HTPC do yourself a favor and play the game with a gamepad...
    The control scheme is clearly designed for a gamepad. I played it also that way and it works out well!
  • edited June 2009
    This actually works pretty well... I like it much better than the default controls.

    I hope this will work for Monkey Island episodes as well.
  • edited June 2009
    Armakuni wrote: »
    I hope this will work for Monkey Island episodes as well.

    I saw your post over there and I am sure that they will make a script for ToMI if this one should not work.
  • edited July 2009
    I would love to use AutoHotKey to allow me to use the right anologue stick on a gamepad as a mouse in W&G. I tried XPadder but because hot spot swap is mapped to it by default it interferes.

    From what I am told I can use AutoHotKey to force it to ignore the original joystick commands.

    Can anyone help me with that? Never used AHK before. Thanks
  • edited July 2009
    parabolee wrote: »
    I would love to use AutoHotKey to allow me to use the right anologue stick on a gamepad as a mouse in W&G. I tried XPadder but because hot spot swap is mapped to it by default it interferes.

    From what I am told I can use AutoHotKey to force it to ignore the original joystick commands.

    Can anyone help me with that? Never used AHK before. Thanks

    You could start with this as the basis for the script and modify it for the second analog stick. I have never tried that script, so I really can't help you any more with that. Autohotkey does have great forums that offer plenty of help and you can search it for ideas.

    Edit... just noticed people are complaining about W&G default mapping still working while they are using the 2nd analog stick as a mouse. I think Autohotkey only allows blocking and remapping of buttons. The axes are not blocked, so autohotkey will be of no help for this issue. I could be wrong, but that is the way it looks from the documentation.

    You could always try Pinnacle Game Profiler.
Sign in to comment in this discussion.