added missing files

This commit is contained in:
Alexander Eckart committed 2012-12-09 19:07:30 +01:00
1 parent f577e53925
commit 3941c631a7
5 files changed
+1469

No files matched your search

+61
View File
@@ -0,0 +1,61 @@
using System;
using System.Collections.Generic;
using System.Text;
using Vocaluxe.Lib.Input;
using Vocaluxe.Lib.Input.WiiMote;
namespace Vocaluxe.Base
{
static class CInput
{
static IInput _Input;
public static void Init()
{
_Input = new CWiiMote();
_Input.Init();
}
public static void Close()
{
_Input.Close();
}
public static bool Connect()
{
return _Input.Connect();
}
public static bool Disconnect()
{
return _Input.Disconnect();
}
public static bool IsConnected()
{
return _Input.IsConnected();
}
public static void Update()
{
_Input.Update();
}
public static bool PollKeyEvent(ref KeyEvent KeyEvent)
{
return _Input.PollKeyEvent(ref KeyEvent);
}
public static bool PollMouseEvent(ref MouseEvent MouseEvent)
{
return _Input.PollMouseEvent(ref MouseEvent);
}
public static void SetRumble(float Duration)
{
_Input.SetRumble(Duration);
}
}
}
+267
View File
@@ -0,0 +1,267 @@
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading;
using Vocaluxe.Base;
namespace Vocaluxe.Lib.Input
{
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
public struct HIDDeviceInfo
{
[MarshalAsAttribute(UnmanagedType.LPTStr)]
public String Path;
public ushort VendorString;
public ushort ProductID;
public String SerialNumber;
public ushort ReleaseNumber;
public String ManufacturerString;
public String ProductString;
public ushort UsagePage;
public ushort Usage;
public int InterfaceNumber;
public IntPtr Next;
}
public static class CHIDAPI
{
#if ARCH_X86
#if WIN
private const string HIDapiDll = "x86\\hidapi.dll";
#endif
#if LINUX
private const string HIDapiDll = "libhidapi.so";
#endif
#endif
#if ARCH_X64
#if WIN
private const string HIDapiDll = "x64\\hidapi.dll";
#endif
#if LINUX
private const string HIDapiDll = "libhidapi.so";
#endif
#endif
[DllImport(HIDapiDll, ExactSpelling = false, CallingConvention = CallingConvention.Cdecl, EntryPoint = "hid_init", CharSet = CharSet.Unicode)]
private static extern int hid_init();
public static bool Init()
{
int result = -1;
try
{
result = hid_init();
}
catch(Exception e)
{
CLog.LogError("Error CHIDAPI.Init(): " + e.ToString());
return false;
}
if (result == 0)
return true;
return false;
}
[DllImport(HIDapiDll, ExactSpelling = false, CallingConvention = CallingConvention.Cdecl, EntryPoint = "hid_exit", CharSet = CharSet.Unicode)]
private static extern int hid_exit();
public static bool Exit()
{
int result = -1;
try
{
result = hid_exit();
}
catch (Exception e)
{
CLog.LogError("Error CHIDAPI.Exit(): " + e.ToString());
return false;
}
if (result == 0)
return true;
return false;
}
[DllImport(HIDapiDll, ExactSpelling = false, CallingConvention = CallingConvention.Cdecl, EntryPoint = "hid_enumerate", CharSet = CharSet.Ansi)]
private static extern IntPtr hid_enumerate(ushort VendorID, ushort ProductID); //HIDDeviceInfo
public static IntPtr Enumerate(ushort VendorID, ushort ProductID) //HIDDeviceInfo
{
return hid_enumerate(VendorID, ProductID);
}
[DllImport(HIDapiDll, ExactSpelling = false, CallingConvention = CallingConvention.Cdecl, EntryPoint = "hid_free_enumeration", CharSet = CharSet.Unicode)]
private static extern void hid_free_enumeration(HIDDeviceInfo devs);
public static void FreeEnumeration(HIDDeviceInfo devs)
{
hid_free_enumeration(devs);
}
[DllImport(HIDapiDll, ExactSpelling = false, CallingConvention = CallingConvention.Cdecl, EntryPoint = "hid_open", CharSet = CharSet.Unicode)]
private static extern IntPtr hid_open(ushort VendorID, ushort ProductID, IntPtr SerialNumber);
public static bool Open(ushort VendorID, ushort ProductID, out IntPtr Handle)
{
Handle = IntPtr.Zero;
try
{
Handle = hid_open(VendorID, ProductID, IntPtr.Zero);
}
catch (Exception e)
{
CLog.LogError("Error CHIDAPI.Open(): " + e.ToString());
return false;
}
if (Handle != IntPtr.Zero)
return true;
return false;
}
[DllImport(HIDapiDll, ExactSpelling = false, CallingConvention = CallingConvention.Cdecl, EntryPoint = "hid_open_path", CharSet = CharSet.Unicode)]
private static extern IntPtr hid_open_path(string Path);
public static IntPtr OpenPath(string Path)
{
return hid_open_path(Path);
}
[DllImport(HIDapiDll, ExactSpelling = false, CallingConvention = CallingConvention.Cdecl, EntryPoint = "hid_write", CharSet = CharSet.Unicode)]
private static extern int hid_write(IntPtr device, byte[] data, int length);
public static int Write(IntPtr Device, byte[] Data)
{
return hid_write(Device, Data, Data.Length);
}
[DllImport(HIDapiDll, ExactSpelling = false, CallingConvention = CallingConvention.Cdecl, EntryPoint = "hid_read_timeout", CharSet = CharSet.Unicode)]
private static extern int hid_read_timeout(IntPtr device, IntPtr data, int length, int milliseconds);
public static int ReadTimeout(IntPtr Device, out byte[] Data, int length, int milliseconds)
{
Data = new byte[length];
IntPtr data = Marshal.AllocHGlobal(length);
int result = -1;
try
{
result = hid_read_timeout(Device, data, length, milliseconds);
}
catch (Exception e)
{
result = -1;
CLog.LogError("Error CHIDAPI.ReadTimeout(): " + e.ToString());
}
if (result != -1)
Marshal.Copy(data, Data, 0, result);
else
Data = null;
Marshal.FreeHGlobal(data);
return result;
}
[DllImport(HIDapiDll, ExactSpelling = false, CallingConvention = CallingConvention.Cdecl, EntryPoint = "hid_read", CharSet = CharSet.Unicode)]
private static extern int hid_read(IntPtr device, IntPtr data, int length);
public static int Read(IntPtr Device, out byte[] Data, int length)
{
Data = new byte[length];
IntPtr data = Marshal.AllocHGlobal(length);
int result = -1;
try
{
result = hid_read(Device, data, length);
}
catch (Exception e)
{
result = -1;
CLog.LogError("Error CHIDAPI.Read(): " + e.ToString());
}
if (result != -1)
Marshal.Copy(data, Data, 0, result);
else
Data = null;
Marshal.FreeHGlobal(data);
return result;
}
[DllImport(HIDapiDll, ExactSpelling = false, CallingConvention = CallingConvention.Cdecl, EntryPoint = "hid_set_nonblocking", CharSet = CharSet.Unicode)]
private static extern int hid_set_nonblocking(IntPtr device, bool nonblock);
public static int Read(IntPtr Device, bool Nonblocking)
{
return hid_set_nonblocking(Device, Nonblocking);
}
[DllImport(HIDapiDll, ExactSpelling = false, CallingConvention = CallingConvention.Cdecl, EntryPoint = "hid_send_feature_report", CharSet = CharSet.Unicode)]
private static extern int hid_send_feature_report(IntPtr device, string data, int length);
public static int SendFeatureReport(IntPtr Device, string Data)
{
return hid_send_feature_report(Device, Data, Data.Length);
}
[DllImport(HIDapiDll, ExactSpelling = false, CallingConvention = CallingConvention.Cdecl, EntryPoint = "hid_get_feature_report", CharSet = CharSet.Unicode)]
private static extern int hid_get_feature_report(IntPtr device, string Data, int length);
public static int GetFeatureReport(IntPtr Device, string Data)
{
return hid_get_feature_report(Device, Data, Data.Length);
}
[DllImport(HIDapiDll, ExactSpelling = false, CallingConvention = CallingConvention.Cdecl, EntryPoint = "hid_close", CharSet = CharSet.Unicode)]
private static extern void hid_close(IntPtr device);
public static bool Close(IntPtr Device)
{
try
{
hid_close(Device);
}
catch (Exception e)
{
CLog.LogError("Error CHIDAPI.Close(): " + e.ToString());
return false;
}
return true;
}
[DllImport(HIDapiDll, ExactSpelling = false, CallingConvention = CallingConvention.Cdecl, EntryPoint = "hid_get_manufacturer_string", CharSet = CharSet.Unicode)]
private static extern int hid_get_manufacturer_string(IntPtr device, string Data, int maxlength);
public static int GetManufacturerString(IntPtr Device, string Data, int MaxLength)
{
return hid_get_manufacturer_string(Device, Data, MaxLength);
}
[DllImport(HIDapiDll, ExactSpelling = false, CallingConvention = CallingConvention.Cdecl, EntryPoint = "hid_get_product_string", CharSet = CharSet.Unicode)]
private static extern int hid_get_product_string(IntPtr device, string Data, int maxlength);
public static int GetProductString(IntPtr Device, string Data, int MaxLength)
{
return hid_get_product_string(Device, Data, MaxLength);
}
[DllImport(HIDapiDll, ExactSpelling = false, CallingConvention = CallingConvention.Cdecl, EntryPoint = "hid_get_serial_number_string", CharSet = CharSet.Unicode)]
private static extern int hid_get_serial_number_string(IntPtr device, string Data, int maxlength);
public static int GetSerialNumberString(IntPtr Device, string Data, int MaxLength)
{
return hid_get_serial_number_string(Device, Data, MaxLength);
}
[DllImport(HIDapiDll, ExactSpelling = false, CallingConvention = CallingConvention.Cdecl, EntryPoint = "hid_get_indexed_string", CharSet = CharSet.Unicode)]
private static extern int hid_get_indexed_string(IntPtr device, string Data, int maxlength);
public static int GetIndexedString(IntPtr Device, string Data, int MaxLength)
{
return hid_get_indexed_string(Device, Data, MaxLength);
}
[DllImport(HIDapiDll, ExactSpelling = false, CallingConvention = CallingConvention.Cdecl, EntryPoint = "hid_error", CharSet = CharSet.Unicode)]
private static extern string hid_error(IntPtr device);
public static string Error(IntPtr Device)
{
return hid_error(Device);
}
}
}
+145
View File
@@ -0,0 +1,145 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Drawing;
using System.Text;
using Vocaluxe.Base;
namespace Vocaluxe.Lib.Input
{
enum EGesture
{
None,
Back,
ScrollDown,
ScrollUp
}
interface IInput
{
bool Init();
void Close();
bool Connect();
bool Disconnect();
bool IsConnected();
void Update();
bool PollKeyEvent(ref KeyEvent KeyEvent);
bool PollMouseEvent(ref MouseEvent MouseEvent);
void SetRumble(float Duration);
}
class RumbleTimer
{
private Stopwatch _timer;
private float _duration;
public bool ShouldStart
{
get
{
if (!_timer.IsRunning && _duration != 0f)
{
_timer.Start();
return true;
}
return false;
}
}
public bool ShouldStop
{
get
{
if (_timer.IsRunning && _timer.ElapsedMilliseconds / 1000f >= _duration)
{
_timer.Reset();
_duration = 0f;
return true;
}
return false;
}
}
public RumbleTimer()
{
_timer = new Stopwatch();
_duration = 0f;
}
public void Set(float Duration)
{
if (!_timer.IsRunning)
{
_duration = Duration;
_timer.Reset();
}
}
public void Reset()
{
_duration = 0f;
}
}
class CGesture
{
Point _Begin;
bool _locked;
public CGesture()
{
_locked = false;
}
public void SetLockPosition(Point Position)
{
_locked = true;
_Begin = new Point(Position.X, Position.Y);
}
public void Reset()
{
_locked = false;
}
public EGesture GetGesture(Point NewPosition)
{
if (!_locked)
return EGesture.None;
int dx = NewPosition.X - _Begin.X;
int dy = NewPosition.Y - _Begin.Y;
//Back/Escape
if (dx < -150 && Math.Abs(dy) < 150)
{
_locked = false;
return EGesture.Back;
}
//ScrollDown
if (Math.Abs(dx) < 150 && dy > 30)
{
_Begin.Y = NewPosition.Y;
_Begin.X = NewPosition.X;
return EGesture.ScrollDown;
}
//ScrollUp
if (Math.Abs(dx) < 150 && dy < -30)
{
_Begin.Y = NewPosition.Y;
_Begin.X = NewPosition.X;
return EGesture.ScrollUp;
}
return EGesture.None;
}
}
}
+327
View File
@@ -0,0 +1,327 @@
using System;
using System.Collections.Generic;
using System.Drawing;
using System.IO;
using System.Windows.Forms;
using System.Text;
using System.Threading;
using Vocaluxe.Base;
namespace Vocaluxe.Lib.Input.WiiMote
{
class CWiiMote : IInput
{
WiiMoteLib _WiiMote;
private List<KeyEvent> _KeysPool;
private List<KeyEvent> _CurrentKeysPool;
private Object _KeyCopyLock = new Object();
private List<MouseEvent> _MousePool;
private List<MouseEvent> _CurrentMousePool;
private Object _MouseCopyLock = new Object();
private bool[] _ButtonStates;
private Point _OldPosition;
private bool _Connected;
private Thread _HandlerThread;
private Object _Sync;
private bool _Active;
private RumbleTimer _RumbleTimer;
private CGesture _Gesture;
public bool Init()
{
_Sync = new Object();
_RumbleTimer = new RumbleTimer();
_Gesture = new CGesture();
_Active = true;
_HandlerThread = new Thread(MainLoop);
_HandlerThread.Priority = ThreadPriority.BelowNormal;
_KeysPool = new List<KeyEvent>();
_CurrentKeysPool = new List<KeyEvent>();
_MousePool = new List<MouseEvent>();
_CurrentMousePool = new List<MouseEvent>();
_ButtonStates = new bool[11];
_OldPosition = new Point();
_HandlerThread.Start();
return true;
}
public void Close()
{
_Active = false;
}
public bool Connect()
{
if (!_Active)
{
_Active = true;
_HandlerThread.Start();
}
return true;
}
public bool Disconnect()
{
_Active = false;
return true;
}
public bool IsConnected()
{
return _Connected;
}
public void Update()
{
CopyEvents();
}
public bool PollKeyEvent(ref KeyEvent KeyEvent)
{
if (_CurrentKeysPool.Count > 0)
{
KeyEvent = _CurrentKeysPool[0];
_CurrentKeysPool.RemoveAt(0);
return true;
}
else return false;
}
public bool PollMouseEvent(ref MouseEvent MouseEvent)
{
if (_CurrentMousePool.Count > 0)
{
MouseEvent = _CurrentMousePool[0];
_CurrentMousePool.RemoveAt(0);
return true;
}
else return false;
}
public void SetRumble(float Duration)
{
lock (_Sync)
{
_RumbleTimer.Set(Duration);
}
}
private void MainLoop()
{
_WiiMote = new WiiMoteLib();
_WiiMote.WiiMoteChanged += wm_WiiMoteChanged;
while (_Active)
{
Thread.Sleep(5);
if (!_WiiMote.Connected)
{
if (!DoConnect())
Thread.Sleep(1000);
}
else
{
bool StartRumble = false;
bool StopRumble = false;
lock (_Sync)
{
StartRumble = _RumbleTimer.ShouldStart;
StopRumble = _RumbleTimer.ShouldStop;
}
if (StartRumble)
_WiiMote.SetRumble(true);
if (StopRumble)
_WiiMote.SetRumble(false);
}
}
_WiiMote.SetRumble(false);
_WiiMote.Disconnect();
_Connected = false;
}
private bool DoConnect()
{
try
{
if (!_WiiMote.Connect())
return false;
}
catch
{
return false; ;
}
_WiiMote.SetReportType(InputReport.IRAccel, IRSensitivity.Max, false);
_WiiMote.SetLEDs(false, false, true, false);
_WiiMote.SetRumble(true);
Thread.Sleep(250);
_WiiMote.SetRumble(false);
Thread.Sleep(250);
_WiiMote.SetRumble(true);
Thread.Sleep(250);
_WiiMote.SetRumble(false);
_Connected = true;
return true;
}
private void wm_WiiMoteChanged(object sender, WiiMoteChangedEventArgs args)
{
if (!_Active)
return;
WiiMoteStatus ws = args.WiiMoteState;
Point p = ws.IRState.Position;
p.X = 1023 - p.X;
//key events
bool alt = false;
bool shift = false;
bool ctrl = false;
bool pressed = false;
char unicode = char.MinValue;
EGesture gesture = _Gesture.GetGesture(p);
bool lb = false;
bool rb = gesture == EGesture.Back;
Keys key = Keys.None;
if (ws.ButtonState.A && !_ButtonStates[0])
lb = true;
else if (ws.ButtonState.B && !_ButtonStates[1])
_Gesture.SetLockPosition(p);
else if (!ws.ButtonState.B && _ButtonStates[1])
_Gesture.Reset();
else if (ws.ButtonState.Down && !_ButtonStates[2])
key = Keys.Right;
else if (ws.ButtonState.Up && !_ButtonStates[3])
key = Keys.Left;
else if (ws.ButtonState.Left && !_ButtonStates[4])
key = Keys.Down;
else if (ws.ButtonState.Right && !_ButtonStates[5])
key = Keys.Up;
else if (ws.ButtonState.Home && !_ButtonStates[6])
key = Keys.Space;
else if (ws.ButtonState.Minus && !_ButtonStates[7])
key = Keys.PageDown;
else if (ws.ButtonState.Plus && !_ButtonStates[8])
key = Keys.PageUp;
else if (ws.ButtonState.One && !_ButtonStates[9])
key = Keys.Enter;
else if (ws.ButtonState.Two && !_ButtonStates[10])
key = Keys.Escape;
_ButtonStates[0] = ws.ButtonState.A;
_ButtonStates[1] = ws.ButtonState.B;
_ButtonStates[2] = ws.ButtonState.Down;
_ButtonStates[3] = ws.ButtonState.Up;
_ButtonStates[4] = ws.ButtonState.Left;
_ButtonStates[5] = ws.ButtonState.Right;
_ButtonStates[6] = ws.ButtonState.Home;
_ButtonStates[7] = ws.ButtonState.Minus;
_ButtonStates[8] = ws.ButtonState.Plus;
_ButtonStates[9] = ws.ButtonState.One;
_ButtonStates[10] = ws.ButtonState.Two;
if (alt || shift || ctrl || pressed || unicode != char.MinValue || key != Keys.None)
{
KeyEvent pool = new KeyEvent(ESender.WiiMote, alt, shift, ctrl, pressed, unicode, key);
lock (_KeyCopyLock)
{
_KeysPool.Add(pool);
}
}
//mouse events
float reducing = 0.15f;
float factor = 1f / (1f - reducing * 2f);
float rx = (((float)p.X / 1024f) - reducing) * factor;
float ry = (((float)p.Y / 768f) - reducing) * factor;
int x = (int)(rx * (float)CSettings.iRenderW);
int y = (int)(ry * (float)CSettings.iRenderH);
bool ld = false;
bool lbh = !lb && ws.ButtonState.A;
bool rbh = false;
bool mb = false;
bool mbh = false;
int wheel = 0;
if (gesture == EGesture.ScrollUp)
wheel = -1;
if (gesture == EGesture.ScrollDown)
wheel = 1;
MouseEvent mpool = new MouseEvent();
bool trigger = false;
if (!lb && !rb && (p.X != _OldPosition.X || p.Y != _OldPosition.Y))
{
mpool = new MouseEvent(ESender.WiiMote, alt, shift, ctrl, x, y, false, false, false, wheel, lbh, rbh, false, mbh);
trigger = true;
}
else if (lb || rb)
{
mpool = new MouseEvent(ESender.WiiMote, alt, shift, ctrl, x, y, lb, ld, rb, wheel, false, false, mb, false);
trigger = true;
}
if (trigger)
{
lock (_MouseCopyLock)
{
_MousePool.Add(mpool);
}
}
_OldPosition.X = p.X;
_OldPosition.Y = p.Y;
}
private void CopyEvents()
{
lock (_KeyCopyLock)
{
foreach (KeyEvent e in _KeysPool)
{
_CurrentKeysPool.Add(e);
}
_KeysPool.Clear();
}
lock (_MouseCopyLock)
{
foreach (MouseEvent e in _MousePool)
{
_CurrentMousePool.Add(e);
}
_MousePool.Clear();
}
}
}
}
+669
View File
@@ -0,0 +1,669 @@
using System;
using System.Diagnostics;
using System.Drawing;
using System.IO;
using System.Runtime.InteropServices;
using System.Runtime.Serialization;
using System.Threading;
using Vocaluxe.Base;
using Vocaluxe.Lib.Draw;
using Vocaluxe.Lib.Input;
namespace Vocaluxe.Lib.Input.WiiMote
{
#region DataTypes
public class WiiMoteStatus
{
public AccelCalibrationInfo AccelCalibrationInfo = new AccelCalibrationInfo();
public AccelStatus AccelState = new AccelStatus();
public Buttons ButtonState = new Buttons();
public IRState IRState = new IRState();
public byte Battery;
public bool Rumble;
public LEDStatus LEDState;
public WiiMoteStatus()
{
IRState.Sensors = new IR[4];
}
}
public struct LEDStatus
{
public bool LED1;
public bool LED2;
public bool LED3;
public bool LED4;
}
public enum IRMode : byte
{
Off = 0x00,
Basic = 0x01, // 10 bytes
Extended = 0x03 // 12 bytes
};
public struct IR
{
public bool Active;
public Point Position; // X: 0-1023; Y: 0-767
public int Width; // 0-15
}
public struct IRState
{
public IRMode Mode;
public IR[] Sensors;
public Point Position; //0..1023, 0..767
public Point Distance; //between Point 0 and Point 1
}
public struct AccelStatus
{
public SPoint3 RawValues; //0-255
public SPoint3f Values; //0-3
}
public struct AccelCalibrationInfo
{
public byte X0, Y0, Z0; //zero point
public byte XG, YG, ZG; //gravity
}
public struct Buttons
{
public bool Up, Down, Left, Right, A, B, Plus, Minus, One, Two, Home;
}
public enum InputReport : byte
{
Status = 0x20,
ReadData = 0x21,
Ack = 0x22,
Buttons = 0x30,
ButtonsAccel = 0x31,
Buttons8Bytes = 0x32,
IRAccel = 0x33,
ButtonsExtension = 0x34,
ExtensionAccel = 0x35,
IRExtensionAccel = 0x37,
};
public enum IRSensitivity
{
Level1,
Level2,
Level3,
Level4,
Level5,
Max
}
#endregion DataTypes
#region Events
public class WiiMoteChangedEventArgs: EventArgs
{
public WiiMoteStatus WiiMoteState;
public WiiMoteChangedEventArgs(WiiMoteStatus ws)
{
WiiMoteState = ws;
}
}
#endregion Events
public class WiiMoteLib : IDisposable
{
private const ushort VID = 0x057e;
private const ushort PID = 0x0306; //Wiimotion
private const ushort PIDPlus = 0x0330; //Wiimotion Plus
// registers
private const int REGISTER_IR = 0x04b00030;
private const int REGISTER_IR_SENSITIVITY_1 = 0x04b00000;
private const int REGISTER_IR_SENSITIVITY_2 = 0x04b0001a;
private const int REGISTER_IR_MODE = 0x04b00033;
private const int REPORT_LENGTH = 22;
// output commands
private enum OutputReport : byte
{
LEDs = 0x11,
Type = 0x12,
IR = 0x13,
Status = 0x15,
WriteMemory = 0x16,
ReadMemory = 0x17,
SpeakerData = 0x18,
SpeakerMute = 0x19,
IR2 = 0x1a,
};
// data handling
private IntPtr _Handle;
private readonly byte[] _Buff = new byte[REPORT_LENGTH];
private byte[] _ReadBuff;
private int _Address;
private short _Size;
private Thread _Reader;
private bool _Active;
private bool _Connected;
public bool Connected
{
get
{
return _Connected;
}
}
private readonly WiiMoteStatus _WiiMoteState = new WiiMoteStatus();
private readonly AutoResetEvent _ReadDone = new AutoResetEvent(false);
public event EventHandler<WiiMoteChangedEventArgs> WiiMoteChanged;
#region Interface
public WiiMoteLib()
{
_Connected = false;
_Active = true;
_Reader = new Thread(ReaderLoop);
_Reader.Start();
}
public bool Connect()
{
_Connected = false;
CHIDAPI.Exit();
if (!CHIDAPI.Init())
{
CLog.LogError("WiiMoteLib: Can't initialize HID API");
return false;
}
//Try WiiMotion
if (_Connected = CHIDAPI.Open(VID, PID, out _Handle))
{
if (!(_Connected = ReadCalibration()))
CHIDAPI.Close(_Handle);
}
if (_Connected)
return true;
//Try WiiMotion Plus
if (_Connected = CHIDAPI.Open(VID, PIDPlus, out _Handle))
{
if (!(_Connected = ReadCalibration()))
CHIDAPI.Close(_Handle);
}
return _Connected;
}
public void Disconnect()
{
_Connected = false;
_Active = false;
CHIDAPI.Exit();
}
public void SetReportType(InputReport type, IRSensitivity irSensitivity, bool continuous)
{
if (!_Connected)
return;
switch (type)
{
case InputReport.IRAccel:
EnableIR(IRMode.Extended, irSensitivity);
break;
default:
DisableIR();
break;
}
ClearReport();
_Buff[0] = (byte)OutputReport.Type;
_Buff[1] = (byte)((continuous ? 0x04 : 0x00) | (byte)(_WiiMoteState.Rumble ? 0x01 : 0x00));
_Buff[2] = (byte)type;
CHIDAPI.Write(_Handle, _Buff);
}
public void SetLEDs(bool led1, bool led2, bool led3, bool led4)
{
_WiiMoteState.LEDState.LED1 = led1;
_WiiMoteState.LEDState.LED2 = led2;
_WiiMoteState.LEDState.LED3 = led3;
_WiiMoteState.LEDState.LED4 = led4;
if (!_Connected)
return;
ClearReport();
_Buff[0] = (byte)OutputReport.LEDs;
_Buff[1] = (byte)(
(led1 ? 0x10 : 0x00) |
(led2 ? 0x20 : 0x00) |
(led3 ? 0x40 : 0x00) |
(led4 ? 0x80 : 0x00) |
RumbleBit);
CHIDAPI.Write(_Handle, _Buff);
}
public void SetRumble(bool on)
{
_WiiMoteState.Rumble = on;
// the LED report also handles rumble
SetLEDs(_WiiMoteState.LEDState.LED1,
_WiiMoteState.LEDState.LED2,
_WiiMoteState.LEDState.LED3,
_WiiMoteState.LEDState.LED4);
}
public WiiMoteStatus WiiMoteState
{
get { return _WiiMoteState; }
}
#endregion Interface
#region Private stuff
private void ReaderLoop()
{
while (_Active)
{
Thread.Sleep(5);
if (_Handle != IntPtr.Zero && _Connected)
{
byte[] buff = new byte[REPORT_LENGTH];
try
{
CHIDAPI.ReadTimeout(_Handle, out buff, REPORT_LENGTH, 100);
}
catch (Exception e)
{
CLog.LogError("(WiiMoteLib) Error reading from device: " + e.ToString());
}
if (ParseInputReport(buff))
{
if (WiiMoteChanged != null)
WiiMoteChanged(this, new WiiMoteChangedEventArgs(_WiiMoteState));
}
}
}
}
private bool ParseInputReport(byte[] buff)
{
if (buff == null)
{
_Connected = false;
return false;
}
InputReport type = (InputReport)buff[0];
switch(type)
{
case InputReport.Buttons:
ParseButtons(buff);
break;
case InputReport.ButtonsAccel:
ParseButtons(buff);
ParseAccel(buff);
break;
case InputReport.IRAccel:
ParseButtons(buff);
ParseAccel(buff);
ParseIR(buff);
break;
case InputReport.ButtonsExtension:
ParseButtons(buff);
break;
case InputReport.ExtensionAccel:
ParseButtons(buff);
ParseAccel(buff);
break;
case InputReport.IRExtensionAccel:
ParseButtons(buff);
ParseAccel(buff);
ParseIR(buff);
break;
case InputReport.Status:
ParseButtons(buff);
_WiiMoteState.Battery = buff[6];
_WiiMoteState.LEDState.LED1 = (buff[3] & 0x10) != 0;
_WiiMoteState.LEDState.LED2 = (buff[3] & 0x20) != 0;
_WiiMoteState.LEDState.LED3 = (buff[3] & 0x40) != 0;
_WiiMoteState.LEDState.LED4 = (buff[3] & 0x80) != 0;
break;
case InputReport.ReadData:
ParseButtons(buff);
ParseReadData(buff);
break;
case InputReport.Ack:
return false;
case InputReport.Buttons8Bytes:
break;
default:
CLog.LogError("(WiiMoteLib) Unknown report type: " + type.ToString("x"));
return false;
}
return true;
}
private byte[] DecryptBuffer(byte[] buff)
{
for(int i = 0; i < buff.Length; i++)
buff[i] = (byte)(((buff[i] ^ 0x17) + 0x17) & 0xff);
return buff;
}
private void ParseButtons(byte[] buff)
{
_WiiMoteState.ButtonState.A = (buff[2] & 0x08) != 0;
_WiiMoteState.ButtonState.B = (buff[2] & 0x04) != 0;
_WiiMoteState.ButtonState.Minus = (buff[2] & 0x10) != 0;
_WiiMoteState.ButtonState.Home = (buff[2] & 0x80) != 0;
_WiiMoteState.ButtonState.Plus = (buff[1] & 0x10) != 0;
_WiiMoteState.ButtonState.One = (buff[2] & 0x02) != 0;
_WiiMoteState.ButtonState.Two = (buff[2] & 0x01) != 0;
_WiiMoteState.ButtonState.Up = (buff[1] & 0x08) != 0;
_WiiMoteState.ButtonState.Down = (buff[1] & 0x04) != 0;
_WiiMoteState.ButtonState.Left = (buff[1] & 0x01) != 0;
_WiiMoteState.ButtonState.Right = (buff[1] & 0x02) != 0;
}
private void ParseAccel(byte[] buff)
{
_WiiMoteState.AccelState.RawValues.X = buff[3];
_WiiMoteState.AccelState.RawValues.Y = buff[4];
_WiiMoteState.AccelState.RawValues.Z = buff[5];
_WiiMoteState.AccelState.Values.X = (float)((float)_WiiMoteState.AccelState.RawValues.X - _WiiMoteState.AccelCalibrationInfo.X0) /
((float)_WiiMoteState.AccelCalibrationInfo.XG - _WiiMoteState.AccelCalibrationInfo.X0);
_WiiMoteState.AccelState.Values.Y = (float)((float)_WiiMoteState.AccelState.RawValues.Y - _WiiMoteState.AccelCalibrationInfo.Y0) /
((float)_WiiMoteState.AccelCalibrationInfo.YG - _WiiMoteState.AccelCalibrationInfo.Y0);
_WiiMoteState.AccelState.Values.Z = (float)((float)_WiiMoteState.AccelState.RawValues.Z - _WiiMoteState.AccelCalibrationInfo.Z0) /
((float)_WiiMoteState.AccelCalibrationInfo.ZG - _WiiMoteState.AccelCalibrationInfo.Z0);
}
private void ParseIR(byte[] buff)
{
switch(_WiiMoteState.IRState.Mode)
{
case IRMode.Basic:
if (_WiiMoteState.IRState.Sensors[0].Active = !(buff[6] == 0xff && buff[7] == 0xff))
{
_WiiMoteState.IRState.Sensors[0].Position.X = buff[6] | ((buff[8] >> 4) & 0x03) << 8;
_WiiMoteState.IRState.Sensors[0].Position.Y = buff[7] | ((buff[8] >> 6) & 0x03) << 8;
_WiiMoteState.IRState.Sensors[0].Width = 0;
}
if (_WiiMoteState.IRState.Sensors[1].Active = !(buff[9] == 0xff && buff[10] == 0xff))
{
_WiiMoteState.IRState.Sensors[1].Position.X = buff[9] | ((buff[8] >> 0) & 0x03) << 8;
_WiiMoteState.IRState.Sensors[1].Position.Y = buff[10] | ((buff[8] >> 2) & 0x03) << 8;
_WiiMoteState.IRState.Sensors[1].Width = 0;
}
break;
case IRMode.Extended:
for (int i = 0; i < 4; i++)
{
if (_WiiMoteState.IRState.Sensors[i].Active = !(buff[6 + i * 3] == 0xff && buff[7 + i * 3] == 0xff && buff[8 + i * 3] == 0xff))
{
_WiiMoteState.IRState.Sensors[i].Position.X = buff[6 + i * 3] | ((buff[8 + i * 3] >> 4) & 0x03) << 8;
_WiiMoteState.IRState.Sensors[i].Position.Y = buff[7 + i * 3] | ((buff[8 + i * 3] >> 6) & 0x03) << 8;
_WiiMoteState.IRState.Sensors[i].Width = buff[8 + i * 3] & 0x0f;
}
}
break;
}
if (_WiiMoteState.IRState.Sensors[0].Active && _WiiMoteState.IRState.Sensors[1].Active)
{
_WiiMoteState.IRState.Position.X = (_WiiMoteState.IRState.Sensors[1].Position.X + _WiiMoteState.IRState.Sensors[0].Position.X) / 2;
_WiiMoteState.IRState.Position.Y = (_WiiMoteState.IRState.Sensors[1].Position.Y + _WiiMoteState.IRState.Sensors[0].Position.Y) / 2;
_WiiMoteState.IRState.Distance.X = Math.Abs(_WiiMoteState.IRState.Sensors[1].Position.X - _WiiMoteState.IRState.Sensors[0].Position.X);
_WiiMoteState.IRState.Distance.Y = Math.Abs(_WiiMoteState.IRState.Sensors[1].Position.Y - _WiiMoteState.IRState.Sensors[0].Position.Y);
}
else if (_WiiMoteState.IRState.Sensors[0].Active)
{
if (_WiiMoteState.IRState.Sensors[0].Position.X > 512)
_WiiMoteState.IRState.Position.X = _WiiMoteState.IRState.Sensors[0].Position.X - _WiiMoteState.IRState.Distance.X / 2;
else
_WiiMoteState.IRState.Position.X = _WiiMoteState.IRState.Sensors[0].Position.X + _WiiMoteState.IRState.Distance.X / 2;
if (_WiiMoteState.IRState.Sensors[0].Position.X < 384)
_WiiMoteState.IRState.Position.Y = _WiiMoteState.IRState.Sensors[0].Position.Y - _WiiMoteState.IRState.Distance.Y / 2;
else
_WiiMoteState.IRState.Position.Y = _WiiMoteState.IRState.Sensors[0].Position.Y + _WiiMoteState.IRState.Distance.Y / 2;
}
}
private void ParseReadData(byte[] buff)
{
if ((buff[3] & 0x08) != 0)
{
CLog.LogError("Error reading data from WiiMote: Bytes do not exist");
_Connected = false;
}
if ((buff[3] & 0x07) != 0)
{
CLog.LogError("Error reading data from WiiMote: Attempt to read from write-only registers.");
_Connected = false;
}
int size = (buff[3] >> 4) + 1;
int offset = (buff[4] << 8 | buff[5]);
Array.Copy(buff, 6, _ReadBuff, offset - _Address, size);
if(_Address + _Size == offset + size)
_ReadDone.Set();
}
private byte RumbleBit
{
get
{
if (_WiiMoteState.Rumble)
return (byte)0x1;
return (byte)0x0;
}
}
private bool ReadCalibration()
{
// this appears to change the report type to 0x31
byte[] buff = ReadData(0x0016, 7);
if (buff == null)
return false;
_WiiMoteState.AccelCalibrationInfo.X0 = buff[0];
_WiiMoteState.AccelCalibrationInfo.Y0 = buff[1];
_WiiMoteState.AccelCalibrationInfo.Z0 = buff[2];
_WiiMoteState.AccelCalibrationInfo.XG = buff[4];
_WiiMoteState.AccelCalibrationInfo.YG = buff[5];
_WiiMoteState.AccelCalibrationInfo.ZG = buff[6];
return true;
}
private void EnableIR(IRMode mode, IRSensitivity Sensitivity)
{
_WiiMoteState.IRState.Mode = mode;
ClearReport();
_Buff[0] = (byte)OutputReport.IR;
_Buff[1] = (byte)(0x04 | RumbleBit);
CHIDAPI.Write(_Handle, _Buff);
Thread.Sleep(50);
ClearReport();
_Buff[0] = (byte)OutputReport.IR2;
_Buff[1] = (byte)(0x04 | RumbleBit);
CHIDAPI.Write(_Handle, _Buff);
Thread.Sleep(50);
WriteData(REGISTER_IR, 0x08);
Thread.Sleep(50);
switch(Sensitivity)
{
case IRSensitivity.Level1:
WriteData(REGISTER_IR_SENSITIVITY_1, 9, new byte[] {0x02, 0x00, 0x00, 0x71, 0x01, 0x00, 0x64, 0x00, 0xfe});
Thread.Sleep(50);
WriteData(REGISTER_IR_SENSITIVITY_2, 2, new byte[] {0xfd, 0x05});
break;
case IRSensitivity.Level2:
WriteData(REGISTER_IR_SENSITIVITY_1, 9, new byte[] {0x02, 0x00, 0x00, 0x71, 0x01, 0x00, 0x96, 0x00, 0xb4});
Thread.Sleep(50);
WriteData(REGISTER_IR_SENSITIVITY_2, 2, new byte[] {0xb3, 0x04});
break;
case IRSensitivity.Level3:
WriteData(REGISTER_IR_SENSITIVITY_1, 9, new byte[] {0x02, 0x00, 0x00, 0x71, 0x01, 0x00, 0xaa, 0x00, 0x64});
Thread.Sleep(50);
WriteData(REGISTER_IR_SENSITIVITY_2, 2, new byte[] {0x63, 0x03});
break;
case IRSensitivity.Level4:
WriteData(REGISTER_IR_SENSITIVITY_1, 9, new byte[] {0x02, 0x00, 0x00, 0x71, 0x01, 0x00, 0xc8, 0x00, 0x36});
Thread.Sleep(50);
WriteData(REGISTER_IR_SENSITIVITY_2, 2, new byte[] {0x35, 0x03});
break;
case IRSensitivity.Level5:
WriteData(REGISTER_IR_SENSITIVITY_1, 9, new byte[] {0x07, 0x00, 0x00, 0x71, 0x01, 0x00, 0x72, 0x00, 0x20});
Thread.Sleep(50);
WriteData(REGISTER_IR_SENSITIVITY_2, 2, new byte[] {0x1, 0x03});
break;
case IRSensitivity.Max:
WriteData(REGISTER_IR_SENSITIVITY_1, 9, new byte[] {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x90, 0x00, 0x41});
Thread.Sleep(50);
WriteData(REGISTER_IR_SENSITIVITY_2, 2, new byte[] {0x40, 0x00});
break;
}
Thread.Sleep(50);
WriteData(REGISTER_IR_MODE, (byte)mode);
Thread.Sleep(50);
WriteData(REGISTER_IR, 0x08);
Thread.Sleep(50);
}
private void DisableIR()
{
_WiiMoteState.IRState.Mode = IRMode.Off;
ClearReport();
_Buff[0] = (byte)OutputReport.IR;
_Buff[1] = RumbleBit;
CHIDAPI.Write(_Handle, _Buff);
ClearReport();
_Buff[0] = (byte)OutputReport.IR2;
_Buff[1] = RumbleBit;
CHIDAPI.Write(_Handle, _Buff);
}
private void ClearReport()
{
Array.Clear(_Buff, 0, REPORT_LENGTH);
}
private byte[] ReadData(int address, short size)
{
ClearReport();
_ReadBuff = new byte[size];
_Address = address & 0xffff;
_Size = size;
_Buff[0] = (byte)OutputReport.ReadMemory;
_Buff[1] = (byte)(((address & 0xff000000) >> 24) | RumbleBit);
_Buff[2] = (byte)((address & 0x00ff0000) >> 16);
_Buff[3] = (byte)((address & 0x0000ff00) >> 8);
_Buff[4] = (byte)(address & 0x000000ff);
_Buff[5] = (byte)((size & 0xff00) >> 8);
_Buff[6] = (byte)(size & 0xff);
CHIDAPI.Write(_Handle, _Buff);
if (!_ReadDone.WaitOne(1000, false))
{
_Connected = false;
return null;
}
return _ReadBuff;
}
private void WriteData(int address, byte data)
{
WriteData(address, 1, new byte[] { data });
}
private void WriteData(int address, byte size, byte[] buff)
{
ClearReport();
_Buff[0] = (byte)OutputReport.WriteMemory;
_Buff[1] = (byte)(((address & 0xff000000) >> 24) | RumbleBit);
_Buff[2] = (byte)((address & 0x00ff0000) >> 16);
_Buff[3] = (byte)((address & 0x0000ff00) >> 8);
_Buff[4] = (byte)(address & 0x000000ff);
_Buff[5] = size;
Array.Copy(buff, 0, _Buff, 6, size);
CHIDAPI.Write(_Handle, _Buff);
Thread.Sleep(100);
}
#endregion Private stuff
#region IDisposable Members
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
if(disposing)
Disconnect();
}
#endregion
}
}