Tuesday 14 June 2016

Keyboard Controller working!

Last week I have been working on making the keyboard controller functional, and I have made some good progress. Although the controls are still set in the keyboard event filter (which will be moved to the keyboard controller very soon), the mapping info is not owned by the keyboard event filter anymore. It's now owned by the keyboard controller preset, which stores the key combinations with the actions that it should trigger. As soon as a new preset is loaded, the keyboard event filter is sent a signal and gets updated about the new preset.

Keyboard preset format

The presets the keyboard controller uses are instances of KeyboardControllerPreset, which rely on *.kbd.xml files. These XML files start of with an info block.
<?xml version="1.0" encoding="utf-8"?>

<MixxxKeyboardPreset schemaVersion="1" mixxxVersion="2.0.0+">
  <info>
    <name>Keyboard Default</name>
    <author>Mixxx</author>
    <description>Default keyboard mapping.</description>
    <wiki>mixxx.org/.../appendix.html#appendix-keyboard</wiki>
  </info>
This <infoblock is required, otherwise it won't even get enumerated and thus will not be listed as a legitimate preset. The block's format is basically the same as for each preset of each other controller type. Though some presets also include <forumsand <devices>, I believe that that information doesn't apply for keyboard presets. However, if I'm proven wrong and we do need those, it can be added really easily.

The data where it all goes about is in the <controllerblock, which contains <groupnodes, listing <controlnodes holding information about which key sequence triggers what action.
<controller>
    <group name="[AutoDJ]">
      <control action="shuffle_playlist" keyseq="Shift+F9" />
      <control action="skip_next" keyseq="Shift+F10" />
      <control action="fade_now" keyseq="Shift+F11" />
      <control action="enabled" keyseq="Shift+F12" />
    </group>

    <group name="[Master]">
      <control action="crossfader_up" keyseq="h" />
      <control action="crossfader_down" keyseq="g" />
      <control action="crossfader_up_small" keyseq="Shift+h" />
      <control action="crossfader_down_small" keyseq="Shift+g" />
    </group>

    <group name="[Microphone]">
      <control action="talkover" keyseq="`" />
    </group>

    <group name="[PreviewDeck1]">
      <control action="LoadSelectedAndPlay" keyseq="Alt+Return" />
      <control action="start_stop" keyseq="Return" />
      <control action="back" keyseq="Alt+Left" />
      <control action="fwd" keyseq="" />
    </group>

    <group name="[Channel1]">
      <control action="play" keyseq="d" />
      <control action="cue_set" keyseq="Shift+d" />
      <control action="cue_default" keyseq="f" />
      <control action="cue_gotoandstop" keyseq="Shift+f" />
    </group>

    <!-- etc... -->

Keyboard preset file handler

The XML file is firstly enumerated by PresetInfoEnumerator, which was added the new preset extension. Then, when the user navigates to the keyboard controller in controller preferences and then selects a preset, the XML document is parsed by KeyboardPresetFileHandler. Each action is read and is stored in a multihash, from which the key is the key sequence (ConfigValueKbd), and the values are the bound actions (ConfigKey). The keyboard preset file handler is not only responsible for loading,  but also for saving presets, where it does basically the same task, but then in reverse.