I wrote this small mouse class to deal with the problem of user mouse movement being lost by scripts which just move the mouse back to where it was before they interacted with it. Hopefully it should mean that any mouse movement made while the script has moved the mouse will persist to the mouse location after the script moves it back using this mouse class if you integrate it into your scripts.
Posting so you guys can test and share improvements to it, I couldn't get conclusive results on how effective it was but my personal scripts felt a lot better once it was added.
Source code:
class "Mouse" function Mouse:__init() self.ActualPos = cursorPos self.ScriptPos = cursorPos self.MousePosLastTick = cursorPos self.mouseReleaseDifference = Vector(0,0) Callback.Add("Draw", function() self:Update() end) end function Mouse:Update() if self.MousePosLastTick ~= cursorPos then self:Moved() end self.MousePosLastTick = cursorPos --Draw.Text("cursorPos", cursorPos+Vector(100, 100)) Draw.Text("ActualPos", self.ActualPos) Draw.Text("ScriptPos", (self.ScriptPos+Vector(20, 200))) end function Mouse:SetMousePos(pos) -- accepts vector2 or vector3 self.IgnoreNextMovement = true pos2 = pos:To2D() self.ScriptPos = Vector(pos2.x, pos2.y, cursorPos.z) Control.SetCursorPos(pos) end function Mouse:Moved() if ScriptControllingMouse == false then self.ActualPos = cursorPos elseif ScriptControllingMouse == true then local mouseDifference = cursorPos - self.ScriptPos self.mouseReleaseDifference = mouseDifference*2 end end function Mouse:ScriptStartedControlling() self.mouseReleaseDifference = Vector(0,0) self.ActualPos = cursorPos ScriptControllingMouse = true end function Mouse:ScriptFinishedControlling(addReleaseDifference) ScriptControllingMouse = false if addReleaseDifference==nil then addReleaseDifference = true end if addReleaseDifference then self.ActualPos = self.ActualPos + self.mouseReleaseDifference end self.mouseReleaseDifference = Vector(0,0) local posX, posY = self.ActualPos.x, self.ActualPos.y Control.SetCursorPos(posX, posY) end GameMouse = Mouse()
How to use: Just copy pasting the sourecode means it will update itself as it adds callbacks when it initiates.
When you want to control the players mouse, you use the Started, Stopped and SetMousePos functions, example implementation:
function Orbwalker:Attack(unit) if not self:CanOrb(unit) then return end self.Attacking = true GameMouse:ScriptStartedControlling(true) if unit.type == Obj_AI_Hero then Control.KeyDown(HK_TCO) end local diff = Vector(0,0,0) if unit.type == Obj_AI_Minion then diff =Vector(0, 20, 0) --Clicks up a little bit to avoid some of the awkward misclicks. end GameMouse:SetMousePos(unit.pos + diff) DelayAction(function() self:RightClick() self.LastAttack = Game.Timer() self.Attacking = true DelayAction(function() Control.KeyUp(HK_TCO) self.Attacking = false GameMouse:ScriptFinishedControlling() self:AfterAttack() end, .001) end, .001) end
Like stated earlier please give feedback and share improvements that you make.
Some ideas for something that could be added is a time based curve movement function for smooth mouse movement towards pos with duration of curve movement being given to the function. This would make EXT much more available to being used while streaming(if someone actually wants to do that).
For some reason GOS wont set the cursor pos back to actual pos at the end, but there's no error, does someone know why this is?
edit: this was caused by Control.SetCursorPos being broken for 2D vectors.
ATM this is better for large movements scripts would make like moving the mouse to cast spells or attack units, for small movements like orbwalkers moving the character it makes controlling the mouse feel a bit "sticky" on the user's end, if someone fixes it please post. Temporarily when calling ScriptFinishedControlling for very frequent mouse movements (i.e orbwalkers moving the mouse when not autoattacking) just pass false to it.