Hi fellas,
I've looked around quite a bit, and have found different scripts that do different aspects of my specific use case. Please help me get started and/or find a solution =D
I have 2 mouses, 1 for each hand, I would like to use each mouse to move the single cursor on the screen in different axis. The right mouse would move only the X axis, and the left mouse would move only the Y axis. I need to lock the axis of each mouse that doesn't move.
I'm going to be using this for a game called Osu!, it's a fairly fast paced game that requires quite a high polling rate from my mouse; I'm guessing I should also look into Raw Mouse Input to retain the high polling rates from each mouse?
Any help would be greatly appreciated. Thank you!
2 mouses, 1 cursor, axis locking
Re: 2 mouses, 1 cursor, axis locking
This is something that is probably best done with a mouse that has onboard memory. Set the DPI on each mouse to a super low amount on the necessary axis. That'll cause that axis movement to do nothing for that mouse.
Re: 2 mouses, 1 cursor, axis locking
This is normally not possible, as windows does not have a built-in way to block input from a specific device.
You can do it, however, with AutoHotInterception
However, the technique you need to use is VERY RISKY, because you need to block ALL movement from BOTH devices, and then fake the input that you want to keep.
ie block X and Y for both mice, and then when the input comes in, synthesize appropriate movement
I would HEAVILY recommend having a 3rd mouse handy, or at the very least knowing the keyboard shortcuts you would need to use to kill the script
Anyway, here is roughly what you would need to do what you want (Untested code)
You can do it, however, with AutoHotInterception
However, the technique you need to use is VERY RISKY, because you need to block ALL movement from BOTH devices, and then fake the input that you want to keep.
ie block X and Y for both mice, and then when the input comes in, synthesize appropriate movement
I would HEAVILY recommend having a 3rd mouse handy, or at the very least knowing the keyboard shortcuts you would need to use to kill the script
Anyway, here is roughly what you would need to do what you want (Untested code)
Code: Select all
AHI := new AutoHotInterception()
mouse1 := AHI.GetMouseId(1234, ABCD) ; Fill in VID/PID for mouse #1 here
mouse2 := AHI.GetMouseId(2345, BCDE) ; Fill in VID/PID for mouse #2 here
AHI.SubscribeMouseMove(mouse1, true, Func("MouseEvent").Bind(1))
AHI.SubscribeMouseMove(mouse1, true, Func("MouseEvent").Bind(2))
MouseEvent(mouseId, x, y){
if (mouseId == 1){
; Simulate mouse movement on the X axis
DllCall("mouse_event", uint, 1, int, x, int, 0, uint, 0, int, 0)
} else {
; Simulate mouse movement on the Y axis
DllCall("mouse_event", uint, 1, int, 0, int, y, uint, 0, int, 0)
}
}
Re: 2 mouses, 1 cursor, axis locking
I've done things like this with MouseDelta, it should be easy.
Simple example, untested, because I'm on laptop with no real mouse,On first toggle, move the x-axis mouse first, then the y-axis mouse.
If it is in a game, the mouse block might not be effective.
Simple example, untested, because I'm on laptop with no real mouse,
Code: Select all
; f1 to toggle, esc to exit.
setmousedelay -1
md:= new MouseDelta("f")
f1::
md.SetState(toggle:=!toggle)
BlockInput % toggle ? "MouseMove" : "MouseMoveOff"
return
f(id,dx,dy){
static id1 := 0, id2 := 0
if !id
return
if !id1
id1 := id
else if (!id2 && id != id1)
id2 := id
if (id == id1)
MouseMove dx, 0, 0, R
else if (id == id2)
MouseMove 0, dy, 0, R
return
}
esc::
BlockInput MouseMoveOff
exitapp
return
; Instantiate this class and pass it a func name or a Function Object
; The specified function will be called with the delta move for the X and Y axes
; Normally, there is no windows message "mouse stopped", so one is simulated.
; After 10ms of no mouse movement, the callback is called with 0 for X and Y
Class MouseDelta {
State := 0
__New(callback){
;~ this.TimeoutFn := this.TimeoutFunc.Bind(this)
this.MouseMovedFn := this.MouseMoved.Bind(this)
this.Callback := callback
}
Start(){
static DevSize := 8 + A_PtrSize, RIDEV_INPUTSINK := 0x00000100
; Register mouse for WM_INPUT messages.
VarSetCapacity(RAWINPUTDEVICE, DevSize)
NumPut(1, RAWINPUTDEVICE, 0, "UShort")
NumPut(2, RAWINPUTDEVICE, 2, "UShort")
NumPut(RIDEV_INPUTSINK, RAWINPUTDEVICE, 4, "Uint")
; WM_INPUT needs a hwnd to route to, so get the hwnd of the AHK Gui.
; It doesn't matter if the GUI is showing, it still exists
Gui +hwndhwnd
NumPut(hwnd, RAWINPUTDEVICE, 8, "Uint")
this.RAWINPUTDEVICE := RAWINPUTDEVICE
DllCall("RegisterRawInputDevices", "Ptr", &RAWINPUTDEVICE, "UInt", 1, "UInt", DevSize )
OnMessage(0x00FF, this.MouseMovedFn)
this.State := 1
return this ; allow chaining
}
Stop(){
static RIDEV_REMOVE := 0x00000001
static DevSize := 8 + A_PtrSize
OnMessage(0x00FF, this.MouseMovedFn, 0)
RAWINPUTDEVICE := this.RAWINPUTDEVICE
NumPut(RIDEV_REMOVE, RAWINPUTDEVICE, 4, "Uint")
DllCall("RegisterRawInputDevices", "Ptr", &RAWINPUTDEVICE, "UInt", 1, "UInt", DevSize )
this.State := 0
return this ; allow chaining
}
SetState(state){
if (state && !this.State)
this.Start()
else if (!state && this.State)
this.Stop()
return this ; allow chaining
}
Delete(){
this.Stop()
;~ this.TimeoutFn := ""
this.MouseMovedFn := ""
}
; Called when the mouse moved.
; Messages tend to contain small (+/- 1) movements, and happen frequently (~20ms)
MouseMoved(wParam, lParam){
Critical
; RawInput statics
static DeviceSize := 2 * A_PtrSize, iSize := 0, sz := 0, pcbSize:=8+2*A_PtrSize, offsets := {x: (20+A_PtrSize*2), y: (24+A_PtrSize*2)}, uRawInput
static axes := {x: 1, y: 2}
; Get hDevice from RAWINPUTHEADER to identify which mouse this data came from
VarSetCapacity(header, pcbSize, 0)
If (!DllCall("GetRawInputData", "UPtr", lParam, "uint", 0x10000005, "UPtr", &header, "Uint*", pcbSize, "Uint", pcbSize) or ErrorLevel)
Return 0
ThisMouse := NumGet(header, 8, "UPtr")
; Find size of rawinput data - only needs to be run the first time.
if (!iSize){
r := DllCall("GetRawInputData", "UInt", lParam, "UInt", 0x10000003, "Ptr", 0, "UInt*", iSize, "UInt", 8 + (A_PtrSize * 2))
VarSetCapacity(uRawInput, iSize)
}
sz := iSize ; param gets overwritten with # of bytes output, so preserve iSize
; Get RawInput data
r := DllCall("GetRawInputData", "UInt", lParam, "UInt", 0x10000003, "Ptr", &uRawInput, "UInt*", sz, "UInt", 8 + (A_PtrSize * 2))
x := 0, y := 0 ; Ensure we always report a number for an axis. Needed?
x := NumGet(&uRawInput, offsets.x, "Int")
y := NumGet(&uRawInput, offsets.y, "Int")
this.Callback.(ThisMouse, x, y)
;~ ; There is no message for "Stopped", so simulate one
;~ fn := this.TimeoutFn
;~ SetTimer, % fn, -50
}
;~ TimeoutFunc(){
;~ this.Callback.("", 0, 0)
;~ }
}
If it is in a game, the mouse block might not be effective.
Re: 2 mouses, 1 cursor, axis locking
@Helgef - I am not sure how nice that will feel, as RawInput reports values in Mickeys, but you are sending MouseMoves, which uses Pixels. Why not replace the MouseMoves with mouse_event DLLCalls?
Re: 2 mouses, 1 cursor, axis locking
Hello evilC. I have no idea, still didn't test it .
Who is online
Users browsing this forum: peter_ahk and 79 guests