using SharpDX; using SharpDX.DirectInput; using System; using System.Collections.Generic; using System.Reflection; using System.Text; using System.Windows.Forms; using System.Drawing; using System.Text.RegularExpressions; using SCJMapper_V2.Common; namespace SCJMapper_V2.Devices.Joystick { /// /// Handles one JS device as DXInput device /// In addition provide some static tools to handle JS props here in one place /// Also owns the GUI i.e. the user control that shows all values /// public class JoystickCls : DeviceCls { private static readonly log4net.ILog log = log4net.LogManager.GetLogger( MethodBase.GetCurrentMethod( ).DeclaringType ); #region Static Items public new const string DeviceClass = "joystick"; // the device name used throughout this app public new const string DeviceID = "js1_"; static public int RegisteredDevices = 0; static public int JSnum_UNKNOWN = 0; static public int JSnum_MAX = 12; // Get to 12 for 'freaks' .. public const string JsUnknown = "jsx_"; public new const string DisabledInput = DeviceID + DeviceCls.DisabledInput; //AC2 .. static public new bool IsDisabledInput( string input ) { if ( input == DisabledInput ) return true; return false; } /// /// Returns the currently valid color for a jsN assignment /// /// The jsN number of the command /// A color static public System.Drawing.Color JsNColor( int jsN ) { if ( jsN == JSnum_UNKNOWN ) return MyColors.BlendedColor; if ( jsN < 1 ) return MyColors.ErrorColor; if ( jsN > JoystickCls.JSnum_MAX ) return MyColors.ErrorColor; return MyColors.JsMapColor[jsN - 1]; // jsN is 1 based, color array is 0 based } /// /// Returns true if the devicename is a joystick /// /// /// static public new bool IsDeviceClass( string deviceClass ) { return ( deviceClass == DeviceClass ); } public static void DecompJsCommand( string jsCmd, out string jsTag, out string sAction ) { // can be jsN_hat1_down .... jsTag = ""; sAction = ""; string[] e = jsCmd.Split( new char[] { '_' }, StringSplitOptions.RemoveEmptyEntries ); if ( e.Length > 1 ) { jsTag = e[0].Trim( ) + "_"; sAction = e[1].Trim( ); if ( e.Length > 2 ) { sAction += "_" + e[2].Trim( ); } } } /// /// Return this deviceClass if the input string contains something like jsN_ /// /// /// static public new string DeviceClassFromInput( string devInput ) { if ( JSNum( devInput ) != JSnum_UNKNOWN ) return DeviceClass; // this else return DeviceCls.DeviceClass; // unknown } /// /// Create a DevInput string if the input does look like not having a device ID /// /// A keyboard input /// DevInput static public new string DevInput( string input ) { if ( DevMatch( input ) ) return input; // already else return DeviceID + input; // this will mostly not be as expected as it returns js1_ only .. } /// /// Create a DevInput string if the input does look like not having a device ID /// /// A keyboard input /// DevInput static public string DevInput( string input, int jsN ) { if ( DevMatch( input ) ) return input; // already else return DeviceID.Replace( "1", jsN.ToString( "D" ) ) + input; } /// /// Returns true if the input matches this device /// /// A devInput string /// True for a match static public new bool DevMatch( string devInput ) { return IsJsN( devInput ); } /// /// Returns true if a command is an axis command /// /// The command string /// True if it is an axis command static public new bool IsAxisCommand( string command ) { string cLower = command.ToLowerInvariant( ); if ( IsJsN( command ) ) return ( cLower.EndsWith( "_x" ) || cLower.EndsWith( "_rotx" ) || cLower.EndsWith( "_throttlex" ) || cLower.EndsWith( "_y" ) || cLower.EndsWith( "_roty" ) || cLower.EndsWith( "_throttley" ) || cLower.EndsWith( "_z" ) || cLower.EndsWith( "_rotz" ) || cLower.EndsWith( "_throttlez" ) || cLower.EndsWith( "_slider1" ) || cLower.EndsWith( "_slider2" ) ); else return false; } /// /// Returns the jsN part from a joystick command /// i.e. js1_x returns js1 /// /// The joystick command in 'jsN_command' notation /// the jsN part or an empty string public static string JsTagFromJsCommand( string jsCmd ) { string jsTag, sAction; DecompJsCommand( jsCmd, out jsTag, out sAction ); return jsTag; } /// /// Returns the stick action part from a node text /// i.e. js1_x returns x /// /// The joystick command in 'jsN_command' notation /// the stick action part or an empty string public static string ActionFromJsCommand( string jsCmd ) { string jsTag, sAction; DecompJsCommand( jsCmd, out jsTag, out sAction ); return sAction; } /// /// Returns properly formatted jsn_ string (jsx_ if the input is UNKNOWN) /// /// The JS number /// The formatted JS name for the CryEngine XML static public string JSTag( int jsNum ) { if ( IsJSValid( jsNum ) ) return "js" + jsNum.ToString( ); return JsUnknown; } /// /// Extract the JS number from a JS string (jsx_ returns 0 - UNKNOWN) /// AC 1.1 can be something as "rctrl+js2_nn" /// /// The JS string /// The JS number static public int JSNum( string jsTag ) { int retNum = JSnum_UNKNOWN; if ( !string.IsNullOrWhiteSpace( jsTag ) ) { // find jsN start int jsPos = jsTag.IndexOf( "+js" ); if ( jsPos > 0 ) { if ( !int.TryParse( ( jsTag + "XX" ).Substring( jsPos + 3, 2 ), out retNum ) ) { // cheap .. test for double digits if ( !int.TryParse( jsTag.Substring( jsPos + 3, 1 ), out retNum ) ) { // now for only single ones retNum = JSnum_UNKNOWN; // neither double nor single digit found } } } else if ( jsTag.StartsWith( "js" ) ) { if ( !int.TryParse( ( jsTag + "XX" ).Substring( 2, 2 ), out retNum ) ) { // cheap .. test for double digits ( have to extend the string to parse) if ( !int.TryParse( jsTag.Substring( 2, 1 ), out retNum ) ) { // now for only single ones retNum = JSnum_UNKNOWN; // neither double nor single digit found } } } else { retNum = JSnum_UNKNOWN; // neither double nor single digit found } } return retNum; } /// /// Returns the validity of a JSnumber /// Done here to maintain the ownership of how things are done /// /// The JS number /// True if it is a valid one static public bool IsJSValid( int jsNum ) { return ( jsNum > JSnum_UNKNOWN ) && ( jsNum <= JSnum_MAX ); } const string js_pattern = @"^js\d{1,2}_*"; static Regex rgx_js = new Regex( js_pattern, RegexOptions.IgnoreCase ); /// /// Returns true if the input starts with a valid jsN_ formatting /// /// /// static public bool IsJsN( string input ) { return rgx_js.IsMatch( input ); } /// /// Returns an adjusted jsN tag with the new number /// /// An input directive /// the new JsN number /// The modified js directive or the directive if no mod can be done static public string ReassignJSTag( string input, int newJsN ) { // find jsN start if ( IsJsN( input ) ) { int inJsN = JSNum( input ); if ( inJsN < 10 ) { return input.Replace( input.Substring( 0, 3 ), JSTag( newJsN ) ); } else { // 2 digit input JsN return input.Replace( input.Substring( 0, 4 ), JSTag( newJsN ) ); } } else { return input; } } const string jsl_pattern = @"^js\d{1,2}_[xyz]$"; static Regex rgx_jsl = new Regex( jsl_pattern, RegexOptions.IgnoreCase ); const string jsr_pattern = @"^js\d{1,2}_rot[xyz]$"; static Regex rgx_jsr = new Regex( jsr_pattern, RegexOptions.IgnoreCase ); /// /// Makes a throttle from the given ctrl /// accepts js#_(rot)[xyz] and returns js#_throttle[xyz] /// /// /// /// static public string MakeThrottle( string control, bool makeIt ) { if ( makeIt == false ) return control; if ( control.Length < 5 ) return control; string retVal = control; if ( rgx_jsl.IsMatch( control ) ) { int inJsN = JSNum( control ); if ( inJsN < 10 ) { retVal = retVal.Insert( 4, "throttle" ); } else { // 2 digit input JsN retVal = retVal.Insert( 5, "throttle" ); } } /* THIS IS WRONG.... don't know if rot can get a throttle... else if ( rgx_jsr.IsMatch( control ) ) { retVal = retVal.Remove( 4, 3 ); // remove rot retVal = retVal.Insert( 4, "throttle" ); } */ return retVal; } /// /// returns true if the ctrl can be a throttle - for now this is js#_[xyz] /// /// /// static public bool CanThrottle( string control ) { return rgx_jsl.IsMatch( control ) || rgx_jsr.IsMatch( control ); } const string jsb_pattern = @"^js\d{1,2}_button\d{1,3}$"; static Regex rgx_jsb = new Regex( jsb_pattern, RegexOptions.IgnoreCase ); /// /// Returns True if devInput seems to be a valid Modifier /// (only buttons are accepted) /// /// A qualified devInput (jsN_buttonM) /// True for a valid one static public Bool ValidModifier( string devInput ) { return rgx_jsb.IsMatch( devInput ); } #endregion // ****************** CLASS ************************* private SharpDX.DirectInput.Joystick m_device; private JoystickState m_state = new JoystickState( ); private JoystickState m_prevState = new JoystickState( ); private Control m_hwnd; private int m_numPOVs = 0; // static counter for UpdateControls private int m_sliderCount = 0; // static counter for UpdateControls private string m_lastItem = ""; private int m_senseLimit = 150; // axis jitter avoidance... private int m_joystickNumber = 0; // 0..n-1 seq number of the enumerated joystick - assigned in Ctor - remains fixed private int m_xmlInstance = 0; // The CIG instance number (may change through property JSAssignment) private bool[] m_ignoreButtons; private bool m_activated = false; private bool[] m_modifierButtons; private UC_JoyPanel m_jPanel = null; // the GUI panel internal int MyTabPageIndex = -1; /// /// Returns a CryEngine compatible hat direction /// /// The Hat value /// The direction string private string HatDir( int value ) { // Hats have a 360deg -> 36000 value reporting if ( value == 0 ) return "up"; if ( value == 9000 ) return "right"; if ( value == 18000 ) return "down"; if ( value == 27000 ) return "left"; return ""; } /// /// Return the CIG instance number (which is the jsN number) /// public override int XmlInstance { get { return m_xmlInstance; } } /// /// Return the DX device instance number (0..n-1) /// public override int DevInstance { get { return m_joystickNumber; } } /// /// The DeviceClass of this instance /// public override string DevClass { get { return JoystickCls.DeviceClass; } } /// /// The JS ProductName property /// public override string DevName { get { return m_device.Properties.ProductName; } } /// /// The ProductGUID property /// public override string DevGUID { get { return "{" + m_device.Information.ProductGuid.ToString( ).ToUpperInvariant( ) + "}"; } } /// /// The JS Instance GUID for multiple device support (VJoy gets 2 of the same name) /// public override string DevInstanceGUID { get { return m_device.Information.InstanceGuid.ToString( ); } } /// /// The assigned jsN number for this device (1..n) /// public int JSAssignment { get { return m_xmlInstance; } set { m_xmlInstance = value; m_jPanel.JsAssignment = m_xmlInstance; } } /// /// Returns the mapping color for this device /// public override System.Drawing.Color MapColor { get { return JsNColor( JSAssignment ); } } // device props public int AxisCount { get { return m_device.Capabilities.AxeCount; } } public int ButtonCount { get { return m_device.Capabilities.ButtonCount; } } public int POVCount { get { return m_device.Capabilities.PovCount; } } public override List AnalogCommands { get { List cmds = new List( ); try { // Enumerate all the objects on the device. m_sliderCount = 0; //20201231 init to 0 else it counts beyond the available ones foreach ( DeviceObjectInstance d in m_device.GetObjects( ) ) { // Set the UI to reflect what objects the joystick supports. if ( ObjectGuid.XAxis == d.ObjectType ) cmds.Add( "x" ); if ( ObjectGuid.YAxis == d.ObjectType ) cmds.Add( "y" ); if ( ObjectGuid.ZAxis == d.ObjectType ) cmds.Add( "z" ); if ( ObjectGuid.RxAxis == d.ObjectType ) cmds.Add( "rotx" ); if ( ObjectGuid.RyAxis == d.ObjectType ) cmds.Add( "roty" ); if ( ObjectGuid.RzAxis == d.ObjectType ) cmds.Add( "rotz" ); if ( ObjectGuid.Slider == d.ObjectType ) { switch ( m_sliderCount++ ) { case 0: cmds.Add( "slider1" ); break; case 1: cmds.Add( "slider2" ); break; } } } } catch ( Exception ex ) { log.Error( "AnalogCommands - Get JS Objects failed", ex ); } cmds.Sort( ); return cmds; } } public override bool Activated { get { return Activated_low; } set { Activated_low = value; } } private bool Activated_low { get { return m_activated; } set { m_activated = value; if ( m_activated == false ) m_device.Unacquire( ); // explicitely if not longer active } } /// /// ctor and init /// /// A DXInput device /// The WinHandle of the main window /// The 0.. n-1 Joystick from DX enum /// The respective JS panel to show the properties /// The Tab index in the GUI public JoystickCls( SharpDX.DirectInput.Joystick device, Control hwnd, int joystickNum, UC_JoyPanel panel, int tabIndex ) { log.DebugFormat( "JoystickCls ctor - Entry with {0}", device.Information.ProductName ); m_device = device; m_hwnd = hwnd; m_joystickNumber = joystickNum; // this remains fixed m_xmlInstance = joystickNum + 1; // initial assignment (is 1 based..) m_jPanel = panel; MyTabPageIndex = tabIndex; Activated_low = false; m_senseLimit = AppConfiguration.AppConfig.jsSenseLimit; // can be changed in the app.config file if it is still too little // Set BufferSize in order to use buffered data. m_device.Properties.BufferSize = 128; m_jPanel.Caption = m_device.Properties.ProductName; m_jPanel.nAxis = AxisCount.ToString( ); m_jPanel.nButtons = ButtonCount.ToString( ); m_jPanel.nPOVs = POVCount.ToString( ); m_jPanel.JsAssignment = 0; // default is no assignment m_ignoreButtons = new bool[m_state.Buttons.Length]; ResetButtons( m_ignoreButtons ); m_modifierButtons = new bool[m_state.Buttons.Length]; ResetButtons( m_modifierButtons ); log.Debug( "Get JS Objects" ); try { // Set the data format to the c_dfDIJoystick pre-defined format. //m_device.SetDataFormat( DeviceDataFormat.Joystick ); // Set the cooperative level for the device. m_device.SetCooperativeLevel( m_hwnd, CooperativeLevel.NonExclusive | CooperativeLevel.Background ); // Enumerate all the objects on the device. foreach ( DeviceObjectInstance d in m_device.GetObjects( ) ) { // For axes that are returned, set the DIPROP_RANGE property for the // enumerated axis in order to scale min/max values. if ( ( 0 != ( d.ObjectId.Flags & DeviceObjectTypeFlags.Axis ) ) ) { // Set the range for the axis. m_device.Properties.Range = new InputRange( -1000, +1000 ); } // Update the controls to reflect what objects the device supports. UpdateControls( d ); } } catch ( Exception ex ) { log.Error( "Get JS Objects failed", ex ); } ApplySettings_low( ); // get whatever is needed here from Settings JoystickCls.RegisteredDevices++; Activated_low = true; } /// /// Shutdown device access /// public override void FinishDX() { if ( null != m_device ) { log.DebugFormat( "Release DirectInput device: {0}", m_device.Information.ProductName ); m_device.Unacquire( ); m_device = null; } } /// /// Tells the Joystick to re-read settings /// public override void ApplySettings() { ApplySettings_low( ); } private void ApplySettings_low() { AppSettings.Instance.Reload( ); ResetButtons( m_ignoreButtons ); // read ignore buttons string igs = ""; switch ( m_joystickNumber + 1 ) { // bug alert, m_joystickNumber is 0 based... case 1: igs = AppSettings.Instance.IgnoreJS1; break; case 2: igs = AppSettings.Instance.IgnoreJS2; break; case 3: igs = AppSettings.Instance.IgnoreJS3; break; case 4: igs = AppSettings.Instance.IgnoreJS4; break; case 5: igs = AppSettings.Instance.IgnoreJS5; break; case 6: igs = AppSettings.Instance.IgnoreJS6; break; case 7: igs = AppSettings.Instance.IgnoreJS7; break; case 8: igs = AppSettings.Instance.IgnoreJS8; break; case 9: igs = AppSettings.Instance.IgnoreJS9; break; case 10: igs = AppSettings.Instance.IgnoreJS10; break; case 11: igs = AppSettings.Instance.IgnoreJS11; break; case 12: igs = AppSettings.Instance.IgnoreJS12; break; default: break; } if ( string.IsNullOrWhiteSpace( igs ) ) return; // no setting - all allowed // read the ignore numbers string[] nums = igs.Split( ' ' ); foreach ( string s in nums ) { int btNum = 0; // gets 1..n if ( int.TryParse( s, out btNum ) ) { if ( ( btNum > 0 ) && ( btNum <= m_ignoreButtons.Length ) ) { m_ignoreButtons[--btNum] = true; // zero indexed } } } } private void ResetButtons( bool[] bt ) { for ( int i = 0; i < bt.Length; i++ ) bt[i] = false; } /// /// Add or Remove a modifier from this joystick /// /// The joystick command (jsN_buttonM) /// True to add, False to remove it public void UpdateModifier( string modS, bool add ) { if ( !ValidModifier( modS ) ) return; // sanity.. // check if it is applicable int jsn = JSNum( modS ); if ( jsn == m_joystickNumber ) { // format is jsN_buttonM i.e. get button number at the end int bNr = 0; if ( int.TryParse( modS.Substring( 10 ), out bNr ) ) { // valid bNr m_modifierButtons[bNr - 1] = add; // update } } } /// /// Enable the properties that are supported by the device /// /// private void UpdateControls( DeviceObjectInstance d ) { // Set the UI to reflect what objects the joystick supports. if ( ObjectGuid.XAxis == d.ObjectType ) { m_jPanel.Xe = true; m_jPanel.Xname = d.Name + ":"; } if ( ObjectGuid.YAxis == d.ObjectType ) { m_jPanel.Ye = true; m_jPanel.Yname = d.Name + ":"; } if ( ObjectGuid.ZAxis == d.ObjectType ) { m_jPanel.Ze = true; m_jPanel.Zname = d.Name + ":"; } if ( ObjectGuid.RxAxis == d.ObjectType ) { m_jPanel.Xre = true; m_jPanel.Xrname = d.Name + ":"; } if ( ObjectGuid.RyAxis == d.ObjectType ) { m_jPanel.Yre = true; m_jPanel.Yrname = d.Name + ":"; } if ( ObjectGuid.RzAxis == d.ObjectType ) { m_jPanel.Zre = true; m_jPanel.Zrname = d.Name + ":"; } if ( ObjectGuid.Slider == d.ObjectType ) { switch ( m_sliderCount++ ) { case 0: m_jPanel.S1e = true; m_jPanel.S1name = d.Name + ":"; break; case 1: m_jPanel.S2e = true; m_jPanel.S2name = d.Name + ":"; break; } } if ( ObjectGuid.PovController == d.ObjectType ) { switch ( m_numPOVs++ ) { case 0: m_jPanel.H1e = true; m_jPanel.H1name = d.Name + ":"; break; case 1: m_jPanel.H2e = true; m_jPanel.H2name = d.Name + ":"; break; case 2: m_jPanel.H3e = true; m_jPanel.H3name = d.Name + ":"; break; case 3: m_jPanel.H4e = true; m_jPanel.H4name = d.Name + ":"; break; } } } // Property Mapping from DXinput to CryEngine string private Dictionary m_axiesDx2Cry = new Dictionary( ) { {"X","x"}, {"Y","y"}, {"Z","z"}, {"RotationX","rotx"}, {"RotationY","roty"}, {"RotationZ","rotz"} }; // Property Mapping from CryEngine string to DxInput private Dictionary m_axiesCry2Dx = new Dictionary( ) { {"x","X"}, {"y","Y"}, {"z","Z"}, {"rotx","RotationX"}, {"roty","RotationY"}, {"rotz","RotationZ"} }; /// /// returns the currently available input string /// (does not retrieve new data but uses what was collected by GetData()) /// NOTE: for Joystick when multiple inputs are available the sequence is /// axis > button > hat > slider (wher prio is max itemNum > min itemNum) /// /// An input string or an empty string if no input is available public override string GetCurrentInput() { string currentInput = string.Empty; // get changed slider int[] slider = m_state.Sliders; int[] pslider = m_prevState.Sliders; if ( DidAxisChange2( slider[0], pslider[0] ) ) currentInput = "slider1"; if ( DidAxisChange2( slider[1], pslider[1] ) ) currentInput = "slider2"; // get prio hat int[] pov = m_state.PointOfViewControllers; int[] ppov = m_prevState.PointOfViewControllers; if ( pov[0] >= 0 ) currentInput = "hat1_" + HatDir( pov[0] ); if ( pov[1] >= 0 ) currentInput = "hat2_" + HatDir( pov[1] ); if ( pov[2] >= 0 ) currentInput = "hat3_" + HatDir( pov[2] ); if ( pov[3] >= 0 ) currentInput = "hat4_" + HatDir( pov[3] ); // get prio button bool[] buttons = m_state.Buttons; bool[] prevButtons = m_prevState.Buttons; for ( int bi = 0; bi < buttons.Length; bi++ ) { if ( m_ignoreButtons[bi] == false ) { if ( buttons[bi] ) currentInput = "button" + ( bi + 1 ).ToString( ); } } // get axis foreach ( KeyValuePair entry in m_axiesDx2Cry ) { PropertyInfo axisProperty = typeof( JoystickState ).GetProperty( entry.Key ); if ( DidAxisChange2( (int)axisProperty.GetValue( this.m_state, null ), (int)axisProperty.GetValue( this.m_prevState, null ) ) ) currentInput = entry.Value; } return currentInput; } /// /// Find the last change the user did on that device /// either new or from persistence /// NOTE: reporting priority is: /// axis > button > hat > slider (for buttons and hats this returns the newly pressed one when more than one is active) /// /// An input string public override string GetLastChange() { // get changed slider int[] slider = m_state.Sliders; int[] pslider = m_prevState.Sliders; if ( DidAxisChange2( slider[0], pslider[0] ) ) m_lastItem = "slider1"; if ( DidAxisChange2( slider[1], pslider[1] ) ) m_lastItem = "slider2"; // get new hat int[] pov = m_state.PointOfViewControllers; int[] ppov = m_prevState.PointOfViewControllers; if ( pov[0] >= 0 ) if ( pov[0] != ppov[0] ) m_lastItem = "hat1_" + HatDir( pov[0] ); if ( pov[1] >= 0 ) if ( pov[1] != ppov[1] ) m_lastItem = "hat2_" + HatDir( pov[1] ); if ( pov[2] >= 0 ) if ( pov[2] != ppov[2] ) m_lastItem = "hat3_" + HatDir( pov[2] ); if ( pov[3] >= 0 ) if ( pov[3] != ppov[3] ) m_lastItem = "hat4_" + HatDir( pov[3] ); // get new button bool[] buttons = m_state.Buttons; bool[] prevButtons = m_prevState.Buttons; for ( int bi = 0; bi < buttons.Length; bi++ ) { if ( m_ignoreButtons[bi] == false ) { if ( buttons[bi] && ( buttons[bi] != prevButtons[bi] ) ) m_lastItem = "button" + ( bi + 1 ).ToString( ); } } // get changed axis foreach ( KeyValuePair entry in m_axiesDx2Cry ) { PropertyInfo axisProperty = typeof( JoystickState ).GetProperty( entry.Key ); if ( DidAxisChange2( (int)axisProperty.GetValue( this.m_state, null ), (int)axisProperty.GetValue( this.m_prevState, null ) ) ) m_lastItem = entry.Value; } return m_lastItem; } /// /// Figure out if an axis changed enough to consider it as a changed state /// The change is polled every 100ms (timer1) so the user has to change so much within that time /// Then an axis usually swings back when left alone - that is the real recording of a change. /// We know that the range is -1000 .. 1000 so we can judge absolute /// % relative is prone to small changes around 0 - which is likely the case with axes /// private bool DidAxisChange2( int current, int prev ) { // determine if the axis drifts more than x units to account for bounce // old-new/old if ( current == prev ) return false; int change = Math.Abs( prev - current ); // if the axis has changed more than x units to it's last value return change > m_senseLimit ? true : false; } /// /// Figure out if an axis changed enough to consider it as a changed state /// private bool DidAxisChange( int current, int prev ) { // determine if the axis drifts more than x% to account for bounce // old-new/old if ( current == prev ) return false; if ( prev == 0 ) prev = 1; int changepct = Math.Abs( prev ) - Math.Abs( current ) / Math.Abs( prev ); // if the axis has changed more than 70% relative to it's last value return changepct > 70 ? true : false; } /// /// Show the current props in the GUI /// private void UpdateUI() { if ( Application.MessageLoop ) { // This function updated the UI with joystick state information. string strText = null; m_jPanel.X = m_state.X.ToString( ); m_jPanel.Y = m_state.Y.ToString( ); m_jPanel.Z = m_state.Z.ToString( ); m_jPanel.Xr = m_state.RotationX.ToString( ); m_jPanel.Yr = m_state.RotationY.ToString( ); m_jPanel.Zr = m_state.RotationZ.ToString( ); int[] slider = m_state.Sliders; m_jPanel.S1 = slider[0].ToString( ); m_jPanel.S2 = slider[1].ToString( ); int[] pov = m_state.PointOfViewControllers; m_jPanel.H1 = pov[0].ToString( ); m_jPanel.H2 = pov[1].ToString( ); m_jPanel.H3 = pov[2].ToString( ); m_jPanel.H4 = pov[3].ToString( ); // Fill up text with which buttons are pressed bool[] buttons = m_state.Buttons; int button = 0; foreach ( bool b in buttons ) { if ( b ) strText += ( button + 1 ).ToString( "00 " ); // buttons are 1 based button++; } m_jPanel.Button = strText; } } /// /// Collect the current data from the device /// public void GetAxisData( out int x, out int y, out int rz ) { x = 0; y = 0; rz = 0; // Make sure there is a valid device. if ( null == m_device ) return; // Poll the device for info. try { m_device.Poll( ); } catch ( SharpDXException e ) { if ( ( e.ResultCode == ResultCode.NotAcquired ) || ( e.ResultCode == ResultCode.InputLost ) ) { // Check to see if either the app needs to acquire the device, or // if the app lost the device to another process. try { // Acquire the device. m_device.Acquire( ); } catch ( SharpDXException ) { // Failed to acquire the device. This could be because the app doesn't have focus. return; // EXIT unaquired } } else { log.Error( "Unexpected Poll Exception", e ); return; // EXIT see ex code } } // Get the state of the device - retaining the previous state to find the lates change m_prevState = m_state; try { m_state = m_device.GetCurrentState( ); } // Catch any exceptions. None will be handled here, // any device re-aquisition will be handled above. catch ( SharpDXException ) { return; } x = m_state.X; y = m_state.Y; rz = m_state.RotationZ; } /// /// Collect the current data from the device /// public override void GetCmdData( string cmd, out int data ) { data = 0; // Make sure there is a valid device. if ( null == m_device ) return; // Poll the device for info. try { m_device.Poll( ); } catch ( SharpDXException e ) { if ( ( e.ResultCode == ResultCode.NotAcquired ) || ( e.ResultCode == ResultCode.InputLost ) ) { // Check to see if either the app needs to acquire the device, or // if the app lost the device to another process. try { // Acquire the device. m_device.Acquire( ); } catch ( SharpDXException ) { // Failed to acquire the device. This could be because the app doesn't have focus. return; // EXIT unaquired } } else { log.Error( "Unexpected Poll Exception", e ); return; // EXIT see ex code } } // Get the state of the device - retaining the previous state to find the lates change m_prevState = m_state; try { m_state = m_device.GetCurrentState( ); } // Catch any exceptions. None will be handled here, // any device re-aquisition will be handled above. catch ( SharpDXException ) { return; } try { PropertyInfo axisProperty = typeof( JoystickState ).GetProperty( m_axiesCry2Dx[cmd] ); data = (int)axisProperty.GetValue( this.m_state, null ); } catch { data = 0; } } /// /// Collect the current data from the device /// public override void GetData() { // Make sure there is a valid device. if ( null == m_device ) return; // Poll the device for info. try { m_device.Poll( ); } catch ( SharpDXException e ) { if ( ( e.ResultCode == ResultCode.NotAcquired ) || ( e.ResultCode == ResultCode.InputLost ) ) { // Check to see if either the app needs to acquire the device, or // if the app lost the device to another process. try { // Acquire the device - if the (main)window is active if ( Activated ) m_device.Acquire( ); } catch ( SharpDXException ) { // Failed to acquire the device. This could be because the app doesn't have focus. return; // EXIT unaquired } } else { log.Error( "Unexpected Poll Exception", e ); return; // EXIT see ex code } } // Get the state of the device - retaining the previous state to find the lates change m_prevState = m_state; try { m_state = m_device.GetCurrentState( ); } // Catch any exceptions. None will be handled here, // any device re-aquisition will be handled above. catch ( SharpDXException ) { return; } UpdateUI( ); // and update the GUI } } }