Skip to content

Commit

Permalink
Optional Arrow Keys for Slider/Button Editors (surge-synthesizer#5636)
Browse files Browse the repository at this point in the history
As part of surge-synthesizer#4616, I learned that even though the accesibility
API has a well defined setvalue method which works, many accessible
users use arrow keys to adjust values. So this commit does three things

1. Makes widget focus follow tab order
2. Makes an optional arrow key to edit slider, button, number field, etc...
3. Make a system wide default for that which like the other kbd mods
   is off by default plugin and on standalone.

More to do here but I want to get this into the hands of the accesibility
testers so merging at this checkpoint.
  • Loading branch information
baconpaul authored Dec 16, 2021
1 parent fb90f20 commit bfd8736
Show file tree
Hide file tree
Showing 17 changed files with 347 additions and 5 deletions.
6 changes: 6 additions & 0 deletions src/common/UserDefaults.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,12 @@ void initMaps()
case UseKeyboardShortcuts_Standalone:
r = "useKeyboardShortcutsStandalone";
break;
case UseKeyboardAccEditors_Plugin:
r = "useKeyboardAccEditorsPlugin";
break;
case UseKeyboardAccEditors_Standalone:
r = "useKeyboardAccEditorsStandalone";
break;
case InfoWindowPopupOnIdle:
r = "infoWindowPopupOnIdle";
break;
Expand Down
4 changes: 4 additions & 0 deletions src/common/UserDefaults.h
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,10 @@ enum DefaultKey // streamed as strings so feel free to change the order to whate
UseKeyboardShortcuts_Plugin,
UseKeyboardShortcuts_Standalone,

// These allow arrow keys to edit sliders, switches, etc...
UseKeyboardAccEditors_Plugin,
UseKeyboardAccEditors_Standalone,

TuningOverlayLocation,
ModlistOverlayLocation,
MSEGOverlayLocation,
Expand Down
1 change: 1 addition & 0 deletions src/surge-xt/gui/SurgeGUICallbackInterfaces.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ struct IComponentTagValue
virtual float getValue() const = 0;
virtual void setValue(float) = 0;

virtual void startHover(const juce::Point<float> &) {}
virtual void endHover() {}

juce::Component *asJuceComponent()
Expand Down
68 changes: 68 additions & 0 deletions src/surge-xt/gui/SurgeGUIEditor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -287,11 +287,39 @@ class DroppedUserDataHandler
};

Surge::GUI::ModulationGrid *Surge::GUI::ModulationGrid::grid = nullptr;
/*
* See the comment in SurgeGUIUtils.cpp
*/
namespace Surge
{
namespace GUI
{
extern void setIsStandalone(bool b);
}
} // namespace Surge

#ifdef DEBUG_FOCUS
struct FocusDebugListener : public juce::FocusChangeListener
{
void globalFocusChanged(juce::Component *fc) override
{
std::cout << "FC [" << fc << "] ";
if (fc)
std::cout << fc->getTitle() << " " << typeid(*fc).name();
std::cout << std::endl;
}
};
#endif

SurgeGUIEditor::SurgeGUIEditor(SurgeSynthEditor *jEd, SurgeSynthesizer *synth)
{
jassert(Surge::GUI::ModulationGrid::getModulationGrid());

#ifdef DEBUG_FOCUS
// it's just debug who cares about the leak (for now)
juce::Desktop::getInstance().addFocusChangeListener(new FocusDebugListener());
#endif

assert(n_paramslots >= n_total_params);
synth->storage.addErrorListener(this);
synth->storage.okCancelProvider = [](const std::string &msg, const std::string &title,
Expand Down Expand Up @@ -327,6 +355,9 @@ SurgeGUIEditor::SurgeGUIEditor(SurgeSynthEditor *jEd, SurgeSynthesizer *synth)
juceEditor = jEd;
this->synth = synth;

Surge::GUI::setIsStandalone(juceEditor->processor.wrapperType ==
juce::AudioProcessor::wrapperType_Standalone);

minimumZoom = 50;
#if LINUX
minimumZoom = 100; // See github issue #628
Expand Down Expand Up @@ -3410,6 +3441,11 @@ juce::PopupMenu SurgeGUIEditor::makeWorkflowMenu(const juce::Point<int> &where)
wfMenu.addItem(Surge::GUI::toOSCaseForMenu("Use Keyboard Shortcuts"), true, kbShortcuts,
[this]() { toggleUseKeyboardShortcuts(); });

bool kbAcc = getUseKeyboardAccEditors();

wfMenu.addItem(Surge::GUI::toOSCaseForMenu("Arrow Keys Modify Values"), true, kbAcc,
[this]() { toggleUseKeyboardAccEditors(); });

wfMenu.addSeparator();

bool showVirtualKeyboard = getShowVirtualKeyboard();
Expand Down Expand Up @@ -3456,6 +3492,37 @@ void SurgeGUIEditor::toggleVirtualKeyboard()
resizeWindow(zoomFactor);
}

bool SurgeGUIEditor::getUseKeyboardAccEditors()
{
auto key = Surge::Storage::UseKeyboardAccEditors_Plugin;
bool defaultVal = false;

if (juceEditor->processor.wrapperType == juce::AudioProcessor::wrapperType_Standalone)
{
key = Surge::Storage::UseKeyboardAccEditors_Standalone;
defaultVal = true;
}

return Surge::Storage::getUserDefaultValue(&(this->synth->storage), key, defaultVal);
}

void SurgeGUIEditor::setUseKeyboardAccEditors(bool b)
{
auto key = Surge::Storage::UseKeyboardAccEditors_Plugin;

if (juceEditor->processor.wrapperType == juce::AudioProcessor::wrapperType_Standalone)
{
key = Surge::Storage::UseKeyboardAccEditors_Standalone;
}

Surge::Storage::updateUserDefaultValue(&(this->synth->storage), key, b);
}

void SurgeGUIEditor::toggleUseKeyboardAccEditors()
{
setUseKeyboardAccEditors(!getUseKeyboardAccEditors());
}

bool SurgeGUIEditor::getUseKeyboardShortcuts()
{
auto key = Surge::Storage::UseKeyboardShortcuts_Plugin;
Expand Down Expand Up @@ -4898,6 +4965,7 @@ SurgeGUIEditor::layoutComponentForSkin(std::shared_ptr<Surge::GUI::Skin::Control
if (std::get<0>(drawables))
{
auto hsw = componentForSkinSession<Surge::Widgets::Switch>(skinCtrl->sessionid);
hsw->setStorage(&(synth->storage));
if (p)
{
addAndMakeVisibleWithTrackingInCG(p->ctrlgroup, *hsw);
Expand Down
4 changes: 4 additions & 0 deletions src/surge-xt/gui/SurgeGUIEditor.h
Original file line number Diff line number Diff line change
Expand Up @@ -693,6 +693,10 @@ class SurgeGUIEditor : public Surge::GUI::IComponentTagValue::Listener,
void setUseKeyboardShortcuts(bool b);
void toggleUseKeyboardShortcuts();

bool getUseKeyboardAccEditors();
void setUseKeyboardAccEditors(bool b);
void toggleUseKeyboardAccEditors();

private:
bool scannedForMidiPresets = false;

Expand Down
29 changes: 29 additions & 0 deletions src/surge-xt/gui/SurgeGUIUtils.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#include "SurgeGUIUtils.h"

#include "juce_core/juce_core.h"
#include "UserDefaults.h"

#if LINUX
#include <sys/types.h>
Expand Down Expand Up @@ -37,6 +38,34 @@ bool showCursor(SurgeStorage *storage)
return sc || tm;
};

/*
* We kinda want to know if we are standalone here, but don't have reference to the processor
* but that's a constant for a process (you can't mix standalone and not) so make it a static
* and explicitly grab this symbol in the SGE startup path
*/
static bool isStandalone{false};
void setIsStandalone(bool b) { isStandalone = b; }

bool allowKeyboardEdits(SurgeStorage *storage)
{
if (!storage)
return false;

bool res{false};
if (isStandalone)
{
res = Surge::Storage::getUserDefaultValue(
storage, Surge::Storage::UseKeyboardAccEditors_Standalone, true);
}
else
{
res = Surge::Storage::getUserDefaultValue(
storage, Surge::Storage::UseKeyboardAccEditors_Plugin, false);
}

return res;
}

// Returns 1 if the lines intersect, otherwise 0. In addition, if the lines
// intersect, the intersection point may be stored in the floats i_x and i_y.
bool get_line_intersection(float p0_x, float p0_y, float p1_x, float p1_y, float p2_x, float p2_y,
Expand Down
1 change: 1 addition & 0 deletions src/surge-xt/gui/SurgeGUIUtils.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ namespace GUI
std::string toOSCaseForMenu(const std::string &menuName);

extern bool showCursor(SurgeStorage *storage);
extern bool allowKeyboardEdits(SurgeStorage *storage);

bool get_line_intersection(float p0_x, float p0_y, float p1_x, float p1_y, float p2_x, float p2_y,
float p3_x, float p3_y, float *i_x, float *i_y);
Expand Down
29 changes: 29 additions & 0 deletions src/surge-xt/gui/widgets/MenuForDiscreteParams.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -342,5 +342,34 @@ std::unique_ptr<juce::AccessibilityHandler> MenuForDiscreteParams::createAccessi
return std::make_unique<DiscreteAH<MenuForDiscreteParams>>(this);
}
#endif

bool MenuForDiscreteParams::keyPressed(const juce::KeyPress &key)
{
if (!Surge::GUI::allowKeyboardEdits(storage))
return false;

bool got{false};
int dir = -1;
if (key.getKeyCode() == juce::KeyPress::leftKey || key.getKeyCode() == juce::KeyPress::downKey)
{
got = true;
}
if (key.getKeyCode() == juce::KeyPress::rightKey || key.getKeyCode() == juce::KeyPress::upKey)
{
got = true;
dir = 1;
}

if (got)
{
notifyBeginEdit();
setValue(nextValueInOrder(value, -dir));
notifyValueChanged();
notifyEndEdit();
repaint();
}
return got;
}

} // namespace Widgets
} // namespace Surge
17 changes: 17 additions & 0 deletions src/surge-xt/gui/widgets/MenuForDiscreteParams.h
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,11 @@ struct MenuForDiscreteParams : public juce::Component,

void mouseExit(const juce::MouseEvent &event) override { endHover(); }

void startHover(const juce::Point<float> &p) override
{
isHovered = true;
repaint();
}
void endHover() override
{
isHovered = false;
Expand All @@ -129,6 +134,18 @@ struct MenuForDiscreteParams : public juce::Component,
repaint();
}

bool keyPressed(const juce::KeyPress &key) override;
void focusGained(juce::Component::FocusChangeType cause) override
{
startHover(getBounds().getBottomLeft().toFloat());
repaint();
}
void focusLost(juce::Component::FocusChangeType cause) override
{
endHover();
repaint();
}

juce::Point<int> mouseDownOrigin;
bool isDraggingGlyph{false};
float lastDragDistance{0};
Expand Down
46 changes: 44 additions & 2 deletions src/surge-xt/gui/widgets/ModulatableSlider.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -333,9 +333,10 @@ void ModulatableSlider::onSkinChanged()
#endif
}

void ModulatableSlider::mouseEnter(const juce::MouseEvent &event)
void ModulatableSlider::mouseEnter(const juce::MouseEvent &event) { startHover(event.position); }
void ModulatableSlider::startHover(const juce::Point<float> &p)
{
enqueueFutureInfowindow(SurgeGUIEditor::InfoQAction::START, event.position);
enqueueFutureInfowindow(SurgeGUIEditor::InfoQAction::START, p);
isHovered = true;
auto sge = firstListenerOfType<SurgeGUIEditor>();
if (sge)
Expand Down Expand Up @@ -671,5 +672,46 @@ std::unique_ptr<juce::AccessibilityHandler> ModulatableSlider::createAccessibili
}
#endif

bool ModulatableSlider::keyPressed(const juce::KeyPress &key)
{
if (!Surge::GUI::allowKeyboardEdits(storage))
return false;

bool got{false};
float dv{0};
if (key.getKeyCode() == juce::KeyPress::leftKey)
{
got = true;
dv = -0.05;
}
if (key.getKeyCode() == juce::KeyPress::rightKey)
{
got = true;
dv = 0.05;
}

if (got)
{
if (key.getModifiers().isShiftDown())
dv *= 0.1;

if (isEditingModulation)
{
modValue = limitpm1(modValue + dv);
}
else
{
value = limit01(value + dv);
}

notifyBeginEdit();
notifyValueChanged();
updateInfowindowContents(isEditingModulation);
notifyEndEdit();
repaint();
}
return got;
}

} // namespace Widgets
} // namespace Surge
13 changes: 12 additions & 1 deletion src/surge-xt/gui/widgets/ModulatableSlider.h
Original file line number Diff line number Diff line change
Expand Up @@ -79,8 +79,19 @@ struct ModulatableSlider : public juce::Component,
void mouseDoubleClick(const juce::MouseEvent &event) override;
void mouseWheelMove(const juce::MouseEvent &event,
const juce::MouseWheelDetails &wheel) override;
void startHover(const juce::Point<float> &) override;
void endHover() override;

bool keyPressed(const juce::KeyPress &key) override;
void focusGained(juce::Component::FocusChangeType cause) override
{
startHover(getBounds().getBottomLeft().toFloat());
repaint();
}
void focusLost(juce::Component::FocusChangeType cause) override
{
endHover();
repaint();
}
SurgeStorage *storage{nullptr};
void setStorage(SurgeStorage *s) { storage = s; }

Expand Down
6 changes: 4 additions & 2 deletions src/surge-xt/gui/widgets/MultiSwitch.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -179,9 +179,11 @@ void MultiSwitch::mouseUp(const juce::MouseEvent &event)
}
}

void MultiSwitch::mouseEnter(const juce::MouseEvent &event)
void MultiSwitch::mouseEnter(const juce::MouseEvent &event) { startHover(event.position); }

void MultiSwitch::startHover(const juce::Point<float> &p)
{
hoverSelection = coordinateToSelection(event.x, event.y);
hoverSelection = coordinateToSelection(p.x, p.y);

isHovered = true;
}
Expand Down
12 changes: 12 additions & 0 deletions src/surge-xt/gui/widgets/MultiSwitch.h
Original file line number Diff line number Diff line change
Expand Up @@ -74,8 +74,20 @@ struct MultiSwitch : public juce::Component, public WidgetBaseMixin<MultiSwitch>
void mouseUp(const juce::MouseEvent &event) override;
void setCursorToArrow();

void startHover(const juce::Point<float> &) override;
void endHover() override;

void focusGained(juce::Component::FocusChangeType cause) override
{
// fixme - probably use the location of the current element
startHover(getBounds().getBottomLeft().toFloat());
repaint();
}
void focusLost(juce::Component::FocusChangeType cause) override
{
endHover();
repaint();
}
Surge::GUI::WheelAccumulationHelper wheelHelper;
void mouseWheelMove(const juce::MouseEvent &event,
const juce::MouseWheelDetails &wheel) override;
Expand Down
Loading

0 comments on commit bfd8736

Please sign in to comment.