Reading Raw Data from a Foot Pedal HID
(more info to come)

$source = @"
using System;
using System.Text;
using System.Runtime.InteropServices;
using System.Windows.Forms;
public class RawInputForm : Form
{
[StructLayout(LayoutKind.Sequential)]
struct RAWINPUTDEVICE
{
public ushort usUsagePage;
public ushort usUsage;
public uint dwFlags;
public IntPtr hwndTarget;
}
[StructLayout(LayoutKind.Sequential)]
struct RAWINPUTHEADER
{
public int dwType;
public int dwSize;
public IntPtr hDevice;
public IntPtr wParam;
}
[StructLayout(LayoutKind.Sequential)]
struct RAWHID
{
public int dwSizeHid;
public int dwCount;
public byte bRawData; // Actual data follows this byte
}
[DllImport("user32.dll", SetLastError = true)]
static extern bool RegisterRawInputDevices(RAWINPUTDEVICE[] pRawInputDevices, uint uiNumDevices, uint cbSize);
[DllImport("user32.dll")]
static extern uint GetRawInputData(IntPtr hRawInput, uint uiCommand, IntPtr pData, ref uint pcbSize, uint cbSizeHeader);
const int WM_INPUT = 0x00FF;
const uint RIDEV_INPUTSINK = 0x00000100;
const uint RID_INPUT = 0x10000003;
public RawInputForm()
{
this.Load += new EventHandler(this.OnLoad);
}
public void KeepAlive() { } // Suppress PowerShell warning
private void OnLoad(object sender, EventArgs e)
{
RAWINPUTDEVICE[] rid = new RAWINPUTDEVICE[1];
rid[0].usUsagePage = 0x0C;
rid[0].usUsage = 0x01;
rid[0].dwFlags = RIDEV_INPUTSINK;
rid[0].hwndTarget = this.Handle;
if (!RegisterRawInputDevices(rid, (uint)rid.Length, (uint)Marshal.SizeOf(typeof(RAWINPUTDEVICE))))
{
MessageBox.Show("Failed to register raw input device.");
}
}
protected override void WndProc(ref Message m)
{
if (m.Msg == WM_INPUT)
{
uint dwSize = 0;
GetRawInputData(m.LParam, RID_INPUT, IntPtr.Zero, ref dwSize, (uint)Marshal.SizeOf(typeof(RAWINPUTHEADER)));
IntPtr buffer = Marshal.AllocHGlobal((int)dwSize);
GetRawInputData(m.LParam, RID_INPUT, buffer, ref dwSize, (uint)Marshal.SizeOf(typeof(RAWINPUTHEADER)));
byte[] rawData = new byte[dwSize];
Marshal.Copy(buffer, rawData, 0, (int)dwSize);
Marshal.FreeHGlobal(buffer);
StringBuilder sb = new StringBuilder();
sb.AppendLine("Raw Input Data:");
for (int i = 0; i < rawData.Length; i++)
{
sb.AppendFormat("{0:X2} ", rawData[i]);
}
sb.AppendLine();
if (rawData.Length >= 36)
{
int usageId = BitConverter.ToInt32(rawData, 24);
if (usageId != 0)
{
sb.AppendLine(String.Format("Detected Usage ID: 0x{0:X}", usageId));
}
int buttonCode32 = BitConverter.ToInt32(rawData, 32);
int buttonCode28 = BitConverter.ToInt32(rawData, 28);
int buttonCode = buttonCode32 != 0 ? buttonCode32 : buttonCode28;
string buttonName = "None/Released";
if ((buttonCode & 0x01000000) != 0) buttonName = "Right";
else if ((buttonCode & 0x02000000) != 0) buttonName = "Middle";
else if ((buttonCode & 0x03000000) != 0) buttonName = "MiddleHigh";
else if ((buttonCode & 0x04000000) != 0) buttonName = "Left";
else if (buttonCode == 2) buttonName = "Top";
sb.AppendLine(String.Format("Footpad Button Code: {0} ({1})", buttonCode, buttonName));
}
Console.WriteLine(sb.ToString());
}
base.WndProc(ref m);
}
}
"@
Add-Type -TypeDefinition $source -ReferencedAssemblies "System.Windows.Forms.dll"
# Handler delegate
$handler = [ConsoleCancelEventHandler]{
param($sender, $args)
Write-Host "`nCtrl+C pressed—shutting down..."
# Prevent PowerShell from also terminating abruptly
$args.Cancel = $true
[System.Windows.Forms.Application]::ExitThread()
}
# Wire it up
[Console]::add_CancelKeyPress($handler)
# Build and run your form
$form = New-Object RawInputForm
$form.WindowState = 'Minimized'
$form.ShowInTaskbar = $false
[System.Windows.Forms.Application]::Run($form)