Skip to content

Instantly share code, notes, and snippets.

@DarkCoderSc
Created January 15, 2022 18:45
Show Gist options
  • Save DarkCoderSc/a85446bf3d1bea9e616b5a5f9d7a6615 to your computer and use it in GitHub Desktop.
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.
<#-------------------------------------------------------------------------------
.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