115 lines
4.3 KiB
C#
115 lines
4.3 KiB
C#
using PIEHidNetCore;
|
|
using System.IO;
|
|
using System.Windows.Media;
|
|
|
|
namespace PamhagenSysCtrl.Helpers {
|
|
public class Xbe24Keyboard : IDisposable, PIEDataHandler, PIEErrorHandler {
|
|
|
|
public enum LedBank { UPPER = 0, LOWER = 1 }
|
|
|
|
public record struct KeyState(byte[] Rows) {
|
|
public readonly bool GetKey(int n) => (Rows[n / 6] & (1 << (n % 6))) != 0;
|
|
}
|
|
|
|
protected readonly PIEDevice XbeDevice;
|
|
|
|
private KeyState LastKeyState = new(new byte[4]);
|
|
private readonly (Color Color, bool Flashing)[] LastStates = new (Color, bool)[48];
|
|
|
|
public bool IsKeyPressed(int keyIndex) => LastKeyState.GetKey(keyIndex);
|
|
|
|
public event EventHandler<int>? KeyDown;
|
|
public event EventHandler<int>? KeyUp;
|
|
public event EventHandler<KeyState>? KeysChanged;
|
|
|
|
public Xbe24Keyboard(int pid = 0x0555) {
|
|
foreach (var device in PIEDevice.EnumeratePIE()) {
|
|
if (device.Pid == pid && device.HidUsagePage == 0x0C && device.HidUsage == 1 && device.WriteLength > 1) {
|
|
XbeDevice = device;
|
|
break;
|
|
}
|
|
}
|
|
if (XbeDevice == null)
|
|
throw new ArgumentException($"No XBE keyboard with id 05f3:{pid:x4}");
|
|
|
|
int res;
|
|
if ((res = XbeDevice.SetupInterface()) != 0)
|
|
throw new IOException($"Unable to SetupInterface for XBE keyboard: {res}");
|
|
if ((res = XbeDevice.SetDataCallback(this)) != 0)
|
|
throw new IOException($"Unable to SetDataCallback for XBE keyboard: {res}");
|
|
if ((res = XbeDevice.SetErrorCallback(this)) != 0)
|
|
throw new IOException($"Unable to SetErrorCallback for XBE keyboard: {res}");
|
|
}
|
|
|
|
public void Dispose() {
|
|
XbeDevice?.CloseInterface();
|
|
}
|
|
|
|
public void HandlePIEHidData(byte[] data, PIEDevice sourceDevice, int error) {
|
|
if (sourceDevice != XbeDevice)
|
|
return;
|
|
var current = new KeyState(data[3..8]);
|
|
var last = LastKeyState;
|
|
LastKeyState = current;
|
|
HandleKeyStateChange(current, last);
|
|
}
|
|
|
|
public void HandlePIEHidError(PIEDevice sourceDevice, int error) {
|
|
if (sourceDevice != XbeDevice)
|
|
return;
|
|
// TODO
|
|
}
|
|
|
|
protected void HandleKeyStateChange(KeyState current, KeyState last) {
|
|
for (int i = 0; i < 24; i++) {
|
|
if (!last.GetKey(i) && current.GetKey(i)) {
|
|
KeyDown?.Invoke(this, i);
|
|
} else if (last.GetKey(i) && !current.GetKey(i)) {
|
|
KeyUp?.Invoke(this, i);
|
|
}
|
|
}
|
|
KeysChanged?.Invoke(this, current);
|
|
}
|
|
|
|
protected void SendCommand(byte command, byte[] payload) {
|
|
byte[] data = new byte[XbeDevice.WriteLength];
|
|
data[1] = command;
|
|
Array.Copy(payload, 0, data, 2, Math.Min(payload.Length, data.Length - 2));
|
|
|
|
int res;
|
|
do {
|
|
res = XbeDevice.WriteData(data);
|
|
} while (res == 404);
|
|
if (res != 0)
|
|
throw new IOException($"Unable to WriteData for XBE keyboard: {res}");
|
|
}
|
|
|
|
public void SetBacklight(int keyIndex, Color color, bool flashing = false) {
|
|
SetBacklight(keyIndex, LedBank.UPPER, color, flashing);
|
|
SetBacklight(keyIndex, LedBank.LOWER, color, flashing);
|
|
}
|
|
|
|
public void SetBacklight(int keyIndex, LedBank bank, Color color, bool flashing = false) {
|
|
if (LastStates[keyIndex * 2 + (int)bank] == (color, flashing))
|
|
return;
|
|
SendCommand(165, [(byte)keyIndex, (byte)bank, color.R, color.G, color.B, (byte)(flashing ? 1 : 0)]);
|
|
LastStates[keyIndex * 2 + (int)bank] = (color, flashing);
|
|
}
|
|
|
|
public void SetBacklight(Color color) {
|
|
SetBacklight(LedBank.UPPER, color);
|
|
SetBacklight(LedBank.LOWER, color);
|
|
}
|
|
|
|
public void SetBacklight(LedBank bank, Color color) {
|
|
SendCommand(166, [(byte)bank, color.R, color.G, color.B]);
|
|
for (int i = 0; i < LastStates.Length; i++)
|
|
LastStates[i] = (color, false);
|
|
}
|
|
|
|
public void SetFashFrequency(int ms) {
|
|
SendCommand(180, [(byte)(ms / 16)]);
|
|
}
|
|
}
|
|
}
|