Skip to content

Instantly share code, notes, and snippets.

@lbehm
Last active June 28, 2018 22:18
Show Gist options
  • Save lbehm/38f960e40cba6f2595c8e770a4b433b0 to your computer and use it in GitHub Desktop.
Save lbehm/38f960e40cba6f2595c8e770a4b433b0 to your computer and use it in GitHub Desktop.
First try on working with Saitek X52Pro MFD
[string]$dll = (gi HKLM:\SOFTWARE\Saitek\DirectOutput).GetValue('DirectOutput_Saitek').Replace('\', '\\')
Add-Type -Namespace Saitek -Name "DirectOutput" -UsingNamespace "System.Collections.Generic" -MemberDefinition @"
[UnmanagedFunctionPointer(CallingConvention.StdCall)] private delegate void Pfn_DirectOutput_EnumerateCallback(IntPtr hDevice, IntPtr pCtxt);
[UnmanagedFunctionPointer(CallingConvention.StdCall)] private delegate void Pfn_DirectOutput_DeviceChange(IntPtr hDevice, bool bAdded, IntPtr pCtxt);
[UnmanagedFunctionPointer(CallingConvention.StdCall)] private delegate void Pfn_DirectOutput_PageChange(IntPtr hDevice, uint dwPage, bool bSetActive, IntPtr pCtxt);
[UnmanagedFunctionPointer(CallingConvention.StdCall)] private delegate void Pfn_DirectOutput_SoftButtonChange(IntPtr hDevice, uint dwButtons, IntPtr pCtxt);
[DllImport("$dll", SetLastError = true, CharSet = CharSet.Ansi)] public static extern IntPtr DirectOutput_Initialize([MarshalAs(UnmanagedType.LPWStr)]System.Text.StringBuilder wszPluginName);
[DllImport("$dll", SetLastError = true)] public static extern IntPtr DirectOutput_Deinitialize();
[DllImport("$dll", SetLastError = true)] private static extern IntPtr DirectOutput_RegisterDeviceCallback(Pfn_DirectOutput_DeviceChange pfnCb, IntPtr pCtxt);
[DllImport("$dll", SetLastError = true)] private static extern IntPtr DirectOutput_Enumerate(Pfn_DirectOutput_EnumerateCallback pfnCb, IntPtr pCtxt);
[DllImport("$dll", SetLastError = true)] private static extern IntPtr DirectOutput_RegisterPageCallback(IntPtr hDevice, Pfn_DirectOutput_PageChange pfnCb, IntPtr pCtxt);
[DllImport("$dll", SetLastError = true)] private static extern IntPtr DirectOutput_RegisterSoftButtonCallback(IntPtr hDevice, Pfn_DirectOutput_SoftButtonChange pfnCb, IntPtr pCtxt);
//[DllImport("$dll", SetLastError = true)] private static extern IntPtr DirectOutput_GetDeviceType(IntPtr hDevice, LPGUID pGuid);
//[DllImport("$dll", SetLastError = true)] private static extern IntPtr DirectOutput_GetDeviceInstance(IntPtr hDevice, LPGUID pGuid);
[DllImport("$dll", SetLastError = true, CharSet = CharSet.Ansi)] private static extern IntPtr DirectOutput_SetProfile(IntPtr hDevice, uint cchProfile, [MarshalAs(UnmanagedType.LPWStr)]System.Text.StringBuilder wszProfile);
[DllImport("$dll", SetLastError = true)] private static extern IntPtr DirectOutput_AddPage(IntPtr hDevice, uint dwPage, uint dwFlags);
[DllImport("$dll", SetLastError = true)] private static extern IntPtr DirectOutput_RemovePage(IntPtr hDevice, uint dwPage);
[DllImport("$dll", SetLastError = true)] private static extern IntPtr DirectOutput_SetLed(IntPtr hDevice, uint dwPage, uint dwIndex, uint dwValue);
[DllImport("$dll", SetLastError = true, CharSet = CharSet.Ansi)] private static extern IntPtr DirectOutput_SetString(IntPtr hDevice, uint dwPage, uint dwIndex, uint cchValue, [MarshalAs(UnmanagedType.LPWStr)]System.Text.StringBuilder wszValue);
[DllImport("$dll", SetLastError = true)] private static extern IntPtr DirectOutput_SetImage(IntPtr hDevice, uint dwPage, uint dwIndex, uint cbValue, IntPtr pvValue);
[DllImport("$dll", SetLastError = true, CharSet = CharSet.Ansi)] private static extern IntPtr DirectOutput_SetImageFromFile(IntPtr hDevice, uint dwPage, uint dwIndex, uint cchFilename, [MarshalAs(UnmanagedType.LPWStr)]System.Text.StringBuilder wszFilename);
private static bool _test(IntPtr a) {
if (a == IntPtr.Zero)
return true;
System.Runtime.InteropServices.Marshal.ThrowExceptionForHR(a.ToInt32());
return false;
}
public class Device {
public class Page {
public Device Owner;
public uint Id;
private string _Line0;
private string _Line1;
private string _Line2;
public string Line0 {
get { return _Line0; }
set { if (_set_string(0, value)) _Line0 = value; }
}
public string Line1 {
get { return _Line1; }
set { if (_set_string(1, value)) _Line1 = value; }
}
public string Line2 {
get { return _Line2; }
set { if (_set_string(2, value)) _Line2 = value; }
}
public Page(Device owner, uint id, bool Active = false) {
Owner = owner;
Id = id;
_Line0 = "";
_Line1 = "";
_Line2 = "";
_test(DirectOutput_AddPage(Owner.hDevice, Id, Convert.ToUInt32(Active ? 1 : 0)));
}
private bool _set_string(uint Line, string Value) {
System.Text.StringBuilder sb = new System.Text.StringBuilder(Value);
return _test(DirectOutput_SetString(Owner.hDevice, Id, Line, Convert.ToUInt32(Value.Length), sb));
}
};
public class PageChangeEventArgs : EventArgs {
public Device Device;
public Page Page;
public bool SetActive;
public PageChangeEventArgs(Device device, Page page, bool setActive) {
Device = device;
Page = page;
SetActive = setActive;
}
};
public class ButtonEventArgs : EventArgs {
public Device Device;
public uint Button;
public long Duration;
public ButtonEventArgs(Device device, uint button, long duration) {
Device = device;
Button = button;
Duration = duration;
}
};
public IntPtr hDevice;
public List<Page> Pages;
public Page ActivePage;
public event EventHandler<PageChangeEventArgs> PageChange;
public event EventHandler<ButtonEventArgs> ButtonDown;
public event EventHandler<ButtonEventArgs> ButtonPress;
public event EventHandler<ButtonEventArgs> ButtonLongPress;
public event EventHandler<ButtonEventArgs> ButtonUp;
private Pfn_DirectOutput_PageChange _PageChangeCallback;
private Pfn_DirectOutput_SoftButtonChange _SoftButtonChangeCallback;
private System.Timers.Timer ButtonUpTimer;
private System.Diagnostics.Stopwatch ButtonDownStopWatch;
private uint ActiveButton; // currently pressed button id; 0 if no key is pressed
public Device(IntPtr Device) {
hDevice = Device;
Pages = new List<Page>();
ActivePage = new Page(this, 0, true);
Pages.Add(ActivePage);
ButtonUpTimer = new System.Timers.Timer(100);
ButtonUpTimer.Elapsed += (sender, e) => {
ButtonDownStopWatch.Stop();
ButtonUpTimer.Enabled = false;
var button = ActiveButton;
ActiveButton = 0;
OnButtonUp(this, new ButtonEventArgs(this, button, ButtonDownStopWatch.ElapsedMilliseconds));
};
ButtonDownStopWatch = new System.Diagnostics.Stopwatch();
_PageChangeCallback = new Pfn_DirectOutput_PageChange(_onPageChange);
_test(DirectOutput_RegisterPageCallback(hDevice, _PageChangeCallback, IntPtr.Zero));
_SoftButtonChangeCallback = new Pfn_DirectOutput_SoftButtonChange(_onButtonDown);
_test(DirectOutput_RegisterSoftButtonCallback(hDevice, _SoftButtonChangeCallback, IntPtr.Zero));
}
private void _onPageChange(IntPtr hDevice, uint dwPage, bool bSetActive, IntPtr pCtxt) {
var Page = Pages.Find(page => page.Id == dwPage);
if (bSetActive)
ActivePage = Page;
EventHandler<PageChangeEventArgs> handler = PageChange;
if (handler != null)
handler(this, new PageChangeEventArgs(this, Page, bSetActive));
}
private void _onButtonDown(IntPtr hDevice, uint dwButton, IntPtr pCtxt) {
if ((dwButton & 1) == 1) // every button that is sended simultaneously with ok/select
dwButton = 1; // is only passed as ok/select
long duration = ButtonDownStopWatch.ElapsedMilliseconds;
if (dwButton == 0) { // holding buttons 1,2,4 and page-buttons are sending 0
if (ActiveButton > 0) {
ButtonUpTimer.Stop();
ButtonUpTimer.Start(); // reset Timer
}
} else {
ButtonUpTimer.Stop();
ActiveButton = dwButton;
ButtonUpTimer.Enabled = true;
ButtonUpTimer.Start();
ButtonDownStopWatch.Restart();
duration = 0;
OnButtonDown(this, new ButtonEventArgs(this, dwButton, duration));
}
if (ActiveButton > 0)
OnButtonPress(this, new ButtonEventArgs(this, ActiveButton, duration));
if (duration > 750) {// long click ms
ButtonDownStopWatch.Restart();
OnButtonLongPress(this, new ButtonEventArgs(this, ActiveButton, duration));
}
}
protected void OnButtonDown(object sender, ButtonEventArgs args) {
EventHandler<ButtonEventArgs> handler = ButtonDown;
if (handler != null)
handler(this, args);
}
protected void OnButtonPress(object sender, ButtonEventArgs args) {
EventHandler<ButtonEventArgs> handler = ButtonPress;
if (handler != null)
handler(this, args);
}
protected void OnButtonLongPress(object sender, ButtonEventArgs args) {
EventHandler<ButtonEventArgs> handler = ButtonLongPress;
if (handler != null)
handler(this, args);
}
protected void OnButtonUp(object sender, ButtonEventArgs args) {
EventHandler<ButtonEventArgs> handler = ButtonUp;
if (handler != null)
handler(this, args);
}
};
public static bool Init(String Name) {
System.Text.StringBuilder sb = new System.Text.StringBuilder(Name);
if (_test(DirectOutput_Initialize(sb))) {
_DeviceChangeCallback = new Pfn_DirectOutput_DeviceChange(_onDeviceChange);
_EnumerateCallback = new Pfn_DirectOutput_EnumerateCallback(_onEnumerate);
return _test(DirectOutput_RegisterDeviceCallback(_DeviceChangeCallback, IntPtr.Zero)) && _test(DirectOutput_Enumerate(_EnumerateCallback, IntPtr.Zero));
}
return false;
}
public static bool Reset() {
return _test(DirectOutput_Deinitialize());
}
public class DeviceChangeEventArgs : EventArgs {
public bool Added;
};
public static event EventHandler<DeviceChangeEventArgs> DeviceChange;
private static Pfn_DirectOutput_DeviceChange _DeviceChangeCallback;
private static Pfn_DirectOutput_EnumerateCallback _EnumerateCallback;
public static List<Device> Devices = new List<Device>();
private static void _onDeviceChange(IntPtr hDevice, bool bAdded, IntPtr pCtxt) {
Device dev = Devices.Find(device => device.hDevice == hDevice);
if (dev == null) {
if (bAdded) {
dev = new Device(hDevice);
Devices.Add(dev);
}
} else {
if (!bAdded)
Devices.Remove(dev);
}
EventHandler<DeviceChangeEventArgs> handler = DeviceChange;
if (handler != null) {
DeviceChangeEventArgs args = new DeviceChangeEventArgs();
args.Added = bAdded;
handler(dev, args);
}
}
private static void _onEnumerate(IntPtr hDevice, IntPtr pCtxt) {
if (Devices.Find(device => device.hDevice == hDevice) == null)
Devices.Add(new Device(hDevice));
}
"@
$DirectOutput = [Saitek.DirectOutput]
function Initialize-DirectOutput ([string]$PluginName)
{
$DirectOutput::Init($PluginName)
}
function Deinitialize-DirectOutput
{
$DirectOutput::Reset()
}
function Get-DirectOutputDevices
{
$DirectOutput::Devices
}
function Write-MFD ([string] $Line0="", [string] $Line1="", [string] $Line2="", $Device=(Get-DirectOutputDevices|select -f 1))
{
$Device.ActivePage.Line0 = $Line0
$Device.ActivePage.Line1 = $Line1
$Device.ActivePage.Line2 = $Line2
}
# examples:
Deinitialize-DirectOutput | Out-Null
Initialize-DirectOutput "app" | Out-Null
Register-ObjectEvent -InputObject $DirectOutput::Devices[0] -EventName PageChange -Action {
Param([Saitek.DirectOutput+Device]$Device, [Saitek.DirectOutput+Device+PageChangeEventArgs]$EventArgs)
Write-Host "Page: $($EventArgs.Page.Id) Active: $($EventArgs.SetActive)"
} | Out-Null
Register-ObjectEvent -InputObject $DirectOutput::Devices[0] -EventName ButtonDown -Action {
Param([Saitek.DirectOutput+Device]$Device, [Saitek.DirectOutput+Device+ButtonEventArgs]$EventArgs)
Write-Host "Button $($EventArgs.Button) pressed down"
} | Out-Null
<#Register-ObjectEvent -InputObject $DirectOutput::Devices[0] -EventName ButtonPress -Action {
Param([Saitek.DirectOutput+Device]$Device, [Saitek.DirectOutput+Device+ButtonEventArgs]$EventArgs)
Write-Host "Button $($EventArgs.Button) pressed"
} | Out-Null#>
Register-ObjectEvent -InputObject $DirectOutput::Devices[0] -EventName ButtonLongPress -Action {
Param([Saitek.DirectOutput+Device]$Device, [Saitek.DirectOutput+Device+ButtonEventArgs]$EventArgs)
Write-Host "Button $($EventArgs.Button) pressed long"
} | Out-Null
Register-ObjectEvent -InputObject $DirectOutput::Devices[0] -EventName ButtonUp -Action {
Param([Saitek.DirectOutput+Device]$Device, [Saitek.DirectOutput+Device+ButtonEventArgs]$EventArgs)
Write-Host "Button $($EventArgs.Button) released"
} | Out-Null
<#Register-ObjectEvent -InputObject $DirectOutput -EventName DeviceChange -Action {
Param([Saitek.DirectOutput+Device]$Device, [Saitek.DirectOutput+DeviceChangeEventArgs]$EventArgs)
Write-Host "Device changed: $($EventArgs.Added)"
} | Out-Null#>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment