Hi
Ich versuch das mal zu erklären:
Für ein Programm benötige ich 2 Mäuse für die Bedienung
Eine Maus steuert einen Cursor, welcher nur in einem Fenster agiert, und die zweite Maus benötigt man um gleichzeitig Einstellungen vorzunehmen.
(Der erste Cursor könnte auch von einem Joystick gesteuert werden, den aber nicht jeder Benutzer besitzt - jedoch die meisten haben einen Laptop mit Touchpad und eine USB-Maus)
Darüberhinaus soll das Programm im Extremfall aber auch mit nur einer Maus gesteuert werden können, dazu muß man die rechte Maustaste gedrückt halten, während man Einstellungen vornimmt, damit sich der erste Cursor nicht bewegt...
Mehrere Mäuse können via RawInput gelesen werden, jedoch bewegen alle Mäuse den Mauszeiger bzw. alle Tastenklicks verursachen auch Mausklicks.
Dies soll jedoch bei der "ersten" Maus nicht passieren.
Meine Idee war ursprünglich folgende:
Ich registriere einen Mausinput via RawInput und eintscheide dann, ob diese Aktion von Windows auch ausgeführt werden darf - wenn nicht, dann blockiere ich die Maus in einem $WM_MOUSE_LL-Hook
Da gibt es jedoch ein großes Problem: $WM_MOUSE_LL-Hook wird VOR RawInput aufgerufen und ich hab keine Chance auf diesem Weg!
Nun mache ich es so: Ich blockiere grundsätzlich alle Mauseingaben und gebe nur die frei, die nicht von der "ersten" Maus stammen - Alles klar?
Mausklicks leite ich jedoch nicht weiter, sondern muß sie via MouaseClick synthetisieren
Die Lösung ist nicht ganz zufriedenstellend, aber für meine Zwecke reicht es fürs erste...
Es wär jedenfalls viel einfacher und besser, wenn RawInput vor dem Hook passieren würde
Naja, hier das TestScript:
Die Radiobuttons auf der linken Seite sind für die Maus, die den normalen Mauszeiger bewegen soll.
Die auf der rechten Seite sind für den GDI+-Cursor im Hauptfenster
getestet bisher nur auf WinXP, allerdings bereits mit 4 Mäusen
Spoiler anzeigen
#include <Array.au3>
#include <GDIPlus.au3>
#include <GUIConstantsEx.au3>
#include <WinAPI.au3>
#include <WindowsConstants.au3>
Opt("GUIOnEventMode", 1)
[/autoit] [autoit][/autoit] [autoit]_GDIPlus_Startup()
[/autoit] [autoit][/autoit] [autoit]Global $hGui_Map = GUICreate("MultiMouse Test Map", 600, 400, @DesktopWidth / 2 - 405, @DesktopHeight / 2 - 200, -1, $WS_EX_TOPMOST)
GUISetOnEvent(-3, "_Exit")
Global $hGraphics = _GDIPlus_GraphicsCreateFromHWND($hGui_Map)
Global $hBmpBuffer = _GDIPlus_BitmapCreateFromGraphics(600, 400, $hGraphics)
Global $hGfxBuffer = _GDIPlus_ImageGetGraphicsContext($hBmpBuffer)
_GDIPlus_GraphicsSetSmoothingMode($hGfxBuffer, 2)
Global $hPen = _GDIPlus_PenCreate(0xFF00FF00, 3)
[/autoit] [autoit][/autoit] [autoit]Global $hGui_Set = GUICreate("MultiMouse Test Set", 200, 400, @DesktopWidth / 2 + 205, @DesktopHeight / 2 - 200, -1, BitOR($WS_EX_TOPMOST, $WS_EX_TOOLWINDOW), $hGui_Map)
GUISetOnEvent(-3, "_Exit")
Global $cButton1 = GUICtrlCreateButton("Test 1", 10, 10, 180, 25)
GUICtrlSetOnEvent(-1, "_Test1")
Global $cButton2 = GUICtrlCreateButton("Test 2", 10, 50, 180, 25)
GUICtrlSetOnEvent(-1, "_Test2")
Global $aRadio_Normal[6]
Global $aLabel[6]
GUIStartGroup()
For $i = 1 To 5
$aLabel[$i] = GUICtrlCreateLabel("Maus " & $i, 80, 100 + ($i - 1) * 20, 120, 20, 0x0C)
$aRadio_Normal[$i] = GUICtrlCreateRadio("", 10, 100 + ($i - 1) * 20, 20, 20)
GUICtrlSetOnEvent(-1, "_ActivateMouse_Normal")
Next
Global $aRadio_Cursor[6]
Global $aActive[6]
GUIStartGroup()
For $i = 1 To 5
$aRadio_Cursor[$i] = GUICtrlCreateRadio("", 30, 100 + ($i - 1) * 20, 20, 20)
GUICtrlSetOnEvent(-1, "_ActivateMouse_Cursor")
$aActive[$i] = GUICtrlCreateLabel("", 50, 100 + ($i - 1) * 20, 20, 20)
Next
GUIRegisterMsg($WM_PAINT, "WM_PAINT")
GUIRegisterMsg($WM_ERASEBKGND, "WM_ERASEBKGND")
GUIRegisterMsg(0x00FF, "WM_INPUT")
GUISetState(@SW_SHOW, $hGui_Map)
GUISetState(@SW_SHOW, $hGui_Set)
Global $aMice = _MM_GetMiceList()
;_ArrayDisplay($aMice)
$aRadio_Normal[0] = 1
$aRadio_Cursor[0] = 2
GUICtrlSetState($aRadio_Normal[1], $GUI_CHECKED)
GUICtrlSetState($aRadio_Cursor[2], $GUI_CHECKED)
If $aMice[0][0] < 2 Then
$aRadio_Cursor[0] = 1
GUICtrlSetState($aRadio_Cursor[1], $GUI_CHECKED)
EndIf
For $i = 1 To 5
If $i <= $aMice[0][0] Then
GUICtrlSetData($aLabel[$i], $aMice[$i][1])
Else
GUICtrlSetState($aRadio_Normal[$i], $GUI_DISABLE)
GUICtrlSetState($aRadio_Cursor[$i], $GUI_DISABLE)
EndIf
Next
Global $aCursor[6] = [0, 0, 25, MouseGetPos(0), MouseGetPos(1), 0]
_DrawCursor()
Global $aMouseStructs = _MM_CreateMouseStructs()
_MM_RegisterMice($hGui_Map)
Global $Block = True
[/autoit] [autoit][/autoit] [autoit]Global $hHook_Module_LL = _WinAPI_GetModuleHandle(0)
Global $hMouse_Proc_LL = DllCallbackRegister("_MouseHook_Proc_LL", "int", "int;ptr;ptr")
Global $hMouse_Hook_LL = _WinAPI_SetWindowsHookEx($WH_MOUSE_LL, DllCallbackGetPtr($hMouse_Proc_LL), $hHook_Module_LL, 0)
OnAutoItExitRegister("_OnExit")
While 1
[/autoit] [autoit][/autoit] [autoit]Sleep(100)
WEnd
Func _MouseHook_Proc_LL($nCode, $wParam, $lParam)
If $nCode < 0 Then Return _WinAPI_CallNextHookEx($hMouse_Hook_LL, $nCode, $wParam, $lParam)
Local $iMouse_Event = BitAND($wParam, 0xFFFF)
If $iMouse_Event = 512 Then Return 1
If $Block Then Return 1
Return _WinAPI_CallNextHookEx($hMouse_Hook_LL, $nCode, $wParam, $lParam)
EndFunc ;==>_MouseHook_Proc_LL
Func _ActivateMouse_Normal()
For $i = 1 To 5
If @GUI_CtrlId = $aRadio_Normal[$i] Then $aRadio_Normal[0] = $i
Next
$aCursor[5] = 0
EndFunc ;==>_ActivateMouse_Normal
Func _ActivateMouse_Cursor()
For $i = 1 To 5
If @GUI_CtrlId = $aRadio_Cursor[$i] Then $aRadio_Cursor[0] = $i
Next
$aCursor[5] = 0
EndFunc ;==>_ActivateMouse_Cursor
Func _MM_CreateMouseStructs()
Local $tMouse = DllStructCreate("dword dwType; dword dwSize; hwnd hDevice; uint_ptr wParam; ushort usFlags; ushort usButtonFlags; ushort usButtonData; ulong ulRawButtons; long lLastX; long lLastY; ulong ulExtraInformation;")
Local $pMouse = DllStructGetPtr($tMouse)
Local $iMouse = DllStructGetSize($tMouse)
Local $tHeader = DllStructCreate("dword dwType; dword dwSize; hwnd hDevice; uint_ptr wParam;")
Local $iHeader = DllStructGetSize($tHeader)
Local $aReturn[4]
$aReturn[0] = $tMouse
$aReturn[1] = $pMouse
$aReturn[2] = $iMouse
$aReturn[3] = $iHeader
Return $aReturn
EndFunc ;==>_MM_CreateMouseStructs
Func WM_INPUT($hWnd, $Msg, $wParam, $lParam)
Local $aResult = DllCall("user32.dll", "dword", "GetRawInputData", "hwnd", $lParam, "dword", 0x10000003, "ptr", $aMouseStructs[1], "dword*", $aMouseStructs[2], "uint", $aMouseStructs[3])
If Not @error Then
Local $hDevice = DllStructGetData($aMouseStructs[0], "hDevice")
If Not $hDevice Then Return 'GUI_RUNDEFMSG'
Local $iX = DllStructGetData($aMouseStructs[0], "lLastX")
Local $iY = DllStructGetData($aMouseStructs[0], "lLastY")
Local $iButton = DllStructGetData($aMouseStructs[0], "usButtonData")
For $i = 1 To $aMice[0][0]
If $aMice[$i][0] = $hDevice Then
GUICtrlSetBkColor($aActive[$i], 0x00FF00)
Switch $i
Case $aRadio_Cursor[0]
If $iButton = 4 Or $iButton = 8 Then $aCursor[5] = $iButton
If $aCursor[5] <> 4 Then
$aCursor[0] += $iX
$aCursor[1] += $iY
If $aCursor[0] < 0 Then $aCursor[0] = 0
If $aCursor[1] < 0 Then $aCursor[1] = 0
If $aCursor[0] > 600 Then $aCursor[0] = 600
If $aCursor[1] > 400 Then $aCursor[1] = 400
If $aRadio_Cursor[0] = $aRadio_Normal[0] Then
Local $tPoints = DllStructCreate("int;int;")
DllStructSetData($tPoints, 1, $aCursor[0])
DllStructSetData($tPoints, 2, $aCursor[1])
_WinAPI_ClientToScreen($hGui_Map, $tPoints)
$aCursor[3] = DllStructGetData($tPoints, 1)
$aCursor[4] = DllStructGetData($tPoints, 2)
EndIf
_DrawCursor()
EndIf
If $i = $aRadio_Normal[0] Then ContinueCase
Case Else
$aCursor[3] += $iX
$aCursor[4] += $iY
If $aCursor[3] < 0 Then $aCursor[3] = 0
If $aCursor[4] < 0 Then $aCursor[4] = 0
If $aCursor[3] > @DesktopWidth Then $aCursor[3] = @DesktopWidth
If $aCursor[4] > @DesktopHeight Then $aCursor[4] = @DesktopHeight
DllCall("user32.dll", "BOOL", "SetCursorPos", "int", $aCursor[3], "int", $aCursor[4])
[/autoit] [autoit][/autoit] [autoit]If $iButton = 1 Then
$Block = False
MouseClick("left", $aCursor[3], $aCursor[4], 1, 0)
EndIf
EndSwitch
Else
GUICtrlSetBkColor($aActive[$i], 0xFF0000)
EndIf
Next
EndIf
$Block = True
Return 'GUI_RUNDEFMSG'
EndFunc ;==>WM_INPUT
Func _MM_GetMiceList()
Local $aMice[1][3] = [[0]]
Local $tStruct = DllStructCreate("hwnd hDevice; dword dwType;")
Local $aResult = DllCall("user32.dll", "dword", "GetRawInputDeviceList", "ptr", 0, "dword*", 0, "dword", DllStructGetSize($tStruct))
If @error Then Return SetError(1, 1, $aMice)
If Not $aResult[2] Then Return SetError(1, 2, $aMice)
Local $iCnt = $aResult[2]
Local $sInfo = ""
For $i = 1 To $iCnt
$sInfo &= StringRegExpReplace("hwnd hDevice; dword dwType; ", "(\w+);", "${1}" & $i & ";")
Next
Local $tList = DllStructCreate($sInfo)
$aResult = DllCall("user32.dll", "dword", "GetRawInputDeviceList", "ptr", DllStructGetPtr($tList), "dword*", $iCnt, "dword", DllStructGetSize($tStruct))
If @error Then Return SetError(1, 3, $aMice)
Local $aInfo = _MM_Get_MiceInfo()
[/autoit] [autoit][/autoit] [autoit]Local $iStep = 0
Local $tName
Local $hDevice, $iSize, $sName_dbcc, $sName, $aRegExp
For $i = 1 To $iCnt
If DllStructGetData($tList, 'dwType' & $i) = 0 Then
$hDevice = DllStructGetData($tList, "hDevice" & $i)
$aResult = DllCall("user32.dll", "dword", "GetRawInputDeviceInfo", "hwnd", $hDevice, "dword", 0x20000007, "ptr", 0, "dword*", 0)
If @error Or Not IsArray($aResult) Then ContinueLoop
$iSize = $aResult[4]
$tName = DllStructCreate("char[" & $iSize & "];")
$aResult = DllCall("user32.dll", "dword", "GetRawInputDeviceInfo", "hwnd", $hDevice, "dword", 0x20000007, "ptr", DllStructGetPtr($tName), "dword*", $iSize)
If @error Or Not IsArray($aResult) Then ContinueLoop
$sName_dbcc = DllStructGetData($tName, 1)
$aRegExp = StringRegExp($sName_dbcc, "[\w\d&]+", 3)
$sName = ""
If UBound($aRegExp) > 2 And IsArray($aInfo) Then
For $j = 1 To $aInfo[0][0]
If StringInStr($aInfo[$j][2], $aRegExp[1]) Then
$sName = $aInfo[$j][10]
ExitLoop
EndIf
Next
EndIf
If Not $sName Or StringInStr($sName_dbcc, "RDP_MOU") Then ContinueLoop
[/autoit] [autoit][/autoit] [autoit]$iStep += 1
ReDim $aMice[$iStep + 1][3]
$aMice[$iStep][0] = $hDevice
$aMice[$iStep][1] = $sName
$aMice[$iStep][2] = $sName_dbcc
EndIf
Next
$aMice[0][0] = $iStep
Return $aMice
EndFunc ;==>_MM_GetMiceList
Func _MM_Get_MiceInfo()
Local $aMice[1][18] = [[0, 'Description', 'Device ID', 'Device Interface', 'Double Speed Threshold', 'Handedness', 'Hardware Type', 'INF File Name', 'INF Section', 'Manufacturer', 'Name', 'Number Of Buttons', 'PNP Device ID', 'Pointing Type', 'Quad Speed Threshold', 'Resolution', 'Sample Rate', 'Synch']]
Local $iCnt = 0
Local $oWMI = ObjGet('winmgmts:\\' & @ComputerName & '\root\cimv2')
If Not @error And IsObj($oWMI) Then
Local $cItems = $oWMI.ExecQuery('Select * from Win32_PointingDevice')
Local $oItem, $Temp
For $oItem In $cItems
$iCnt += 1
ReDim $aMice[$iCnt + 1][18]
$aMice[$iCnt][1] = $oItem.Description
$aMice[$iCnt][2] = $oItem.DeviceID
$Temp = $oItem.DeviceInterface
Switch $Temp
Case 1
$aMice[$iCnt][3] = "Other"
Case 2
$aMice[$iCnt][3] = "Unknown"
Case 3
$aMice[$iCnt][3] = "Serial"
Case 4
$aMice[$iCnt][3] = "PS/2"
Case 5
$aMice[$iCnt][3] = "Infrared"
Case 6
$aMice[$iCnt][3] = "HP-HIL"
Case 7
$aMice[$iCnt][3] = "Bus mouse"
Case 8
$aMice[$iCnt][3] = "ADB (Apple Desktop Bus)"
Case 160
$aMice[$iCnt][3] = "Bus mouse DB-9"
Case 161
$aMice[$iCnt][3] = "Bus mouse micro-DIN"
Case 162
$aMice[$iCnt][3] = "USB"
EndSwitch
$aMice[$iCnt][4] = $oItem.DoubleSpeedThreshold
$aMice[$iCnt][5] = $oItem.Handedness
$aMice[$iCnt][6] = $oItem.HardwareType
$aMice[$iCnt][7] = $oItem.InfFileName
$aMice[$iCnt][8] = $oItem.InfSection
$aMice[$iCnt][9] = $oItem.Manufacturer
$aMice[$iCnt][10] = $oItem.Name
$aMice[$iCnt][11] = $oItem.NumberOfButtons
$aMice[$iCnt][12] = $oItem.PNPDeviceID
$aMice[$iCnt][13] = $oItem.PointingType
$aMice[$iCnt][14] = $oItem.QuadSpeedThreshold
$aMice[$iCnt][15] = $oItem.Resolution
$aMice[$iCnt][16] = $oItem.SampleRate
$aMice[$iCnt][17] = $oItem.Synch
Next
$aMice[0][0] = $iCnt
Return $aMice
EndIf
Return SetError(1, 1, $aMice)
EndFunc ;==>_MM_Get_MiceInfo
Func _MM_RegisterMice($hGui)
Local Const $RIDEV_INPUTSINK = 0x00000100
Local $tStruct = DllStructCreate("ushort usUsagePage; ushort usUsage; dword dwFlags; hwnd hwndTarget;")
DllStructSetData($tStruct, "usUsagePage", 0x01)
DllStructSetData($tStruct, "usUsage", 0x02)
DllStructSetData($tStruct, "dwFlags", $RIDEV_INPUTSINK)
DllStructSetData($tStruct, "hwndTarget", $hGui)
Local $aResult = DllCall("user32.dll", "int", "RegisterRawInputDevices", "ptr", DllStructGetPtr($tStruct), "dword", 1, "dword", DllStructGetSize($tStruct))
If @error Then Return SetError(1, 2, False)
Return $aResult[0]
EndFunc ;==>_MM_RegisterMice
Func _DrawCursor()
_GDIPlus_GraphicsClear($hGfxBuffer, 0xFF000000)
_GDIPlus_GraphicsDrawLine($hGfxBuffer, $aCursor[0] - $aCursor[2], $aCursor[1], $aCursor[0] + $aCursor[2], $aCursor[1], $hPen)
_GDIPlus_GraphicsDrawLine($hGfxBuffer, $aCursor[0], $aCursor[1] - $aCursor[2], $aCursor[0], $aCursor[1] + $aCursor[2], $hPen)
_GDIPlus_GraphicsDrawImage($hGraphics, $hBmpBuffer, 0, 0)
EndFunc ;==>_DrawCursor
Func _Test1()
ConsoleWrite("! Test1" & @CRLF)
EndFunc ;==>_Test1
Func _Test2()
ConsoleWrite("> Test2" & @CRLF)
EndFunc ;==>_Test2
Func WM_PAINT($hWnd, $uMsgm, $wParam, $lParam)
If $hWnd = $hGui_Map Then _GDIPlus_GraphicsDrawImage($hGraphics, $hBmpBuffer, 0, 0)
Return $GUI_RUNDEFMSG
EndFunc ;==>WM_PAINT
Func WM_ERASEBKGND($hWnd, $uMsgm, $wParam, $lParam)
If $hWnd = $hGui_Map Then _GDIPlus_GraphicsDrawImage($hGraphics, $hBmpBuffer, 0, 0)
Return $GUI_RUNDEFMSG
EndFunc ;==>WM_ERASEBKGND
Func _Exit()
_GDIPlus_PenDispose($hPen)
_GDIPlus_GraphicsDispose($hGfxBuffer)
_GDIPlus_BitmapDispose($hBmpBuffer)
_GDIPlus_GraphicsDispose($hGraphics)
_GDIPlus_Shutdown()
Exit
EndFunc ;==>_Exit
Func _OnExit()
_WinAPI_UnhookWindowsHookEx($hMouse_Hook_LL)
DllCallbackFree($hMouse_Proc_LL)
EndFunc ;==>_OnExit
Hat jemand eine Idee, wie man das anders/besser machen könnte?
E