Multi-touch Slider implementation

Hi team!

I don’t know whether any of you have noticed, but multi-touch devices and multi-value sliders don’t really work nicely together in JUCE. As I see it, the problem is that only one touch is ever considered “active”, so you can’t drag two or more slider thumbs around independently without interference. We could fix this by keeping a record of each active MouseInputSource rather than assuming there can be only one. :person_fencing:

Currently, each input source simply grabs the closest thumb and has its way with it. My initial thought on the desired behaviour is to assign/release thumbs to input sources on a first come, first nearest, first served basis. Does this sound reasonable? Also, does this mean we want to disable further interaction for single value sliders with an already active thumb, for example? I believe so.

I’m not exactly sure why I have a picture in my head of a large team of audio engineers all working on a single plugin’s controls on a large interactive surface, but I do want these people to have the best possible experience.


I’ve created two GitHub pull requests: one to address this specific issue and another as a sister fix for MidiKeyboardComponent.


I have a few questions and thoughts and would really appreciate your feedback.

  1. After wrestling with some decisions, the mouse wheel will now always move the nearest unoccupied thumb, which can result in some exciting yo-yo action when this nearest thumb changes. Any thoughts, concerns or violent objections? I have trouble coming up with a satisfactory alternative right now (but see below for further discussion). I’ve noticed that the original behaviour was only ever moving the core value (in a single or three-value slider), never minValue or maxValue, but in such a context I do miss the ability to mouse wheel over a two-value slider, for instance, and there’s always a chance that value is already taken by a touch event. Personally, I find my current implementation fairly intuitive … not to mention playful and vaguely hypnotic. :candy:
  2. If you use two touch inputs to drag two thumbs of a two-value slider across each other, you can get some tug-of-war style flickering because of value nudging. Perhaps this leads to a larger conversation about thumbs and values…

Thumbs and values

Would anyone find use in a flexible ordering of the thumbs, where e.g. min > max is allowed? One such application is a widget in the style of Vienna Power Pan that allows for inverting of left and right channels, or mapping any range of inputs to inverted outputs; I’m keen to explore this space. Of course this would be an opt-in feature.

How about defining “nudgability” (and “mousewheelability”, etc.) per thumb as part of the slider settings too, with sensible defaults? Obviously nudging makes no sense if values are free to overshoot each other anyway, so there is an interrelationship here to consider when setting everything up.

Dragging value will never nudge (and this aspect is conspicuously absent from the setValue function signature) whereas most other nudging scenarios are automatically permitted where perhaps occasionally they shouldn’t be; in short, there are no doubt situations in which something different is desirable, one way or another, and precise control is lacking. Furthermore, I feel that the semantic assumptions about a three-value slider (namely that value is the single value of interest, while minValue and maxValue define its sliding range within a larger range) may not hold in all use cases.

Finally, this all led me to think that it could be worth introducing a more general system for this, where you could specify any number of slider thumbs and how they look/behave: the nValue[Horizontal/Vertical] Slider. That’s certainly a version 1.5 consideration, but it could inform how some of the refactorings play out in the short term.

Okay, here we go again, even if I’m talking mostly to myself here… :speak_no_evil:

On Windows (at least) there seems to be a system-wide issue of mouse drag and touch not playing nicely together: well, I couldn’t get it to work. However, it’s probably worth pointing out that the mouse wheel actually does a good job, so kudos for that.

Judging from my JUCE experiments, the basic problem seems to be that the disappearing/interrupted mouse dragging events mentioned above are inhibited by a kind of “touch stack”: I say this because the mouse’s mouseUp isn’t triggered until after all the touch events have ended, even if the mouse button is released much earlier, and will be triggered even if the mouse button is still down. In other words, the mouse drag lifetime is immediately terminated by adding a mouseUp “cap” to an event queue, and then burying this queue under a layer of touch events until all the fingers have gone. I’ve seen the first touch drag steal data from the mouse drag too, so a kind of passing of the baton can occur during this exchange. This is certainly beyond the scope of the Slider class so I’ve not yet journeyed down such a rabbit hole, but I suppose this means that the workaround (to remove mouse inputs pro-actively as touch inputs appear) could be in order to prevent a mouse drag uselessly hanging on to a slider thumb.

Also in the world of disappointments, I wanted to experiment with pen input in the mix, but HP’s current notion of palm rejection is essentially “nuke all mouse and touch inputs until the pen has left the building”. Aside from this policy, I see no reason why it shouldn’t work as intended in a more permissive society.