diff --git a/Joysticks/octavi/octavi.joystick.json b/Joysticks/octavi/octavi.joystick.json index c285d06c7..675b30f87 100644 --- a/Joysticks/octavi/octavi.joystick.json +++ b/Joysticks/octavi/octavi.joystick.json @@ -66,7 +66,12 @@ "Id": "AP.VS", "Byte": 1, "Bit": 5 + }, + { + "Label": "Blink Context", + "Id": "CS.SH", + "Byte": 1, + "Bit": 6 } - ] } diff --git a/MobiFlight/Joysticks/Octavi/OctaviHandler.cs b/MobiFlight/Joysticks/Octavi/OctaviHandler.cs index 3562f65df..f9ff068a9 100644 --- a/MobiFlight/Joysticks/Octavi/OctaviHandler.cs +++ b/MobiFlight/Joysticks/Octavi/OctaviHandler.cs @@ -6,6 +6,9 @@ namespace MobiFlight.Joysticks.Octavi { internal class OctaviHandler { + private const string Shift_VButton_Name = "Button_SHIFT_SW"; + private const string Unshift_VButton_Name = "Button_UNSHIFT_SW"; + private bool isInShiftMode = false; private OctaviReport lastReport = new OctaviReport(); private readonly List buttons = new List(); @@ -54,6 +57,16 @@ public OctaviHandler(JoystickDefinition definition = null) var context = new Context(state, true, stateName + "^"); this.contexts.Add(context); } + + /* create at least one instance for the Buttons for the virtual (un)shift events on context change. + * always created first to keep them together in the Button list. + * (shift button will only be called from the buttonmapping later, + * unshift either virtually without context or from the mapping) + */ + _ = ToButton(Shift_VButton_Name); + _ = ToButton(Unshift_VButton_Name); + + foreach (var context in contexts) { // Encoders @@ -69,6 +82,22 @@ public OctaviHandler(JoystickDefinition definition = null) if (!definition.Inputs.Any(JoystickInput => JoystickInput.Id == (int) context.state)) { buttonMappings.Add((context.state, context.isShifted, OctaviReport.OctaviButtons.HID_ENC_SW), ToButton($"Button_{context.name}_CRSR")); + + /* do not create the unshift button in the mapping, will be a duplicate key in the dictionary. + * will be called with the buttons.IndexOf method later in this "virtual" case. + */ + //buttonMappings.Add((context.state, context.isShifted, OctaviReport.OctaviButtons.HID_ENC_SW), ToButton(Unshift_VButton_Name)); + } + else + { + /* Will be used to raise the "we are shifted now" flag + * Can be used to control a "shifted" variable that turns output pin 7 on/off + * We need two buttons, because context switching forces "unshifting", + * so the shift state always has to be sent explicitly + * (i.e. not a variable that will be toggled when a single button is pressed can be used) + * States that do not support a shift mode will always be "unshifted". + */ + buttonMappings.Add((context.state, context.isShifted, OctaviReport.OctaviButtons.HID_ENC_SW), ToButton(context.isShifted ? Shift_VButton_Name : Unshift_VButton_Name)); } // DCT, MENU, CLR, ENT, CDI, OBS, MSG, FLP, VNAV, PROC @@ -86,6 +115,9 @@ public OctaviHandler(JoystickDefinition definition = null) buttonMappings.Add((context.state, context.isShifted, OctaviReport.OctaviButtons.HID_BTN_AP_ALT), ToButton($"Button_{context.name}_VNAV")); buttonMappings.Add((context.state, context.isShifted, OctaviReport.OctaviButtons.HID_BTN_AP_VS), ToButton($"Button_{context.name}_PROC")); } + /* else: why can't we use these buttons out of FMS-States? + * e.g. Context COM1 Button -D-> could be used to set the radio to VATSIM Unicom "122.800" + */ // AP, HDG, NAV, APR, ALT, VS (AP context only for now to not mess up the ordering of buttons) if (context.state == OctaviReport.OctaviState.STATE_AP) @@ -137,10 +169,20 @@ private int ToButton(string buttonName) // "Shift Mode" for supported contexts if (report.contextState != lastReport.contextState) { - isInShiftMode = false; // reset shift mode on context change + // reset shift mode on context changes (and synthesize unshift press/release) + int unshift_vButton = buttons.IndexOf(Unshift_VButton_Name); + + if (unshift_vButton >= 0) + { + buttonEvents.Add((unshift_vButton, MobiFlightButton.InputEvent.PRESS)); + buttonEvents.Add((unshift_vButton, MobiFlightButton.InputEvent.RELEASE)); + } + + isInShiftMode = false; } else if (pressed.HasFlag(OctaviReport.OctaviButtons.HID_ENC_SW) && this.definition.Inputs.Any(JoystickInput => JoystickInput.Id == (int)report.contextState)) { + /* Button events will be generated by finding the corrensponding ButtonMapping in the loop at the end. */ isInShiftMode = !isInShiftMode; }