Created
January 15, 2022 18:45
-
-
Save DarkCoderSc/a85446bf3d1bea9e616b5a5f9d7a6615 to your computer and use it in GitHub Desktop.
Proof of Concept I made to monitor the state of global Windows mouse cursor. I will implement this code in PowerRemoteDesktop_Server to synchronize mouse state with Viewer.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<#------------------------------------------------------------------------------- | |
.Developer | |
Jean-Pierre LESUEUR (@DarkCoderSc) | |
https://www.twitter.com/darkcodersc | |
https://github.com/DarkCoderSc | |
www.phrozen.io | |
[email protected] | |
PHROZEN | |
.License | |
Apache License | |
Version 2.0, January 2004 | |
http://www.apache.org/licenses/ | |
-------------------------------------------------------------------------------#> | |
enum CursorType { | |
IDC_APPSTARTING = 32650 | |
IDC_ARROW = 32512 | |
IDC_CROSS = 32515 | |
IDC_HAND = 32649 | |
IDC_HELP = 32651 | |
IDC_IBEAM = 32513 | |
IDC_ICON = 32641 | |
IDC_NO = 32648 | |
IDC_SIZE = 32640 | |
IDC_SIZEALL = 32646 | |
IDC_SIZENESW = 32643 | |
IDC_SIZENS = 32645 | |
IDC_SIZENWSE = 32642 | |
IDC_SIZEWE = 32644 | |
IDC_UPARROW = 32516 | |
IDC_WAIT = 32514 | |
} | |
function Initialize-Cursors | |
{ | |
<# | |
.SYNOPSIS | |
Initialize different Windows supported mouse cursors. | |
.DESCRIPTION | |
Unfortunately, there is not WinAPI to get current mouse cursor icon state (Ex: as a flag) | |
but only current mouse cursor icon (via its handle). | |
One solution, is to resolve each supported mouse cursor handles (HCURSOR) with corresponding name | |
in a hashtable and then compare with GetCursorInfo() HCURSOR result. | |
#> | |
$cursors = @{} | |
Add-Type -MemberDefinition '[DllImport("User32.dll")] public static extern int LoadCursorA(int hInstance, int lpCursorName);[DllImport("User32.dll")] public static extern bool GetCursorInfo(IntPtr pci);' -Name User32 -Namespace W; | |
foreach ($cursorType in [CursorType].GetEnumValues()) { | |
$result = [W.User32]::LoadCursorA(0, [int]$cursorType) | |
if ($result -gt 0) | |
{ | |
$cursors[[string] $cursorType] = $result | |
} | |
} | |
return $cursors | |
} | |
function Get-GlobalMouseCursorIconHandle | |
{ | |
<# | |
.SYNOPSIS | |
Return global mouse cursor handle. | |
.DESCRIPTION | |
For this project I really want to avoid using "inline c#" but only pure PowerShell Code. | |
I'm using a Hackish method to retrieve the global Windows cursor info by playing by hand | |
with memory to prepare and read CURSORINFO structure. | |
--- | |
typedef struct tagCURSORINFO { | |
DWORD cbSize; // Size: 0x4 | |
DWORD flags; // Size: 0x4 | |
HCURSOR hCursor; // Size: 0x4 (32bit) , 0x8 (64bit) | |
POINT ptScreenPos; // Size: 0x8 | |
} CURSORINFO, *PCURSORINFO, *LPCURSORINFO; | |
Total Size of Structure: | |
- [32bit] 20 Bytes | |
- [64bit] 24 Bytes | |
#> | |
# sizeof(cbSize) + sizeof(flags) + sizeof(ptScreenPos) = 16 | |
$structSize = [IntPtr]::Size + 16 | |
$cursorInfo = [System.Runtime.InteropServices.Marshal]::AllocHGlobal($structSize) | |
try | |
{ | |
# ZeroMemory(@cursorInfo, SizeOf(tagCURSORINFO)) | |
for ($i = 0; $i -lt $structSize; $i++) | |
{ | |
[System.Runtime.InteropServices.Marshal]::WriteByte($cursorInfo, $i, 0x0) | |
} | |
[System.Runtime.InteropServices.Marshal]::WriteInt32($cursorInfo, 0x0, $structSize) | |
if ([W.User32]::GetCursorInfo($cursorInfo)) | |
{ | |
$hCursor = [System.Runtime.InteropServices.Marshal]::ReadInt64($cursorInfo, 0x8) | |
return $hCursor | |
} | |
<#for ($i = 0; $i -lt $structSize; $i++) | |
{ | |
$offsetValue = [System.Runtime.InteropServices.Marshal]::ReadByte($cursorInfo, $i) | |
Write-Host "Offset: ${i} -> " -NoNewLine | |
Write-Host $offsetValue -ForegroundColor Green -NoNewLine | |
Write-Host ' (' -NoNewLine | |
Write-Host ('0x{0:x}' -f $offsetValue) -ForegroundColor Cyan -NoNewLine | |
Write-Host ')' | |
}#> | |
} | |
finally | |
{ | |
[System.Runtime.InteropServices.Marshal]::FreeHGlobal($cursorInfo) | |
} | |
} | |
$cursors = Initialize-Cursors | |
Write-Host "@Cursors:" | |
foreach ($cursor in $cursors.GetEnumerator()) | |
{ | |
Write-Host "Value:" -NoNewLine | |
Write-Host $cursor.Value -ForegroundColor Green -NoNewLine | |
Write-Host " Name:" -NoNewLine | |
Write-Host $cursor.Key -ForegroundColor Cyan | |
} | |
Write-Host "---`r`n" | |
$oldCursor = 0 | |
while ($true) | |
{ | |
$currentCursor = Get-GlobalMouseCursorIconHandle | |
if ($currentCursor -ne 0 -and $currentCursor -ne $oldCursor) | |
{ | |
$cursorTypeName = ($cursors.GetEnumerator() | ? { $_.Value -eq $currentCursor }).Key | |
if ($cursorTypeName) | |
{ | |
Write-Host "Mouse Cursor Update: " -NoNewLine | |
Write-Host $currentCursor -ForegroundColor Green -NoNewLine | |
Write-Host " (" -NoNewLine | |
Write-Host $cursorTypeName -NoNewLine -ForegroundColor Cyan | |
Write-Host ")" | |
} | |
$oldCursor = $currentCursor | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment