/// <summary> /// Parse the configuration file and fill the Direct Input device attributes /// </summary> private void SetAttributes(AltDirectInputDevice Device, String Section) { InputRange Range; // Parse the global dead zone attribute for this device. This is the dead zone // that will be applied if there isn't a specific axis override float.TryParse(ini.IniReadValue(Section, "DeadZone"), out Device.DeadZone); // Parse the global sensitivity float.TryParse(ini.IniReadValue(Section, "Factor"), out Device.Factor); if (Device.Factor == 0.0f) Device.Factor = 1.0f; // Find our which modes have been setup for (var m = 1; m < GameState.NumModes; m++) Device.enabledModes[m] = (ini.IniReadValue(Section + "." + GameState.ModeName[m], null) != ""); // Process the axes for (var i = 0; i < AltDirectInputDevice.AxisList.GetLength(0); i++) { // We get a DIERR_NOTFOUND/NotFound exception when probing the range for unused axes. // We use this to detect if the axe is available try { // Parse common axis settings, starting with the Range Range = Device.Joystick.GetObjectPropertiesByName(AltDirectInputDevice.AxisList[i, 0]).Range; Device.Axis[i].Range.Minimum = Range.Minimum; Device.Axis[i].Range.Maximum = Range.Maximum; Device.Axis[i].Range.FloatRange = 1.0f * (Range.Maximum - Range.Minimum); // TODO: Check if mapping name is valid for (var m = 0; m < GameState.NumModes; m++) { if (!Device.enabledModes[m]) continue; // Parse the dead zone float.TryParse(ini.IniReadValue(Section, AltDirectInputDevice.AxisList[i, 1] + ".DeadZone"), out Device.Axis[i].Control[m].DeadZone); if (Device.Axis[i].Control[m].DeadZone == 0.0f) // Override with global dead zone if none was specified // NB: This prohibits setting a global dead zone and then an individual one to 0 - oh well... Device.Axis[i].Control[m].DeadZone = Device.DeadZone; // A slider's dead zone is special and needs to be handled separately if (!AltDirectInputDevice.AxisList[i, 0].StartsWith("Slider")) Device.Joystick.GetObjectPropertiesByName(AltDirectInputDevice.AxisList[i, 0]).DeadZone = (int)(10000.0f * Device.Axis[i].Control[m].DeadZone); // Parse the Factor float.TryParse(ini.IniReadValue(Section, AltDirectInputDevice.AxisList[i, 1] + ".Factor"), out Device.Axis[i].Control[m].Factor); if (Device.Axis[i].Control[m].Factor == 0.0f) Device.Axis[i].Control[m].Factor = Device.Factor; ParseControl(Section, AltDirectInputDevice.AxisList[i, 1], Device.Axis[i].Control, m); if (Device.Axis[i].Control[m].Type == ControlType.Axis) { ParseMapping(Section, AltDirectInputDevice.AxisList[i, 1], Device.Axis[i].Mapping1, m); } else { ParseMapping(Section, AltDirectInputDevice.AxisList[i, 1] + ".Min", Device.Axis[i].Mapping1, m); ParseMapping(Section, AltDirectInputDevice.AxisList[i, 1] + ".Max", Device.Axis[i].Mapping2, m); } } Device.Axis[i].isAvailable = (Device.Axis[i].Range.FloatRange != 0.0f); if (!Device.Axis[i].isAvailable) print("Altinput: WARNING - Axis " + AltDirectInputDevice.AxisList[i, 1] + " was disabled because its range is zero."); } // Typical exception "SharpDX.SharpDXException: HRESULT: [0x80070002], Module: [SharpDX.DirectInput], // ApiCode: [DIERR_NOTFOUND/NotFound], Message: The system cannot find the file specified." catch (SharpDX.SharpDXException ex) { if (ex.ResultCode == 0x80070002) Device.Axis[i].isAvailable = false; else throw ex; } #if (DEBUG) if (Device.Axis[i].isAvailable) { for (var m = 0; m < GameState.NumModes; m++) { String Mappings = ""; if (!Device.enabledModes[m]) continue; if (Device.Axis[i].Control[m].Type == ControlType.Axis) { Mappings += ", Mapping = '" + Device.Axis[i].Mapping1[m].Action + "'"; } else { Mappings += ", Mapping.Min = '" + Device.Axis[i].Mapping1[m].Action + "'"; Mappings += ", Mapping.Max = '" + Device.Axis[i].Mapping2[m].Action + "'"; } print("Altinput: Axis #" + (i + 1) + "[" + GameState.ModeName[m] + "] ('" + AltDirectInputDevice.AxisList[i, 1] + "'): Range [" + Device.Axis[i].Range.Minimum + ", " + Device.Axis[i].Range.Maximum + "]" + ", DeadZone = " + Device.Axis[i].Control[m].DeadZone + ", Factor = " + Device.Axis[i].Control[m].Factor + Mappings + ", Inverted = " + Device.Axis[i].Control[m].Inverted); } } #endif } // Process the POV controls for (var i = 0; i < Device.Joystick.Capabilities.PovCount; i++) { for (var j = 0; j < AltDirectInputDevice.NumPOVPositions; j++) { for (var m = 0; m < GameState.NumModes; m++) { if (!Device.enabledModes[m]) continue; Boolean.TryParse(ini.IniReadValue(Section + "." + GameState.ModeName[0], "POV" + (i + 1) + "." + AltDirectInputDevice.POVPositionName[j] + ".Continuous"), out Device.Pov[i].Button[j].Continuous[m]); ParseMapping(Section, "POV" + (i + 1) + "." + AltDirectInputDevice.POVPositionName[j], Device.Pov[i].Button[j].Mapping, m); } } #if (DEBUG) for (var m = 0; m < GameState.NumModes; m++) { if (!Device.enabledModes[m]) continue; String Mappings = ""; for (var j = 0; j < AltDirectInputDevice.NumPOVPositions; j++) Mappings += ((j != 0) ? ", " : "") + AltDirectInputDevice.POVPositionName[j] + " = '" + Device.Pov[i].Button[j].Mapping[m].Action + "', Value = " + Device.Pov[i].Button[j].Mapping[m].Value; print("Altinput: POV #" + (i + 1) + " [" + GameState.ModeName[m] + "]: " + Mappings); } #endif } // Process the buttons for (var i = 0; i < Device.Joystick.Capabilities.ButtonCount; i++) { for (var m = 0; m < GameState.NumModes; m++) { if (!Device.enabledModes[m]) continue; Boolean.TryParse(ini.IniReadValue(Section + "." + GameState.ModeName[m], "Button" + (i + 1) + ".Continuous"), out Device.Button[i].Continuous[m]); ParseMapping(Section, "Button" + (i + 1), Device.Button[i].Mapping, m); } #if (DEBUG) for (var m = 0; m < GameState.NumModes; m++) { if (!Device.enabledModes[m]) continue; String Mappings = "Mapping = '" + Device.Button[i].Mapping[m].Action + "'"; if (Device.Button[i].Mapping[m].Value != 0.0f) Mappings += ", Value = " + Device.Button[i].Mapping[m].Value; print("Altinput: Button #" + (i + 1) + "[" + GameState.ModeName[m] + "]: " + Mappings); } #endif } }
/// <summary> /// Process each input section from the config file /// </summary> void ParseInputs() { String InterfaceName, ClassName; AltDirectInputDevice Device; print("AltInput: (re)loading configuration"); ini = null; DeviceList.Clear(); DetectedList.Clear(); if (!File.Exists(ini_path)) return; ini = new IniFile(ini_path); iniVersion = new System.Version(ini.IniReadValue("global", "Version")); if (iniVersion != currentVersion) return; List<String> sections = ini.IniReadAllSections(); // Remove the [global] and [___.Mode] sections from our list sections.RemoveAll(s => s.Equals("global")); foreach (var modeName in GameState.ModeName) sections.RemoveAll(s => s.EndsWith("." + modeName)); foreach (var dev in directInput.GetDevices(DeviceClass.GameControl, DeviceEnumerationFlags.AllDevices)) { Joystick js = new Joystick(directInput, dev.InstanceGuid); DetectedList.Add("AltInput: Detected Controller '" + dev.InstanceName + "': " + js.Capabilities.AxeCount + " Axes, " + js.Capabilities.ButtonCount + " Buttons, " + js.Capabilities.PovCount + " POV(s)"); foreach(var section in sections) { if (dev.InstanceName.Contains(section)) { InterfaceName = ini.IniReadValue(section, "Interface"); if ((InterfaceName == "") || (ini.IniReadValue(section, "Ignore") == "true")) break; if (InterfaceName != "DirectInput") { print("AltInput[" + section + "]: Only 'DirectInput' is supported for Interface type"); continue; } ClassName = ini.IniReadValue(section, "Class"); if (ClassName == "") ClassName = "GameControl"; else if (ClassName != "GameControl") { print("AltInput[" + section + "]: '" + ClassName + "' is not an allowed Class value"); continue; // ignore the device } // Only add this device if not already in our list if (DeviceList.Where(item => ((AltDirectInputDevice)item).InstanceGuid == dev.InstanceGuid).Any()) continue; Device = new AltDirectInputDevice(directInput, DeviceClass.GameControl, dev.InstanceGuid); SetAttributes(Device, section); DeviceList.Add(Device); print("AltInput: Added controller '" + dev.InstanceName + "'"); } } } }