public void ButtonPressedCallback(IController controller, int button, FlightCtrlState state)
        {
            if(!HighLogic.LoadedSceneIsFlight)
            {
                return;
            }

            var config = m_Configuration.GetConfigurationByIController(controller);

            Bitset mask = controller.GetButtonsMask();

            if (config.evaluatedDiscreteActionMasks.Contains(mask))
            {
                return;
            }

            List<DiscreteAction> actions = config.GetCurrentPreset().GetDiscreteBinding(mask);

            if(actions != null)
            {
                foreach (DiscreteAction action in actions)
                {
                    m_FlightManager.EvaluateDiscreteAction(config, action, state);
                    config.evaluatedDiscreteActionMasks.Add(mask);
                }
            }
        }
        public static List<ControllerPreset> GetDefaultPresets(IController controller)
        {
            List<ControllerPreset> presets = new List<ControllerPreset>();

            #if !LINUX
            if (Utility.CheckXInputSupport() && controller is XInputController)
            {
                presets.Add(GetXInputDefaultRocketPreset(controller));
            }
            #endif

            return presets;
        }
        public void ActivateController(InputWrapper wrapper, int controllerIndex, IController.ButtonPressedCallback pressedCallback, IController.ButtonReleasedCallback releasedCallback)
        {
            foreach (var config in controllers)
            {
                if (config.wrapper == wrapper && config.controllerIndex == controllerIndex)
                {
                    return;
                }
            }

            ControllerConfiguration controller = new ControllerConfiguration();

            controller.wrapper = wrapper;
            controller.controllerIndex = controllerIndex;

            if (Utility.CheckXInputSupport() && wrapper == InputWrapper.XInput)
            {
            #if !LINUX
                controller.iface = new XInputController(controller.controllerIndex);
            #endif
            }
            else if (Utility.CheckSDLSupport() && wrapper == InputWrapper.SDL)
            {
                controller.iface = new SDLController(controller.controllerIndex);
            }
            else  if (wrapper == InputWrapper.KeyboardMouse)
            {
                controller.iface = new KeyboardMouseController();
            }
            else
            {
                // invalid configuration, bail out..
                return;
            }

            controller.SetTreatHatsAsButtons(controller.treatHatsAsButtons);
            controller.iface.analogEvaluationCurve = CurveFactory.Instantiate(controller.analogInputCurve);
            controller.iface.buttonPressedCallback = new IController.ButtonPressedCallback(pressedCallback);
            controller.iface.buttonReleasedCallback = new IController.ButtonReleasedCallback(releasedCallback);

            controller.presets = DefaultControllerPresets.GetDefaultPresets(controller.iface);
            controller.currentPreset = 0;

            controllers.Add(controller);

            ScreenMessages.PostScreenMessage("CONTROLLER: " + controller.iface.GetControllerName(), 1.0f, ScreenMessageStyle.UPPER_CENTER);
        }
        public static ControllerPreset GetXInputDefaultRocketPreset(IController controller)
        {
            ControllerPreset preset = new ControllerPreset();
            preset.name = "XInput Default";

            int buttonsCount = controller.GetButtonsCount();

            #if !LINUX

            preset.SetDiscreteBinding(new Bitset(buttonsCount, (int)XInput.Button.DPadLeft), DiscreteAction.SAS);
            preset.SetDiscreteBinding(new Bitset(buttonsCount, (int)XInput.Button.DPadRight), DiscreteAction.Light);
            preset.SetDiscreteBinding(new Bitset(buttonsCount, (int)XInput.Button.DPadUp), DiscreteAction.RCS);
            preset.SetDiscreteBinding(new Bitset(buttonsCount, (int)XInput.Button.DPadDown), DiscreteAction.Gear);

            preset.SetDiscreteBinding(new Bitset(buttonsCount, (int)XInput.Button.Back), DiscreteAction.Abort);

            preset.SetDiscreteBinding(new Bitset(buttonsCount, (int)XInput.Button.X), DiscreteAction.NextPreset);
            preset.SetDiscreteBinding(new Bitset(buttonsCount, (int)XInput.Button.Y), DiscreteAction.FullThrottle);
            preset.SetDiscreteBinding(new Bitset(buttonsCount, (int)XInput.Button.A), DiscreteAction.Stage);
            preset.SetDiscreteBinding(new Bitset(buttonsCount, (int)XInput.Button.B), DiscreteAction.CutThrottle);

            preset.SetDiscreteBinding(new Bitset(buttonsCount, (int)XInput.Button.LeftStick), DiscreteAction.CameraViewToggle);
            preset.SetDiscreteBinding(new Bitset(buttonsCount, (int)XInput.Button.RightStick), DiscreteAction.NavballToggle);

            preset.SetDiscreteBinding(new Bitset(buttonsCount, (int)XInput.Button.Guide), DiscreteAction.OrbitMapToggle);

            preset.SetContinuousBinding((int)XInput.AnalogInput.LeftStickX, new Bitset(buttonsCount), ContinuousAction.CameraX);
            preset.SetContinuousBinding((int)XInput.AnalogInput.LeftStickY, new Bitset(buttonsCount), ContinuousAction.CameraY);
            preset.SetContinuousBinding((int)XInput.AnalogInput.LeftStickY, new Bitset(buttonsCount, (int)XInput.Button.LB), ContinuousAction.CameraZoom);

            preset.SetContinuousBinding((int)XInput.AnalogInput.RightStickX, new Bitset(buttonsCount), ContinuousAction.Yaw);
            preset.SetContinuousBinding((int)XInput.AnalogInput.RightStickY, new Bitset(buttonsCount), ContinuousAction.Pitch);
            preset.SetContinuousBinding((int)XInput.AnalogInput.RightStickX, new Bitset(buttonsCount, (int)XInput.Button.LB), ContinuousAction.Roll);

            preset.SetContinuousBinding((int)XInput.AnalogInput.RightStickX, new Bitset(buttonsCount, (int)XInput.Button.RB), ContinuousAction.X);
            preset.SetContinuousBinding((int)XInput.AnalogInput.RightStickY, new Bitset(buttonsCount, (int)XInput.Button.RB), ContinuousAction.Y);
            preset.SetContinuousBinding((int)XInput.AnalogInput.RightStickX, new Bitset(buttonsCount, (int)XInput.Button.LB | (int)XInput.Button.RB), ContinuousAction.Z);

            preset.SetContinuousBinding((int)XInput.AnalogInput.LeftTrigger, new Bitset(buttonsCount), ContinuousAction.ThrottleDecrement);
            preset.SetContinuousBinding((int)XInput.AnalogInput.RightTrigger, new Bitset(buttonsCount), ContinuousAction.ThrottleIncrement);

            #endif

            return preset;
        }
        public void ButtonReleasedCallback(IController controller, int button, FlightCtrlState state)
        {
            if (!HighLogic.LoadedSceneIsFlight)
            {
                return;
            }

            var config = m_Configuration.GetConfigurationByIController(controller);

            List<Bitset> masksToRemove = new List<Bitset>();

            foreach (Bitset evaluatedMask in config.evaluatedDiscreteActionMasks)
            {
                for (int i = 0; i < controller.GetButtonsCount(); i++)
                {
                    if (!controller.GetButtonState(i) && evaluatedMask.Get(i))
                   {
                       masksToRemove.Add(evaluatedMask);
                       break;
                   }
                }
            }

            foreach (Bitset maskRemove in masksToRemove)
            {
                config.evaluatedDiscreteActionMasks.Remove(maskRemove);
            }

            if(controller.lastUpdateMask != null)
            {
                foreach (var presetEditor in m_PresetEditors)
                {
                    Bitset bitset = controller.lastUpdateMask.Copy();
                    bitset.Set(button);
                    presetEditor.SetCurrentBitmask(bitset);
                }
            }

            var mask = controller.GetButtonsMask();
            mask.Set(button);
            var actions = config.GetCurrentPreset().GetDiscreteBinding(mask);

            if(actions != null)
            {
                foreach (DiscreteAction action in actions)
                {
                    m_FlightManager.EvaluateDiscreteActionRelease(config, action, state);
                }
            }
        }
        public ControllerConfiguration GetConfigurationByIController(IController controller)
        {
            foreach (ControllerConfiguration config in controllers)
            {
                if(config.iface == controller)
                {
                    return config;
                }
            }

            return null;
        }
        void DoMainWindow(int index)
        {
            GUI.DragWindow(new Rect(0, 0, 10000, 20));

            GUILayout.BeginHorizontal();
            GUILayout.FlexibleSpace();
            if (GUILayout.Button("X", GUILayout.Height(16)))
            {
                m_UIActive = false;
                InputLockManager.RemoveControlLock("AdvancedFlyByWireMainWindow");
            }

            GUILayout.EndHorizontal();

            if (GUILayout.Button("Mod settings"))
            {
                if (m_ModSettings == null)
                {
                    m_ModSettings = new ModSettingsWindow();
                }
            }

            m_ScrollPosition = GUILayout.BeginScrollView(m_ScrollPosition);

            GUILayout.BeginHorizontal();
            GUILayout.FlexibleSpace();
            GUILayout.Label("Controllers");
            GUILayout.FlexibleSpace();
            GUILayout.EndHorizontal();

            var controllers = IController.EnumerateAllControllers();

            foreach (var controller in controllers)
            {
                GUILayout.BeginHorizontal();
                ControllerConfiguration config = m_Configuration.GetConfigurationByControllerType(controller.Key,
                                                                                                  controller.Value.Key);
                bool isEnabled    = config != null && config.iface != null && config.isEnabled;
                bool newIsEnabled = GUILayout.Toggle(isEnabled, "");

                GUILayout.Label(controller.Value.Value);
                GUILayout.FlexibleSpace();

                if (!isEnabled && newIsEnabled)
                {
                    isEnabled = true;
                    m_Configuration.ActivateController
                    (
                        controller.Key,
                        controller.Value.Key,
                        ButtonPressedCallback,
                        ButtonReleasedCallback
                    );
                }
                else if (isEnabled && !newIsEnabled)
                {
                    m_Configuration.DeactivateController(controller.Key, controller.Value.Key);
                }

                if (!isEnabled || config == null || config.presetEditorOpen)
                {
                    GUI.enabled = false;
                }

                if (GUILayout.Button("Presets", GUILayout.Height(32)))
                {
                    if (m_UseOldPresetsWindow)
                    {
                        m_PresetEditors.Add(new PresetEditorWindow(config, m_PresetEditors.Count));
                    }
                    else
                    {
                        m_PresetEditors.Add(new PresetEditorWindowNG(config, m_PresetEditors.Count));
                    }

                    config.presetEditorOpen = true;
                }

                if (isEnabled)
                {
                    GUI.enabled = true;
                }

                if (!isEnabled || config == null || config.controllerConfigurationOpen)
                {
                    GUI.enabled = false;
                }

                if (GUILayout.Button("Configuration", GUILayout.Height(32)))
                {
                    m_ControllerTests.Add(new ControllerConfigurationWindow(config, m_ControllerTests.Count));
                    config.controllerConfigurationOpen = true;
                }

                if (isEnabled)
                {
                    GUI.enabled = true;
                }

                GUILayout.EndHorizontal();

                if (isEnabled && config != null)
                {
                    GUILayout.Space(4);

                    GUILayout.BeginHorizontal();
                    GUILayout.FlexibleSpace();

                    GUILayout.Label("Preset: " + config.GetCurrentPreset().name);

                    if (config.currentPreset <= 0)
                    {
                        GUI.enabled = false;
                    }

                    if (GUILayout.Button("<", GUILayout.Width(32)))
                    {
                        config.currentPreset--;
                    }

                    GUI.enabled = true;
                    GUILayout.Space(4);

                    if (config.currentPreset >= config.presets.Count - 1)
                    {
                        GUI.enabled = false;
                    }

                    if (GUILayout.Button(">", GUILayout.Width(32)))
                    {
                        config.currentPreset++;
                    }

                    GUI.enabled = true;
                    GUILayout.EndHorizontal();
                }

                GUILayout.Space(24);

                GUI.enabled = true;
            }

            GUILayout.EndScrollView();
        }