Use more generic 'hooks' for each input device's actions
This commit is contained in:
@@ -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(
|
||||
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(
|
||||
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, 192, 32))) {
|
||||
default:
|
||||
break;
|
||||
}
|
||||
switch (down_.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(
|
||||
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
|
||||
|
||||
Reference in New Issue
Block a user