The reason the driver for APC Key 25 mkII works so nicely re. the keyboard (and sustain), is that the device is actually two devices. So the driver just works on the first device, and the second is left alone (except that some notes are also listened to from within the driver in order to get the StepSeq submode to work (assigning notes to pads, which can in turn be used to create patterns).
Now I am working on porting (by subclassing) that driver to its predecessor, which is just listed as a single device, with the keybed and sustain over MIDI channel 1 (zero based), and the rest over MIDI channel 0, so there I am encountering kind of the same challenges.
There is this class property (if that is correct Python parlance):
unroute_from_chains = False
This will leave all normal Zynthian plumbing intact. This in turn is is not interceptible however: when I e.g. set a breakpoint in midi_event, the note will sound before.
And when you set it to True, I do not see a way to still let it be processed. It looks like you said, that returning False (or True) from the driver that it will be processed, but I just tried both, and I notice no difference.
What I am now doing is sending all channel 1 events directly to libseq, see below. It does not have any fancy handling for when a note on is sent, and then the chain switches (so no note off ever arrives) (and I don’t know yet how to get the last ‘MIDI playable’ chain (e.g. if you are on an instrument chain and then switch to an Audio chain, the last chain normally still receives the events). And this also does not reach live pattern recording. So this is all quite suboptimal, so having something like you described (return value from midi_event dictating whether we do want subsequent processing or not) would be ideal*.
# Direct keybed to chains
if (channel == 1):
chain = self.chain_manager.get_active_chain()
# print(chain.midi_chan)
# @todo: find out how to get 'last' active chain, for now: just back out.
if chain.midi_chan is None:
return
status = (ev[0] & 0xF0) | chain.midi_chan
self.zynseq.libseq.sendMidiCommand(status, ev[1], ev[2])
return
return super()._on_midi_event(ev)`
*For my case, what would also work is if we could declaratively ‘unroute’ only a certain channel.