Files
ATV_STDLabelAttach/Handler/Project_form2/Class/JoystickRaw.cs
2025-07-17 16:11:46 +09:00

276 lines
10 KiB
C#

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using HidSharp;
using HidSharp.Reports;
using HidSharp.Reports.Encodings;
namespace arDev.Joystick
{
public class JoystickRaw : IDisposable
{
HidDevice _dev;
HidStream _hidStream;
public Boolean IsOpen { get; private set; }
public event EventHandler Disconnected;
public event EventHandler Connected;
public event EventHandler Changed;
public delegate void MessageHandler(string msg);
public event MessageHandler Message;
public int InputLength { get; private set; }
public int OutputLength { get; private set; }
public int FeatureLength { get; private set; }
public int vid { get; set; }
public int pid { get; set; }
public Boolean[] Buttons = new bool[64]; //버튼정보를 기록한다
Boolean bListUpdate = false;
public JoystickRaw()
{
vid = -1;
pid = -1;
this.InputLength = 0;
this.OutputLength = 0;
this.FeatureLength = 0;
this.IsOpen = false;
this._dev = null;
this._hidStream = null;
DeviceList.Local.Changed += Local_Changed;
Job = new Task(JobMain, ct);
Job.Start();
for (int i = 0; i < Buttons.Length; i++)
Buttons[i] = false;
}
CancellationToken ct ;
public IEnumerable<HidDevice> GetHidDevices()
{
return DeviceList.Local.GetHidDevices();
}
public void Connect(int vid, int pid)
{
this.vid = vid;
this.pid = pid;
}
public void Connect(HidDevice device)
{
this.vid = device.VendorID;
this.pid = device.ProductID;
}
Task Job = null;
private bool disposed = false;
DateTime LastConnTime = DateTime.Now;
void JobMain()
{
//개체가 소멸하기전까지 진행한다
while (this.disposed == false)
{
if (IsOpen == false)
{
if (this.vid == -1 || this.pid == -1)
{
//아직설정되지 않았으니 대기를한다
System.Threading.Thread.Sleep(3000);
}
else
{
//연결작업을 시작해야한다
if (bListUpdate || (DateTime.Now - LastConnTime).TotalMilliseconds >= 3000)
{
LastConnTime = DateTime.Now;
//연결작업
var list = this.GetHidDevices();
this._dev = list.Where(t => t.VendorID == this.vid && t.ProductID == this.pid).FirstOrDefault();
if (_dev != null)
{
try
{
IsOpen = _dev.TryOpen(out _hidStream);
if (IsOpen)
{
this.InputLength = _dev.GetMaxInputReportLength();
this.OutputLength = _dev.GetMaxOutputReportLength();
this.FeatureLength = _dev.GetMaxFeatureReportLength();
this._hidStream.ReadTimeout = Timeout.Infinite;
Connected?.Invoke(this, null);
var rawReportDescriptor = _dev.GetRawReportDescriptor();
var msg = ("Report Descriptor:");
msg += string.Format(" {0} ({1} bytes)", string.Join(" ", rawReportDescriptor.Select(d => d.ToString("X2"))), rawReportDescriptor.Length);
Message?.Invoke(msg);
}
else
{
if (this._hidStream != null) this._hidStream.Dispose();
}
}
catch { System.Threading.Thread.Sleep(1500); }
}
else System.Threading.Thread.Sleep(1500);
}
else System.Threading.Thread.Sleep(1500);
}
}
else
{
//데이터를 가지고 온다
using (_hidStream)
{
try
{
reportDescriptor = _dev.GetReportDescriptor();
deviceItem = reportDescriptor.DeviceItems[0];
var inputReportBuffer = new byte[_dev.GetMaxInputReportLength()];
var inputReceiver = reportDescriptor.CreateHidDeviceInputReceiver();
var inputParser = deviceItem.CreateDeviceItemInputParser();
inputReceiver.Start(_hidStream);
while (true)
{
if (!inputReceiver.IsRunning) { break; } // Disconnected?
Report report; //
while (inputReceiver.TryRead(inputReportBuffer, 0, out report))
{
if (inputParser.TryParseReport(inputReportBuffer, 0, report))
{
WriteDeviceItemInputParserResult(inputParser);
}
}
System.Threading.Thread.Sleep(20);
}
inputReceiver = null;
IsOpen = false;
}
catch (Exception ex)
{
Message?.Invoke(ex.Message);
}
finally
{
Disconnected?.Invoke(this, null);
IsOpen = false;
}
}
}
}
}
void WriteDeviceItemInputParserResult(HidSharp.Reports.Input.DeviceItemInputParser parser)
{
while (parser.HasChanged)
{
int changedIndex = parser.GetNextChangedIndex();
var previousDataValue = parser.GetPreviousValue(changedIndex);
var dataValue = parser.GetValue(changedIndex);
var oVal = previousDataValue.GetPhysicalValue();
var nVal = dataValue.GetPhysicalValue();
if (double.IsNaN(oVal)) oVal = 0.0;
if (double.IsNaN(nVal)) nVal = 0.0;
var InputMethod = (Usage)dataValue.Usages.FirstOrDefault();
if (InputMethod.ToString().StartsWith("Button"))
{
var butNo = int.Parse(InputMethod.ToString().Substring(6));
this.Buttons[butNo - 1] = nVal > 0; //버튼값은 기록 210107
}
//이벤트발생
InputChanged?.Invoke(this, new InputChangedEventHandler(
InputMethod, oVal, nVal));
//메세지도 발생함
//var msg = (string.Format(" {0}: {1} -> {2}",
// (Usage)dataValue.Usages.FirstOrDefault(),
// previousDataValue.GetPhysicalValue(),
// dataValue.GetPhysicalValue()));
//Message?.Invoke(msg);
}
}
public event EventHandler<InputChangedEventHandler> InputChanged;
public class InputChangedEventHandler : EventArgs
{
public Usage input { get; set; }
public double oldValue { get; set; }
public double newValue { get; set; }
public InputChangedEventHandler(Usage input_, double oValue_, double nValue_)
{
this.input = input_;
this.oldValue = oValue_;
this.newValue = nValue_;
}
}
ReportDescriptor reportDescriptor;
DeviceItem deviceItem;
~JoystickRaw()
{
Dispose(false);
}
public void Dispose()
{
Dispose(true);
// This object will be cleaned up by the Dispose method.
// Therefore, you should call GC.SupressFinalize to
// take this object off the finalization queue
// and prevent finalization code for this object
// from executing a second time.
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
// Check to see if Dispose has already been called.
if (!this.disposed)
{
// If disposing equals true, dispose all managed
// and unmanaged resources.
if (disposing)
{
// Dispose managed resources.
this._dev = null;
}
Job.Wait();
Job.Dispose();
// Call the appropriate methods to clean up
// unmanaged resources here.
// If disposing is false,
// only the following code is executed.
//CloseHandle(handle);
//handle = IntPtr.Zero;
// Note disposing has been done.
DeviceList.Local.Changed -= Local_Changed;
disposed = true;
}
}
private void Local_Changed(object sender, DeviceListChangedEventArgs e)
{
Changed?.Invoke(sender, e);
bListUpdate = true;
}
}
}