Use more generic 'hooks' for each input device's actions

custom
jacqueline 1 year ago
parent c24dfa6846
commit 1baaa6dadc
  1. 3
      src/input/CMakeLists.txt
  2. 47
      src/input/include/input_hook.hpp
  3. 28
      src/input/include/input_hook_actions.hpp
  4. 5
      src/input/include/input_nav_buttons.hpp
  5. 11
      src/input/include/input_touch_dpad.hpp
  6. 10
      src/input/include/input_touch_wheel.hpp
  7. 6
      src/input/include/input_volume_buttons.hpp
  8. 66
      src/input/input_hook.cpp
  9. 52
      src/input/input_hook_actions.cpp
  10. 32
      src/input/input_nav_buttons.cpp
  11. 67
      src/input/input_touch_dpad.cpp
  12. 56
      src/input/input_touch_wheel.cpp
  13. 23
      src/input/input_volume_buttons.cpp

@ -5,7 +5,8 @@
idf_component_register(
SRCS "input_touch_wheel.cpp" "input_touch_dpad.cpp" "input_trigger.cpp"
"input_volume_buttons.cpp" "lvgl_input_driver.cpp" "feedback_haptics.cpp"
"device_factory.cpp" "input_nav_buttons.cpp"
"device_factory.cpp" "input_nav_buttons.cpp" "input_hook.cpp"
"input_hook_actions.cpp"
INCLUDE_DIRS "include"
REQUIRES "drivers" "lvgl" "events" "system_fsm")

@ -0,0 +1,47 @@
/*
* Copyright 2024 jacqueline <me@jacqueline.id.au>
*
* SPDX-License-Identifier: GPL-3.0-only
*/
#pragma once
#include <functional>
#include <optional>
#include "hal/lv_hal_indev.h"
#include "input_trigger.hpp"
namespace input {
using HookCb = std::optional<std::function<void(lv_indev_data_t*)>>;
class Hook {
public:
Hook(HookCb);
auto invoke(lv_indev_data_t*) -> void;
auto override(HookCb) -> void;
private:
HookCb default_;
HookCb override_;
};
class TriggerHooks {
public:
TriggerHooks(HookCb cb) : TriggerHooks(cb, cb, cb) {}
TriggerHooks(HookCb, HookCb, HookCb);
auto update(bool, lv_indev_data_t*) -> void;
auto override(Trigger::State, HookCb) -> void;
private:
Trigger trigger_;
Hook click_;
Hook long_press_;
Hook repeat_;
};
} // namespace input

@ -0,0 +1,28 @@
/*
* Copyright 2024 jacqueline <me@jacqueline.id.au>
*
* SPDX-License-Identifier: GPL-3.0-only
*/
#pragma once
#include "hal/lv_hal_indev.h"
namespace input {
namespace actions {
auto select(lv_indev_data_t*) -> void;
auto scrollUp(lv_indev_data_t*) -> void;
auto scrollDown(lv_indev_data_t*) -> void;
auto scrollToTop(lv_indev_data_t*) -> void;
auto scrollToBottom(lv_indev_data_t*) -> void;
auto goBack(lv_indev_data_t*) -> void;
auto volumeUp(lv_indev_data_t*) -> void;
auto volumeDown(lv_indev_data_t*) -> void;
} // namespace actions
} // namespace input

@ -13,6 +13,7 @@
#include "haptics.hpp"
#include "input_device.hpp"
#include "input_hook.hpp"
#include "input_trigger.hpp"
#include "touchwheel.hpp"
@ -27,8 +28,8 @@ class NavButtons : public IInputDevice {
private:
drivers::IGpios& gpios_;
Trigger up_;
Trigger down_;
TriggerHooks up_;
TriggerHooks down_;
};
} // namespace input

@ -6,13 +6,13 @@
#pragma once
#include <stdint.h>
#include <cstdint>
#include "hal/lv_hal_indev.h"
#include "haptics.hpp"
#include "input_device.hpp"
#include "input_hook.hpp"
#include "input_trigger.hpp"
#include "touchwheel.hpp"
@ -27,10 +27,11 @@ class TouchDPad : public IInputDevice {
private:
drivers::TouchWheel& wheel_;
Trigger up_;
Trigger right_;
Trigger down_;
Trigger left_;
TriggerHooks centre_;
TriggerHooks up_;
TriggerHooks right_;
TriggerHooks down_;
TriggerHooks left_;
};
} // namespace input

@ -13,6 +13,7 @@
#include "haptics.hpp"
#include "input_device.hpp"
#include "input_hook.hpp"
#include "input_trigger.hpp"
#include "nvs.hpp"
#include "property.hpp"
@ -37,10 +38,11 @@ class TouchWheel : public IInputDevice {
lua::Property sensitivity_;
Trigger up_;
Trigger right_;
Trigger down_;
Trigger left_;
TriggerHooks centre_;
TriggerHooks up_;
TriggerHooks right_;
TriggerHooks down_;
TriggerHooks left_;
bool is_scrolling_;
uint8_t threshold_;

@ -13,7 +13,7 @@
#include "haptics.hpp"
#include "input_device.hpp"
#include "input_trigger.hpp"
#include "input_hook.hpp"
#include "touchwheel.hpp"
namespace input {
@ -27,8 +27,8 @@ class VolumeButtons : public IInputDevice {
private:
drivers::IGpios& gpios_;
Trigger up_;
Trigger down_;
TriggerHooks up_;
TriggerHooks down_;
};
} // namespace input

@ -0,0 +1,66 @@
/*
* Copyright 2024 jacqueline <me@jacqueline.id.au>
*
* SPDX-License-Identifier: GPL-3.0-only
*/
#include "input_hook.hpp"
#include <functional>
#include <optional>
#include "hal/lv_hal_indev.h"
namespace input {
Hook::Hook(HookCb fn) : default_(fn), override_() {}
auto Hook::invoke(lv_indev_data_t* d) -> void {
if (override_) {
std::invoke(*override_, d);
} else if (default_) {
std::invoke(*default_, d);
}
}
auto Hook::override(HookCb fn) -> void {
override_ = fn;
}
TriggerHooks::TriggerHooks(HookCb click, HookCb long_press, HookCb repeat)
: click_(click), long_press_(long_press), repeat_(repeat) {}
auto TriggerHooks::update(bool pressed, lv_indev_data_t* d) -> void {
switch (trigger_.update(pressed)) {
case Trigger::State::kClick:
click_.invoke(d);
break;
case Trigger::State::kLongPress:
long_press_.invoke(d);
break;
case Trigger::State::kRepeatPress:
repeat_.invoke(d);
break;
case Trigger::State::kNone:
default:
break;
}
}
auto TriggerHooks::override(Trigger::State s, HookCb fn) -> void {
switch (s) {
case Trigger::State::kClick:
click_.override(fn);
break;
case Trigger::State::kLongPress:
long_press_.override(fn);
break;
case Trigger::State::kRepeatPress:
repeat_.override(fn);
break;
case Trigger::State::kNone:
default:
break;
}
}
} // namespace input

@ -0,0 +1,52 @@
/*
* Copyright 2024 jacqueline <me@jacqueline.id.au>
*
* SPDX-License-Identifier: GPL-3.0-only
*/
#include "input_hook_actions.hpp"
#include <cstdint>
#include "hal/lv_hal_indev.h"
#include "event_queue.hpp"
#include "ui_events.hpp"
namespace input {
namespace actions {
auto select(lv_indev_data_t* d) -> void {
d->state = LV_INDEV_STATE_PRESSED;
}
auto scrollUp(lv_indev_data_t* d) -> void {
d->enc_diff = -1;
}
auto scrollDown(lv_indev_data_t* d) -> void {
d->enc_diff = 1;
}
auto scrollToTop(lv_indev_data_t* d) -> void {
d->enc_diff = INT16_MIN;
}
auto scrollToBottom(lv_indev_data_t* d) -> void {
d->enc_diff = INT16_MAX;
}
auto goBack(lv_indev_data_t* d) -> void {
events::Ui().Dispatch(ui::internal::BackPressed{});
}
auto volumeUp(lv_indev_data_t* d) -> void {
events::Audio().Dispatch(audio::StepUpVolume{});
}
auto volumeDown(lv_indev_data_t* d) -> void {
events::Audio().Dispatch(audio::StepDownVolume{});
}
} // namespace actions
} // namespace input

@ -9,36 +9,18 @@
#include "event_queue.hpp"
#include "gpios.hpp"
#include "hal/lv_hal_indev.h"
#include "input_hook_actions.hpp"
namespace input {
NavButtons::NavButtons(drivers::IGpios& gpios) : gpios_(gpios) {}
NavButtons::NavButtons(drivers::IGpios& gpios)
: gpios_(gpios),
up_(actions::scrollUp, actions::select, {}),
down_(actions::scrollDown, actions::select, {}) {}
auto NavButtons::read(lv_indev_data_t* data) -> void {
bool vol_up = gpios_.Get(drivers::IGpios::Pin::kKeyUp);
switch (up_.update(!vol_up)) {
case Trigger::State::kClick:
data->enc_diff = -1;
break;
case Trigger::State::kLongPress:
events::Ui().Dispatch(ui::internal::BackPressed{});
break;
default:
break;
}
bool vol_down = gpios_.Get(drivers::IGpios::Pin::kKeyDown);
switch (down_.update(!vol_down)) {
case Trigger::State::kClick:
data->enc_diff = 1;
break;
case Trigger::State::kLongPress:
data->state = LV_INDEV_STATE_PRESSED;
break;
default:
data->state = LV_INDEV_STATE_RELEASED;
break;
}
up_.update(!gpios_.Get(drivers::IGpios::Pin::kKeyUp), data);
down_.update(!gpios_.Get(drivers::IGpios::Pin::kKeyDown), data);
}
} // namespace input

@ -13,63 +13,42 @@
#include "event_queue.hpp"
#include "haptics.hpp"
#include "input_device.hpp"
#include "input_hook_actions.hpp"
#include "input_touch_dpad.hpp"
#include "touchwheel.hpp"
namespace input {
static inline auto IsAngleWithin(int16_t wheel_angle,
int16_t target_angle,
int threshold) -> bool {
int16_t difference = (wheel_angle - target_angle + 127 + 255) % 255 - 127;
return difference <= threshold && difference >= -threshold;
}
TouchDPad::TouchDPad(drivers::TouchWheel& wheel) : wheel_(wheel) {}
TouchDPad::TouchDPad(drivers::TouchWheel& wheel)
: wheel_(wheel),
centre_(actions::select, {}, {}),
up_(actions::scrollUp),
right_({}, {}, {}),
down_(actions::scrollDown),
left_(actions::goBack) {}
auto TouchDPad::read(lv_indev_data_t* data) -> void {
wheel_.Update();
auto wheel_data = wheel_.GetTouchWheelData();
if (wheel_data.is_button_touched) {
data->state = LV_INDEV_STATE_PRESSED;
} else {
data->state = LV_INDEV_STATE_RELEASED;
}
centre_.update(wheel_data.is_button_touched, data);
switch (up_.update(
wheel_data.is_wheel_touched &&
drivers::TouchWheel::isAngleWithin(wheel_data.wheel_position, 0, 32))) {
case Trigger::State::kNone:
break;
default:
data->enc_diff = -1;
break;
}
switch (right_.update(
wheel_data.is_wheel_touched &&
drivers::TouchWheel::isAngleWithin(wheel_data.wheel_position, 192, 32))) {
default:
break;
}
switch (down_.update(
up_.update(
wheel_data.is_wheel_touched &&
drivers::TouchWheel::isAngleWithin(wheel_data.wheel_position, 128, 32))) {
case Trigger::State::kNone:
break;
default:
data->enc_diff = 1;
break;
}
switch (left_.update(
drivers::TouchWheel::isAngleWithin(wheel_data.wheel_position, 0, 32),
data);
right_.update(
wheel_data.is_wheel_touched && drivers::TouchWheel::isAngleWithin(
wheel_data.wheel_position, 192, 32),
data);
down_.update(
wheel_data.is_wheel_touched && drivers::TouchWheel::isAngleWithin(
wheel_data.wheel_position, 128, 32),
data);
left_.update(
wheel_data.is_wheel_touched &&
drivers::TouchWheel::isAngleWithin(wheel_data.wheel_position, 64, 32))) {
case Trigger::State::kLongPress:
events::Ui().Dispatch(ui::internal::BackPressed{});
break;
default:
break;
}
drivers::TouchWheel::isAngleWithin(wheel_data.wheel_position, 64, 32),
data);
}
} // namespace input

@ -5,16 +5,16 @@
*/
#include "input_touch_wheel.hpp"
#include <stdint.h>
#include <cstdint>
#include <variant>
#include "event_queue.hpp"
#include "hal/lv_hal_indev.h"
#include "event_queue.hpp"
#include "haptics.hpp"
#include "input_device.hpp"
#include "input_hook_actions.hpp"
#include "input_trigger.hpp"
#include "nvs.hpp"
#include "property.hpp"
@ -39,6 +39,11 @@ TouchWheel::TouchWheel(drivers::NvsStorage& nvs, drivers::TouchWheel& wheel)
threshold_ = calculateThreshold(int_val);
return true;
}),
centre_(actions::select, {}, {}),
up_({}, actions::scrollToTop, actions::scrollUp),
right_({}, {}, {}),
down_({}, actions::scrollToBottom, actions::scrollDown),
left_({}, actions::goBack, {}),
is_scrolling_(false),
threshold_(calculateThreshold(nvs.ScrollSensitivity())),
is_first_read_(true),
@ -63,45 +68,24 @@ auto TouchWheel::read(lv_indev_data_t* data) -> void {
data->enc_diff = 0;
}
if (!is_scrolling_ && wheel_data.is_button_touched) {
data->state = LV_INDEV_STATE_PRESSED;
} else {
data->state = LV_INDEV_STATE_RELEASED;
}
centre_.update(!is_scrolling_ && wheel_data.is_button_touched, data);
// If the user is touching the wheel but not scrolling, then they may be
// clicking on one of the wheel's cardinal directions.
bool pressing = wheel_data.is_wheel_touched && !is_scrolling_;
switch (up_.update(pressing && drivers::TouchWheel::isAngleWithin(
wheel_data.wheel_position, 0, 32))) {
case Trigger::State::kLongPress:
data->enc_diff = INT16_MIN;
break;
default:
break;
}
switch (right_.update(pressing && drivers::TouchWheel::isAngleWithin(
wheel_data.wheel_position, 192, 32))) {
default:
break;
}
switch (down_.update(pressing && drivers::TouchWheel::isAngleWithin(
wheel_data.wheel_position, 128, 32))) {
case Trigger::State::kLongPress:
data->enc_diff = INT16_MAX;
break;
default:
break;
}
switch (left_.update(pressing && drivers::TouchWheel::isAngleWithin(
wheel_data.wheel_position, 64, 32))) {
case Trigger::State::kLongPress:
events::Ui().Dispatch(ui::internal::BackPressed{});
break;
default:
break;
}
up_.update(pressing && drivers::TouchWheel::isAngleWithin(
wheel_data.wheel_position, 0, 32),
data);
right_.update(pressing && drivers::TouchWheel::isAngleWithin(
wheel_data.wheel_position, 192, 32),
data);
down_.update(pressing && drivers::TouchWheel::isAngleWithin(
wheel_data.wheel_position, 128, 32),
data);
left_.update(pressing && drivers::TouchWheel::isAngleWithin(
wheel_data.wheel_position, 64, 32),
data);
}
auto TouchWheel::sensitivity() -> lua::Property& {

@ -7,29 +7,16 @@
#include "input_volume_buttons.hpp"
#include "event_queue.hpp"
#include "gpios.hpp"
#include "input_hook_actions.hpp"
namespace input {
VolumeButtons::VolumeButtons(drivers::IGpios& gpios) : gpios_(gpios) {}
VolumeButtons::VolumeButtons(drivers::IGpios& gpios)
: gpios_(gpios), up_(actions::volumeUp), down_(actions::volumeDown) {}
auto VolumeButtons::read(lv_indev_data_t* data) -> void {
bool vol_up = gpios_.Get(drivers::IGpios::Pin::kKeyUp);
switch (up_.update(!vol_up)) {
case Trigger::State::kNone:
break;
default:
events::Audio().Dispatch(audio::StepUpVolume{});
break;
}
bool vol_down = gpios_.Get(drivers::IGpios::Pin::kKeyDown);
switch (down_.update(!vol_down)) {
case Trigger::State::kNone:
break;
default:
events::Audio().Dispatch(audio::StepDownVolume{});
break;
}
up_.update(!gpios_.Get(drivers::IGpios::Pin::kKeyUp), data);
down_.update(!gpios_.Get(drivers::IGpios::Pin::kKeyDown), data);
}
} // namespace input

Loading…
Cancel
Save