using System;
using System.Collections.Generic;
using System.Drawing;
using System.Text;
using Xbox360USB;
namespace uDrawLib
{
public class Xbox360InputDevice : IInputDevice
{
#region Declarations
private const int _MULTITOUCH_SENSITIVITY = 30;
private WirelessReceiver _receiver;
private int _index;
public WirelessReceiver.DeviceInformation Info { get; set; }
public byte LeftTrigger { get; set; }
public byte RightTrigger { get; set; }
public short X1 { get; set; }
public short Y1 { get; set; }
public short X2 { get; set; }
public short Y2 { get; set; }
//Chatpad statuses
public bool PeopleLit { get; set; }
public bool ShiftLit { get; set; }
public bool OrangeLit { get; set; }
public bool GreenLit { get; set; }
public bool BacklightLit { get; set; }
public bool PeopleHeld { get; set; }
public bool ShiftHeld { get; set; }
public bool OrangeHeld { get; set; }
public bool GreenHeld { get; set; }
private enum RawPressureType
{
NotPressed = 0x00,
PenPressed = 0x40,
FingerPressed = 0x80
};
///
/// Indicates the pressed state of every non-directional button on the tablet.
///
public TabletButtonState ButtonState { get; set; }
///
/// Indicates the pressed state of each direction on the directional pad.
///
public TabletDPadState DPadState { get; set; }
///
/// Indicates whether the nib/stylus, fingers, or nothing are currently pressing on the tablet.
///
public TabletPressureType PressureType { get; set; }
///
/// The raw pressure being applied by the pen. Only valid with TabletPressureType.PenPressed.
///
public ushort PenPressure { get; set; }
///
/// Indicates the distance between fingers. Only valid with TabletPressureType.Multitouch.
///
public ushort MultitouchDistance { get; set; }
///
/// Indicates the absolute coordinates (from top-left corner) of the current pressure point.
/// Only valid with TabletPressureType.PenPressed and TabletPressureType.FingerPressed.
///
public Point PressurePoint { get; set; }
///
/// Raw X-, Y-, and Z-axis data from the accelerometer.
///
public TabletAccelerometerData AccelerometerData { get; set; }
private int _multitouchTimer;
private ushort _previousMultitouchDistance;
#endregion
#region Constructors / Teardown
public Xbox360InputDevice(WirelessReceiver receiver, int index, WirelessReceiver.DeviceInformation info)
{
ButtonState = new TabletButtonState();
DPadState = new TabletDPadState();
AccelerometerData = new TabletAccelerometerData();
_index = index;
_receiver = receiver;
Info = info;
_receiver.EventDataReceived += _receiver_EventDataReceived;
}
#endregion
#region Public Events
public event EventHandler ButtonStateChanged;
public event EventHandler DPadStateChanged;
public event EventHandler ChatpadKeyStateChanged;
public event EventHandler ShiftPressed;
public event EventHandler PeoplePressed;
#endregion
#region Public Properties
///
/// Indicates whether pressure is being applied to the tablet.
///
public bool IsPressed
{
get
{
bool ret = false;
if (PressureType != TabletPressureType.NotPressed)
ret = true;
return ret;
}
}
///
/// Indicates whether the user is currently zooming out by multitouch.
///
public bool IsZooming
{
get
{
bool ret = false;
if (MultitouchDistance > _previousMultitouchDistance)
ret = true;
return ret;
}
}
///
/// Indicates whether the user is currently pinching by multitouch.
///
public bool IsPinching
{
get
{
bool ret = false;
if (MultitouchDistance < _previousMultitouchDistance)
ret = true;
return ret;
}
}
#endregion
#region Event Handlers
private void _HandleKeyDownData(int index, byte key)
{
if (key > 0)
{
if (!_chatpadKeysHeld.Contains(key))
{
_chatpadKeysHeld.Add(key);
//Let others know this key is now being held down
if (ChatpadKeyStateChanged != null)
ChatpadKeyStateChanged(this, new ChatpadKeyStateEventArgs(index, key, true));
}
}
}
private byte[] _oldChatpadData = new byte[29];
private List _chatpadKeysHeld = new List();
private void _receiver_EventDataReceived(object sender, Xbox360USB.DataReceivedEventArgs e)
{
if (Info.Subtype == WirelessReceiver.DeviceSubtype.Controller)
{
if (e.Data[0] == 0x00 && e.Data[2] == 0x00 && e.Data[3] == 0xF0)
{
if (e.Data[1] == 0x01)
{
//Parse raw data for buttons
//Console.WriteLine("Controller data: " + BitConverter.ToString(e.Data));
bool changed = false;
bool raw = (e.Data[7] & 0x40) > 0;
changed |= ButtonState.SquareHeld != raw; ButtonState.SquareHeld = raw;
raw = (e.Data[7] & 0x10) > 0;
changed |= ButtonState.CrossHeld != raw; ButtonState.CrossHeld = raw;
raw = (e.Data[7] & 0x20) > 0;
changed |= ButtonState.CircleHeld != raw; ButtonState.CircleHeld = raw;
raw = (e.Data[7] & 0x80) > 0;
changed |= ButtonState.TriangleHeld != raw; ButtonState.TriangleHeld = raw;
raw = (e.Data[6] & 0x20) > 0;
changed |= ButtonState.SelectHeld != raw; ButtonState.SelectHeld = raw;
raw = (e.Data[6] & 0x10) > 0;
changed |= ButtonState.StartHeld != raw; ButtonState.StartHeld = raw;
raw = (e.Data[7] & 0x04) > 0;
changed |= ButtonState.PSHeld != raw; ButtonState.PSHeld = raw;
raw = (e.Data[6] & 0x40) > 0;
changed |= ButtonState.LeftStickHeld != raw; ButtonState.LeftStickHeld = raw;
raw = (e.Data[6] & 0x80) > 0;
changed |= ButtonState.RightStickHeld != raw; ButtonState.RightStickHeld = raw;
raw = (e.Data[7] & 0x01) > 0;
changed |= ButtonState.LeftButtonHeld != raw; ButtonState.LeftButtonHeld = raw;
raw = (e.Data[7] & 0x02) > 0;
changed |= ButtonState.RightButtonHeld != raw; ButtonState.RightButtonHeld = raw;
if (changed && ButtonStateChanged != null)
ButtonStateChanged(this, EventArgs.Empty);
//Now parse raw data for D-pad changes
changed = false;
raw = (e.Data[6] == 0x1) || (e.Data[6] == 0x5) || (e.Data[6] == 0x9);
changed |= DPadState.UpHeld != raw; DPadState.UpHeld = raw;
raw = (e.Data[6] == 0x2) || (e.Data[6] == 0x6) || (e.Data[6] == 0xA);
changed |= DPadState.DownHeld != raw; DPadState.DownHeld = raw;
raw = (e.Data[6] == 0x4) || (e.Data[6] == 0x6) || (e.Data[6] == 0x5);
changed |= DPadState.LeftHeld != raw; DPadState.LeftHeld = raw;
raw = (e.Data[6] == 0x8) || (e.Data[6] == 0x9) || (e.Data[6] == 0xA);
changed |= DPadState.RightHeld != raw; DPadState.RightHeld = raw;
if (changed && DPadStateChanged != null)
DPadStateChanged(this, EventArgs.Empty);
LeftTrigger = e.Data[8];
RightTrigger = e.Data[9];
X1 = (short)(e.Data[10] | (e.Data[11] << 8));
Y1 = (short)(e.Data[12] | (e.Data[13] << 8));
X2 = (short)(e.Data[14] | (e.Data[15] << 8));
Y2 = (short)(e.Data[16] | (e.Data[17] << 8));
}
else if (e.Data[1] == 0x02)
{
if (e.Data[24] == 0xF0 && e.Data[25] == 0x04)
{
//LED statuses
this.PeopleLit = (e.Data[26] & 0x01) > 0;
this.GreenLit = (e.Data[26] & 0x08) > 0;
this.OrangeLit = (e.Data[26] & 0x10) > 0;
this.ShiftLit = (e.Data[26] & 0x20) > 0;
this.BacklightLit = (e.Data[26] & 0x80) > 0;
}
else if (e.Data[24] == 0x00)
{
//See if anything at all has changed
bool changed = false;
if (_oldChatpadData != null && _oldChatpadData.Length == e.Data.Length)
{
for (int i = 0; i < e.Data.Length; i++)
{
if (_oldChatpadData[i] != e.Data[i])
{
changed = true;
break;
}
}
}
else
changed = true;
if (changed)
{
//Get modifier statuses
this.GreenHeld = (e.Data[25] & 0x02) > 0;
this.OrangeHeld = (e.Data[25] & 0x04) > 0;
bool raw = (e.Data[25] & 0x01) > 0;
changed = this.ShiftHeld != raw;
this.ShiftHeld = raw;
if (changed && this.ShiftHeld && ShiftPressed != null)
ShiftPressed(this, new Xbox360DeviceEventArgs(e.Index));
raw = (e.Data[25] & 0x08) > 0;
changed = this.PeopleHeld != raw;
this.PeopleHeld = raw;
if (changed && this.PeopleHeld && PeoplePressed != null)
PeoplePressed(this, new Xbox360DeviceEventArgs(e.Index));
//Raise scan code events
var key1 = e.Data[26];
var key2 = e.Data[27];
_HandleKeyDownData(e.Index, key1);
_HandleKeyDownData(e.Index, key2);
var keysToRemove = new List();
foreach (var key in _chatpadKeysHeld)
if (key != key1 && key != key2)
keysToRemove.Add(key);
foreach (var key in keysToRemove)
{
_chatpadKeysHeld.Remove(key);
//Let others know this key is no longer being held down
if (ChatpadKeyStateChanged != null)
ChatpadKeyStateChanged(this, new ChatpadKeyStateEventArgs(e.Index, key, false));
}
}
_oldChatpadData = e.Data;
}
}
}
}
else if (Info.Subtype == WirelessReceiver.DeviceSubtype.uDrawTablet)
{
const int MULTITOUCH_DISTANCE_OFFSET = 15;
const int PEN_PRESSURE_OFFSET = 8;
const int PRESSURE_DATA_OFFSET = 10;
const int ACCELEROMETER_X_OFFSET = 16;
const int ACCELEROMETER_Y_OFFSET = 17;
const int ACCELEROMETER_Z_OFFSET = 9;
const int PRESSURE_STATE = 14;
//Get the pressure state
if (e.Data[PRESSURE_STATE] == (byte)RawPressureType.NotPressed)
PressureType = TabletPressureType.NotPressed;
else if (e.Data[PRESSURE_STATE] == (byte)RawPressureType.PenPressed)
PressureType = TabletPressureType.PenPressed;
else if (e.Data[PRESSURE_STATE] == (byte)RawPressureType.FingerPressed)
PressureType = TabletPressureType.FingerPressed;
else
PressureType = TabletPressureType.Multitouch;
//Get the pen pressure
PenPressure = (ushort)(e.Data[PEN_PRESSURE_OFFSET]);
//Get the multitouch distance
_multitouchTimer++;
if (_multitouchTimer > _MULTITOUCH_SENSITIVITY)
{
_multitouchTimer = 0;
_previousMultitouchDistance = MultitouchDistance;
}
MultitouchDistance = e.Data[MULTITOUCH_DISTANCE_OFFSET];
//Get the (singular) pressure point
PressurePoint = new Point(e.Data[PRESSURE_DATA_OFFSET + 1] * 0x100 + e.Data[PRESSURE_DATA_OFFSET],
e.Data[PRESSURE_DATA_OFFSET + 3] * 0x100 + e.Data[PRESSURE_DATA_OFFSET + 2]);
//Get the accelerometer data
const ushort X_MIN = 0x0C; const ushort X_MAX = 0x34;
const ushort Y_MIN = 0x0A; const ushort Y_MAX = 0x34;
const ushort Z_MIN = 0x0C; const ushort Z_MAX = 0x34;
ushort x = (ushort)(e.Data[ACCELEROMETER_X_OFFSET]);
if (x < X_MIN) x = X_MIN; if (x > X_MAX) x = X_MAX;
AccelerometerData.XAxis = (ushort)((x - X_MIN) / (X_MAX - X_MIN));
ushort y = (ushort)(e.Data[ACCELEROMETER_Y_OFFSET]);
if (y < Y_MIN) y = Y_MIN; if (y > Y_MAX) y = Y_MAX;
AccelerometerData.YAxis = (ushort)((y - Y_MIN) / (Y_MAX - Y_MIN));
ushort z = (ushort)(e.Data[ACCELEROMETER_Z_OFFSET]);
if (z < Z_MIN) z = Z_MIN; if (z > Z_MAX) z = Z_MAX;
AccelerometerData.ZAxis = (ushort)((z - Z_MIN) / (Z_MAX - Z_MIN));
//Parse raw data for buttons
bool changed = false;
bool raw = (e.Data[7] & 0x40) > 0;
changed |= ButtonState.SquareHeld != raw; ButtonState.SquareHeld = raw;
raw = (e.Data[7] & 0x10) > 0;
changed |= ButtonState.CrossHeld != raw; ButtonState.CrossHeld = raw;
raw = (e.Data[7] & 0x20) > 0;
changed |= ButtonState.CircleHeld != raw; ButtonState.CircleHeld = raw;
raw = (e.Data[7] & 0x80) > 0;
changed |= ButtonState.TriangleHeld != raw; ButtonState.TriangleHeld = raw;
raw = (e.Data[6] & 0x20) > 0;
changed |= ButtonState.SelectHeld != raw; ButtonState.SelectHeld = raw;
raw = (e.Data[6] & 0x10) > 0;
changed |= ButtonState.StartHeld != raw; ButtonState.StartHeld = raw;
raw = (e.Data[7] & 0x04) > 0;
changed |= ButtonState.PSHeld != raw; ButtonState.PSHeld = raw;
if (changed && ButtonStateChanged != null)
ButtonStateChanged(this, EventArgs.Empty);
//Now parse raw data for D-pad changes
changed = false;
raw = (e.Data[6] == 0x1) || (e.Data[6] == 0x5) || (e.Data[6] == 0x9);
changed |= DPadState.UpHeld != raw; DPadState.UpHeld = raw;
raw = (e.Data[6] == 0x2) || (e.Data[6] == 0x6) || (e.Data[6] == 0xA);
changed |= DPadState.DownHeld != raw; DPadState.DownHeld = raw;
raw = (e.Data[6] == 0x4) || (e.Data[6] == 0x6) || (e.Data[6] == 0x5);
changed |= DPadState.LeftHeld != raw; DPadState.LeftHeld = raw;
raw = (e.Data[6] == 0x8) || (e.Data[6] == 0x9) || (e.Data[6] == 0xA);
changed |= DPadState.RightHeld != raw; DPadState.RightHeld = raw;
if (changed && DPadStateChanged != null)
DPadStateChanged(this, EventArgs.Empty);
}
}
#endregion
}
}