using System;
using System.Collections.Generic;
using System.Drawing;
using System.Text;
using Xbox360USB;
namespace uDrawLib
{
public class Xbox360uDrawTabletDevice : ITabletDevice
{
#region Declarations
private const int _MULTITOUCH_SENSITIVITY = 30;
private WirelessReceiver _receiver;
private int _index;
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 Xbox360uDrawTabletDevice(WirelessReceiver receiver, int index)
{
ButtonState = new TabletButtonState();
DPadState = new TabletDPadState();
AccelerometerData = new TabletAccelerometerData();
_index = index;
_receiver = receiver;
_receiver.EventDataReceived += _receiver_EventDataReceived;
}
#endregion
#region Public Events
public event EventHandler ButtonStateChanged;
public event EventHandler DPadStateChanged;
#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 _receiver_EventDataReceived(object sender, Xbox360USB.DataReceivedEventArgs e)
{
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
AccelerometerData.XAxis = (ushort)(e.Data[ACCELEROMETER_X_OFFSET]);
AccelerometerData.YAxis = (ushort)(e.Data[ACCELEROMETER_Y_OFFSET]);
AccelerometerData.ZAxis = (ushort)(e.Data[ACCELEROMETER_Z_OFFSET]);
//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
}
}