InkHUD: Allow non-system applets to subscribe to input events (#9514)
* Allow inkhud user applets to consume inputs with opt-in system Adds a way for applets to subscribe to input events while keeping it off by default to preserve compatibility and expected behaviours. Adds example for use as well. * Add check for nullptr on getActiveApplet uses * Remove redundant includes * Move subscribedInputs to protected * More consistent naming scheme
This commit is contained in:
@@ -144,6 +144,21 @@ void InkHUD::Applet::resetDrawingSpace()
|
|||||||
setFont(fontSmall);
|
setFont(fontSmall);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Sets one or more inputs to enabled/disabled for this applet and if they should be sent to it
|
||||||
|
void InkHUD::Applet::setInputsSubscribed(uint8_t input, bool captured)
|
||||||
|
{
|
||||||
|
if (captured)
|
||||||
|
subscribedInputs |= input;
|
||||||
|
else
|
||||||
|
subscribedInputs &= ~input;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Checks if a specific input is enabled for this applet and should be sent to it
|
||||||
|
bool InkHUD::Applet::isInputSubscribed(InputMask input)
|
||||||
|
{
|
||||||
|
return (subscribedInputs & input) == input;
|
||||||
|
}
|
||||||
|
|
||||||
// Tell InkHUD::Renderer that we want to render now
|
// Tell InkHUD::Renderer that we want to render now
|
||||||
// Applets should internally listen for events they are interested in, via MeshModule, CallbackObserver etc
|
// Applets should internally listen for events they are interested in, via MeshModule, CallbackObserver etc
|
||||||
// When an applet decides it has heard something important, and wants to redraw, it calls this method
|
// When an applet decides it has heard something important, and wants to redraw, it calls this method
|
||||||
|
|||||||
@@ -89,6 +89,9 @@ class Applet : public GFX
|
|||||||
virtual void onForeground() {}
|
virtual void onForeground() {}
|
||||||
virtual void onBackground() {}
|
virtual void onBackground() {}
|
||||||
virtual void onShutdown() {}
|
virtual void onShutdown() {}
|
||||||
|
|
||||||
|
// Input Events
|
||||||
|
|
||||||
virtual void onButtonShortPress() {}
|
virtual void onButtonShortPress() {}
|
||||||
virtual void onButtonLongPress() {}
|
virtual void onButtonLongPress() {}
|
||||||
virtual void onExitShort() {}
|
virtual void onExitShort() {}
|
||||||
@@ -100,6 +103,18 @@ class Applet : public GFX
|
|||||||
virtual void onFreeText(char c) {}
|
virtual void onFreeText(char c) {}
|
||||||
virtual void onFreeTextDone() {}
|
virtual void onFreeTextDone() {}
|
||||||
virtual void onFreeTextCancel() {}
|
virtual void onFreeTextCancel() {}
|
||||||
|
// List of inputs which can be subscribed to
|
||||||
|
enum InputMask { // | No Joystick | With Joystick |
|
||||||
|
BUTTON_SHORT = 1, // | Button Click | Joystick Center Click |
|
||||||
|
BUTTON_LONG = 2, // | Button Hold | Joystick Center Hold |
|
||||||
|
EXIT_SHORT = 4, // | no-op | Back Button Click |
|
||||||
|
EXIT_LONG = 8, // | no-op | Back Button Hold |
|
||||||
|
NAV_UP = 16, // | no-op | Joystick Up |
|
||||||
|
NAV_DOWN = 32, // | no-op | Joystick Down |
|
||||||
|
NAV_LEFT = 64, // | no-op | Joystick Left |
|
||||||
|
NAV_RIGHT = 128 // | no-op | Joystick Right |
|
||||||
|
};
|
||||||
|
bool isInputSubscribed(InputMask input); // Check if input should be handled by applet, this should not be overloaded.
|
||||||
|
|
||||||
virtual bool approveNotification(Notification &n); // Allow an applet to veto a notification
|
virtual bool approveNotification(Notification &n); // Allow an applet to veto a notification
|
||||||
|
|
||||||
@@ -121,6 +136,13 @@ class Applet : public GFX
|
|||||||
void setCrop(int16_t left, int16_t top, uint16_t width, uint16_t height); // Ignore pixels drawn outside a certain region
|
void setCrop(int16_t left, int16_t top, uint16_t width, uint16_t height); // Ignore pixels drawn outside a certain region
|
||||||
void resetCrop(); // Removes setCrop()
|
void resetCrop(); // Removes setCrop()
|
||||||
|
|
||||||
|
// User Input Handling
|
||||||
|
|
||||||
|
uint8_t subscribedInputs = 0b00000000; // Maybe uint16_t for futureproofing? other devices may need more inputs
|
||||||
|
void setInputsSubscribed(uint8_t input,
|
||||||
|
bool captured); // Set if an input should be handled by applet or not, this should not be
|
||||||
|
// overloaded. Can take multiple inputs at once if you OR/`|` them together
|
||||||
|
|
||||||
// Text
|
// Text
|
||||||
|
|
||||||
void setFont(AppletFont f);
|
void setFont(AppletFont f);
|
||||||
|
|||||||
+79
@@ -0,0 +1,79 @@
|
|||||||
|
#ifdef MESHTASTIC_INCLUDE_INKHUD
|
||||||
|
#include "./UserAppletInputExample.h"
|
||||||
|
|
||||||
|
using namespace NicheGraphics;
|
||||||
|
|
||||||
|
void InkHUD::UserAppletInputExampleApplet::onActivate()
|
||||||
|
{
|
||||||
|
setGrabbed(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
void InkHUD::UserAppletInputExampleApplet::onRender(bool full)
|
||||||
|
{
|
||||||
|
drawHeader("Input Example");
|
||||||
|
uint16_t headerHeight = getHeaderHeight();
|
||||||
|
|
||||||
|
std::string buttonName;
|
||||||
|
if (settings->joystick.enabled)
|
||||||
|
buttonName = "joystick center button";
|
||||||
|
else
|
||||||
|
buttonName = "user button";
|
||||||
|
|
||||||
|
std::string additional = " | Control is grabbed, long press " + buttonName + " to release controls";
|
||||||
|
if (!isGrabbed)
|
||||||
|
additional = " | Control is released, long press " + buttonName + " to grab controls";
|
||||||
|
|
||||||
|
printWrapped(0, headerHeight, width(), "Last button: " + lastInput + additional);
|
||||||
|
}
|
||||||
|
|
||||||
|
void InkHUD::UserAppletInputExampleApplet::setGrabbed(bool grabbed)
|
||||||
|
{
|
||||||
|
isGrabbed = grabbed;
|
||||||
|
setInputsSubscribed(BUTTON_SHORT | EXIT_SHORT | EXIT_LONG | NAV_UP | NAV_DOWN | NAV_LEFT | NAV_RIGHT,
|
||||||
|
grabbed); // Enables/disables grabbing all inputs
|
||||||
|
setInputsSubscribed(BUTTON_LONG, true); // Always grab this input
|
||||||
|
}
|
||||||
|
|
||||||
|
void InkHUD::UserAppletInputExampleApplet::onButtonShortPress()
|
||||||
|
{
|
||||||
|
lastInput = "BUTTON_SHORT";
|
||||||
|
requestUpdate();
|
||||||
|
}
|
||||||
|
void InkHUD::UserAppletInputExampleApplet::onButtonLongPress()
|
||||||
|
{
|
||||||
|
lastInput = "BUTTON_LONG";
|
||||||
|
setGrabbed(!isGrabbed);
|
||||||
|
requestUpdate();
|
||||||
|
}
|
||||||
|
void InkHUD::UserAppletInputExampleApplet::onExitShort()
|
||||||
|
{
|
||||||
|
lastInput = "EXIT_SHORT";
|
||||||
|
requestUpdate();
|
||||||
|
}
|
||||||
|
void InkHUD::UserAppletInputExampleApplet::onExitLong()
|
||||||
|
{
|
||||||
|
lastInput = "EXIT_LONG";
|
||||||
|
requestUpdate();
|
||||||
|
}
|
||||||
|
void InkHUD::UserAppletInputExampleApplet::onNavUp()
|
||||||
|
{
|
||||||
|
lastInput = "NAV_UP";
|
||||||
|
requestUpdate();
|
||||||
|
}
|
||||||
|
void InkHUD::UserAppletInputExampleApplet::onNavDown()
|
||||||
|
{
|
||||||
|
lastInput = "NAV_DOWN";
|
||||||
|
requestUpdate();
|
||||||
|
}
|
||||||
|
void InkHUD::UserAppletInputExampleApplet::onNavLeft()
|
||||||
|
{
|
||||||
|
lastInput = "NAV_LEFT";
|
||||||
|
requestUpdate();
|
||||||
|
}
|
||||||
|
void InkHUD::UserAppletInputExampleApplet::onNavRight()
|
||||||
|
{
|
||||||
|
lastInput = "NAV_RIGHT";
|
||||||
|
requestUpdate();
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
+36
@@ -0,0 +1,36 @@
|
|||||||
|
#ifdef MESHTASTIC_INCLUDE_INKHUD
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "configuration.h"
|
||||||
|
|
||||||
|
#include "graphics/niche/InkHUD/Applet.h"
|
||||||
|
|
||||||
|
namespace NicheGraphics::InkHUD
|
||||||
|
{
|
||||||
|
|
||||||
|
class UserAppletInputExampleApplet : public Applet
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
void onActivate() override;
|
||||||
|
|
||||||
|
void onRender(bool full) override;
|
||||||
|
void onButtonShortPress() override;
|
||||||
|
void onButtonLongPress() override;
|
||||||
|
void onExitShort() override;
|
||||||
|
void onExitLong() override;
|
||||||
|
void onNavUp() override;
|
||||||
|
void onNavDown() override;
|
||||||
|
void onNavLeft() override;
|
||||||
|
void onNavRight() override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::string lastInput = "None";
|
||||||
|
bool isGrabbed = false;
|
||||||
|
|
||||||
|
void setGrabbed(bool grabbed);
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace NicheGraphics::InkHUD
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -59,10 +59,16 @@ void InkHUD::Events::onButtonShort()
|
|||||||
if (consumer) {
|
if (consumer) {
|
||||||
consumer->onButtonShortPress();
|
consumer->onButtonShortPress();
|
||||||
} else if (!dismissedExt) { // Don't change applet if this button press silenced the external notification module
|
} else if (!dismissedExt) { // Don't change applet if this button press silenced the external notification module
|
||||||
if (!settings->joystick.enabled)
|
Applet *userConsumer = inkhud->getActiveApplet();
|
||||||
inkhud->nextApplet();
|
|
||||||
else
|
if (userConsumer != nullptr && userConsumer->isInputSubscribed(Applet::BUTTON_SHORT))
|
||||||
inkhud->openMenu();
|
userConsumer->onButtonShortPress();
|
||||||
|
else {
|
||||||
|
if (!settings->joystick.enabled)
|
||||||
|
inkhud->nextApplet();
|
||||||
|
else
|
||||||
|
inkhud->openMenu();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -84,8 +90,14 @@ void InkHUD::Events::onButtonLong()
|
|||||||
// If no system applet is handling input, default behavior instead is to open the menu
|
// If no system applet is handling input, default behavior instead is to open the menu
|
||||||
if (consumer)
|
if (consumer)
|
||||||
consumer->onButtonLongPress();
|
consumer->onButtonLongPress();
|
||||||
else
|
else {
|
||||||
inkhud->openMenu();
|
Applet *userConsumer = inkhud->getActiveApplet();
|
||||||
|
|
||||||
|
if (userConsumer != nullptr && userConsumer->isInputSubscribed(Applet::BUTTON_LONG))
|
||||||
|
userConsumer->onButtonLongPress();
|
||||||
|
else
|
||||||
|
inkhud->openMenu();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void InkHUD::Events::onExitShort()
|
void InkHUD::Events::onExitShort()
|
||||||
@@ -110,8 +122,14 @@ void InkHUD::Events::onExitShort()
|
|||||||
// If no system applet is handling input, default behavior instead is change tiles
|
// If no system applet is handling input, default behavior instead is change tiles
|
||||||
if (consumer)
|
if (consumer)
|
||||||
consumer->onExitShort();
|
consumer->onExitShort();
|
||||||
else if (!dismissedExt) // Don't change tile if this button press silenced the external notification module
|
else if (!dismissedExt) { // Don't change tile if this button press silenced the external notification module
|
||||||
inkhud->nextTile();
|
Applet *userConsumer = inkhud->getActiveApplet();
|
||||||
|
|
||||||
|
if (userConsumer != nullptr && userConsumer->isInputSubscribed(Applet::EXIT_SHORT))
|
||||||
|
userConsumer->onExitShort();
|
||||||
|
else
|
||||||
|
inkhud->nextTile();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -133,6 +151,13 @@ void InkHUD::Events::onExitLong()
|
|||||||
|
|
||||||
if (consumer)
|
if (consumer)
|
||||||
consumer->onExitLong();
|
consumer->onExitLong();
|
||||||
|
else {
|
||||||
|
Applet *userConsumer = inkhud->getActiveApplet();
|
||||||
|
|
||||||
|
if (userConsumer != nullptr && userConsumer->isInputSubscribed(Applet::EXIT_LONG))
|
||||||
|
userConsumer->onExitLong();
|
||||||
|
// Nothing uses exit long yet
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -157,6 +182,12 @@ void InkHUD::Events::onNavUp()
|
|||||||
|
|
||||||
if (consumer)
|
if (consumer)
|
||||||
consumer->onNavUp();
|
consumer->onNavUp();
|
||||||
|
else if (!dismissedExt) {
|
||||||
|
Applet *userConsumer = inkhud->getActiveApplet();
|
||||||
|
|
||||||
|
if (userConsumer != nullptr && userConsumer->isInputSubscribed(Applet::NAV_UP))
|
||||||
|
userConsumer->onNavUp();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -181,6 +212,12 @@ void InkHUD::Events::onNavDown()
|
|||||||
|
|
||||||
if (consumer)
|
if (consumer)
|
||||||
consumer->onNavDown();
|
consumer->onNavDown();
|
||||||
|
else if (!dismissedExt) {
|
||||||
|
Applet *userConsumer = inkhud->getActiveApplet();
|
||||||
|
|
||||||
|
if (userConsumer != nullptr && userConsumer->isInputSubscribed(Applet::NAV_DOWN))
|
||||||
|
userConsumer->onNavDown();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -206,8 +243,14 @@ void InkHUD::Events::onNavLeft()
|
|||||||
// If no system applet is handling input, default behavior instead is to cycle applets
|
// If no system applet is handling input, default behavior instead is to cycle applets
|
||||||
if (consumer)
|
if (consumer)
|
||||||
consumer->onNavLeft();
|
consumer->onNavLeft();
|
||||||
else if (!dismissedExt) // Don't change applet if this button press silenced the external notification module
|
else if (!dismissedExt) { // Don't change applet if this button press silenced the external notification module
|
||||||
inkhud->prevApplet();
|
Applet *userConsumer = inkhud->getActiveApplet();
|
||||||
|
|
||||||
|
if (userConsumer != nullptr && userConsumer->isInputSubscribed(Applet::NAV_LEFT))
|
||||||
|
userConsumer->onNavLeft();
|
||||||
|
else
|
||||||
|
inkhud->prevApplet();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -233,8 +276,14 @@ void InkHUD::Events::onNavRight()
|
|||||||
// If no system applet is handling input, default behavior instead is to cycle applets
|
// If no system applet is handling input, default behavior instead is to cycle applets
|
||||||
if (consumer)
|
if (consumer)
|
||||||
consumer->onNavRight();
|
consumer->onNavRight();
|
||||||
else if (!dismissedExt) // Don't change applet if this button press silenced the external notification module
|
else if (!dismissedExt) { // Don't change applet if this button press silenced the external notification module
|
||||||
inkhud->nextApplet();
|
Applet *userConsumer = inkhud->getActiveApplet();
|
||||||
|
|
||||||
|
if (userConsumer != nullptr && userConsumer->isInputSubscribed(Applet::NAV_RIGHT))
|
||||||
|
userConsumer->onNavRight();
|
||||||
|
else
|
||||||
|
inkhud->nextApplet();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -210,6 +210,12 @@ void InkHUD::InkHUD::prevApplet()
|
|||||||
windowManager->prevApplet();
|
windowManager->prevApplet();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Returns the currently active applet
|
||||||
|
InkHUD::Applet *InkHUD::InkHUD::getActiveApplet()
|
||||||
|
{
|
||||||
|
return windowManager->getActiveApplet();
|
||||||
|
}
|
||||||
|
|
||||||
// Show the menu (on the the focused tile)
|
// Show the menu (on the the focused tile)
|
||||||
// The applet previously displayed there will be restored once the menu closes
|
// The applet previously displayed there will be restored once the menu closes
|
||||||
void InkHUD::InkHUD::openMenu()
|
void InkHUD::InkHUD::openMenu()
|
||||||
|
|||||||
@@ -74,6 +74,7 @@ class InkHUD
|
|||||||
|
|
||||||
void nextApplet();
|
void nextApplet();
|
||||||
void prevApplet();
|
void prevApplet();
|
||||||
|
NicheGraphics::InkHUD::Applet *getActiveApplet();
|
||||||
void openMenu();
|
void openMenu();
|
||||||
void openAlignStick();
|
void openAlignStick();
|
||||||
void openKeyboard();
|
void openKeyboard();
|
||||||
|
|||||||
@@ -273,6 +273,12 @@ void InkHUD::WindowManager::prevApplet()
|
|||||||
inkhud->forceUpdate(EInk::UpdateTypes::FAST); // bringToForeground already requested, but we're manually forcing FAST
|
inkhud->forceUpdate(EInk::UpdateTypes::FAST); // bringToForeground already requested, but we're manually forcing FAST
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Returns active applet
|
||||||
|
NicheGraphics::InkHUD::Applet *InkHUD::WindowManager::getActiveApplet()
|
||||||
|
{
|
||||||
|
return userTiles.at(settings->userTiles.focused)->getAssignedApplet();
|
||||||
|
}
|
||||||
|
|
||||||
// Rotate the display image by 90 degrees
|
// Rotate the display image by 90 degrees
|
||||||
void InkHUD::WindowManager::rotate()
|
void InkHUD::WindowManager::rotate()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -29,6 +29,7 @@ class WindowManager
|
|||||||
|
|
||||||
void nextTile();
|
void nextTile();
|
||||||
void prevTile();
|
void prevTile();
|
||||||
|
Applet *getActiveApplet();
|
||||||
void openMenu();
|
void openMenu();
|
||||||
void openAlignStick();
|
void openAlignStick();
|
||||||
void openKeyboard();
|
void openKeyboard();
|
||||||
|
|||||||
@@ -9,6 +9,7 @@
|
|||||||
#include "graphics/niche/InkHUD/InkHUD.h"
|
#include "graphics/niche/InkHUD/InkHUD.h"
|
||||||
|
|
||||||
// Applets
|
// Applets
|
||||||
|
#include "graphics/niche/InkHUD/Applets/Examples/UserAppletInputExample/UserAppletInputExample.h"
|
||||||
#include "graphics/niche/InkHUD/Applets/User/AllMessage/AllMessageApplet.h"
|
#include "graphics/niche/InkHUD/Applets/User/AllMessage/AllMessageApplet.h"
|
||||||
#include "graphics/niche/InkHUD/Applets/User/DM/DMApplet.h"
|
#include "graphics/niche/InkHUD/Applets/User/DM/DMApplet.h"
|
||||||
#include "graphics/niche/InkHUD/Applets/User/FavoritesMap/FavoritesMapApplet.h"
|
#include "graphics/niche/InkHUD/Applets/User/FavoritesMap/FavoritesMapApplet.h"
|
||||||
|
|||||||
Reference in New Issue
Block a user