Unify the native display config between legacy display and MUI (#6838)

* Add missed include

* Another Warning fix

* Add another HAS_SCREEN

* Namespace fixes

* Removed depricated destination types and re-factored destination screen

* Get rid of Arduino Strings

* Clean up after Copilot

* SixthLine Def, Screen Rename

Added Sixth Line Definition Screen Rename, and Automatic Line Adjustment

* Consistency is hard - fixed "Sixth"

* System Frame Updates

Adjusted line construction to ensure we fit maximum content per screen.

* Fix up notifications

* Add a couple more ifdef HAS_SCREEN lines

* Add screen->isOverlayBannerShowing()

* Don't forget the invert!

* Adjust Nodelist Center Divider

Adjust Nodelist Center Divider

* Fix variable casting

* Fix entryText variable as empty before update to fix validation

* Altitude is int32_t

* Update PowerTelemetry to have correct data type

* Fix cppcheck warnings (#6945)

* Fix cppcheck warnings

* Adjust logic in Power.cpp for power sensor

---------

Co-authored-by: Jason P <applewiz@mac.com>

* More pixel wrangling so things line up NodeList edition

* Adjust NodeList alignments and plumb some background padding for a possible title fix

* Better alignment for banner notifications

* Move title into drawCommonHeader; initial screen tested

* Fonts make spacing items difficult

* Improved beeping booping and other buzzer based feedback (#6947)

* Improved beeping booping and other buzzer based feedback

* audible button feedback (#6949)

* Refactor

---------

Co-authored-by: todd-herbert <herbert.todd@gmail.com>

* Sandpapered the corners of the notification popup

* Finalize drawCommonHeader migration

* Update Title of Favorite Node Screens

* Update node metric alignment on LoRa screen

* Update the border for popups to separate it from background

* Update PaxcounterModule.cpp with CommonHeader

* Update WiFi screen with CommonHeader and related data reflow

* It was not, in fact, pointing up

* Fix build on wismeshtap

* T-deck trackball debounce

* Fix uptime on Device Focused page to actually detail

* Update Sys screen for new uptime, add label to Freq/Chan on LoRa

* Don't display DOP any longer, make Uptime consistent

* Revert Uptime change on Favorites, Apply to Device Focused

* Label the satelite number to avoid confusion

* Boop boop boop boop

* Correct GPS positioning and string consistency across strings for GPS

* Fix GPS text alignment

* Enable canned messages by default

* Don't wake screen on new nodes

* Cannedmessage list emote support added

* Fn+e emote picker for freetext screen

* Actually block CannedInput actions while display is shown

* Add selection menu to bannerOverlay

* Off by one

* Move to unified text layouts and spacing

* Still my Fav without an "e"

* Fully remove EVENT_NODEDB_UPDATED

* Simply LoRa screen

* Make some char pointers const to fix compilation on native targets

* Update drawCompassNorth to include radius

* Fix warning

* button thread cleanup

* Pull OneButton handling from PowerFSM and add MUI switch (#6973)

* Trunk

* Onebutton Menu Support

* Add temporary clock icon

* Add gps location to fsi

* Banner message state reset

* Cast to char to satisfy compiler

* Better fast handling of input during banner

* Fix warning

* Derp

* oops

* Update ref

* Wire buzzer_mode

* remove legacy string->print()

* Only init screen if one found

* Unsigned Char

* More buttonThread cleaning

* screen.cpp button handling cleanup

* The Great Event Rename of 2025

* Fix the Radiomaster

* Missed trackball type change

* Remove unused function

* Make ButtonThread an InputBroker

* Coffee hadn't kicked in yet

* Add clock icon for Navigation Bar

* Restore clock screen definition code - whoops

* ExternalNotifications now observe inputBroker

* Clock rework (#6992)

* Move Clock bits into ClockRenderer space

* Rework clock into all device navigation

* T-Watch Actually Builds Different

* Compile fix

---------

Co-authored-by: Jonathan Bennett <jbennett@incomsystems.biz>

* Add AM/PM to Digital Clock

* Flip Seconds and AM/PM on Clock Display

* Tik-tok pixels are hard

* Fix builds on Thinknode M1

* Check for GPS and don't crash

* Don't endif til the end

* Rework the OneButton thread to be much less of a mess. (#6997)

* Rework the OneButton thread to be much less of a mess. And break lots of targets temporarily

* Update src/input/ButtonThread.h

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* fix GPS toggle

* Send the shutdown event, not just the kbchar

* Honor the back button in a notificaiton popup

* Draw the right size box for popup with options

* Try to un-break all the things

---------

Co-authored-by: Ben Meadors <benmmeadors@gmail.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* 24-hour Clock Should have leading zero, but not 12-hour

* Fixup some compile errors

* Add intRoutine to ButtonThread init, to get more responsive user button back

* Add Timezone picker

* Fix Warning

* Optionally set the initial selection for the chooser popup

* Make back buttons work in canned messages

* Drop the wrapper classes

* LonPressTime now configurable

* Clock Frame can not longer be blank; just add valid time

* Back buttons everywhere!

* Key Verification confirm banner

* Make Elecrow M* top button a back button

* Add settings saves

* EInk responsiveness fixes

* Linux Input Fixes

* Add Native Trackball/Joystick support, and move UserButton to Input

* No Flight Stick Mode

* Send input event

* Add Channel Utilization to Device Focused frame

* Don't shift screens when we draw new ones

* Add showOverlayBanner arguments to no-op

* trunk

* Default Native trackball to NC

* Fix crash in simulator mode

* Add longLong button press

* Get the args right

* Adjust Bluetooth Pairing Screen to account for bottom navigation.

* Trackball everywhere, and unPhone buttons

* Remap visionmaster secondary button to TB_UP

* Kill ScanAndSelect

* trunk

* No longer need the canned messages input filter

* All Canned All the time

* Fix stm32 compile error regarding inputBroker

* Unify tft lineheights (#7033)

* Create variable line heights based upon SCREEN_HEIGHT

* Refactor textPositions into method -> getTextPositions

* Update SharedUIDisplay.h

---------

Co-authored-by: Jason P <applewiz@mac.com>

* Adjust top distance for larger displays

* Adjust icon sizes for larger displays

* Fix Paxcounter compile errors after code updates

* Pixel wrangling to make larger screens fit better

* Alert frame has precedence over banner -- for now

* Unify on ALT_BUTTON

* Align AM/PM to the digit, not the segment on larger displays

* Move some global pin defines into configuration.h

* Scaffolding for BMM150 9-axis gyro

* Alt button behavior

* Don't add the blank GPS frames without HAS_GPS

* EVENT_NODEDB_UPDATED has been retired

* Clean out LOG_WARN messages from debugging

* Add dismiss message function

* Minor buttonThread cleanup

* Add BMM150 support

* Clean up last warning from dev

* Simplify bmm150 init return logic

* Add option to reply to messages

* Add minimal menu upon selecting home screen

* Move Messages to slot 2, rename GPS to Position, move variables nearer functional usage in Screen.cpp

* Properly dismiss message

* T-Deck Trackball press is not user button

* Add select on favorite frame to launch cannedMessage DM

* Minor wording change

* Less capital letters

* Fix empty message check, time isn't reliable

* drop dead code

* Make UIRenderer a static class instead of namespace

* Fix the select on favorite

* Check if message is empty early and then 'return'

* Add kb_found, and show the option to launch freetype if appropriate

* Ignore impossible touchscreen touches

* Auto scroll fix

* Move linebreak after "from" for banners to maximize screen usage.

* Center "No messages to show" on Message frame

* Start consolidating buzzer behavior

* Fixed signed / unsigned warning

* Cast second parameter of max() to make some targets happy

* Cast kbchar to (char) to make arduino string happy

* Shorten the notice of "No messages"

* Add buzzer mode chooser

* Add regionPicker to Lora icon

* Reduce line spacing and reorder Position screen to resolve overlapping issues

* Update message titles, fix GPS icons, add Back options

* Leftover boops

* Remove chirp

* Make the region selection dismissable when a region is already set

* Add read-aloud functionality on messages w/ esp8266sam

* "Last Heard" is a better label

* tweak the beep

* 5 options

* properly tear down freetext upon cancel

* de-convelute canned messages just a bit

* Correct height of Mail icon in navigation bar

* Remove unused warning

* Consolidate time methods into TimeFormatters

* Oops

* Change LoRa Picker Cancel to Back

* Tweak selection characters on Banner

* Message render not scrolling on 5th line

* More fixes for message scrolling

* Remove the safety next on text overflow - we found that root cause

* Add pin definitions to fix compilation for obscure target

* Don't let the touchscreen send unitialized kbchar values

* Make virtual KB just a bit quicker

* No more double tap, swipe!

* Left is left, and Right is right

* Update horizontal lightning bolt design

* Move from solid to dashed separator for Message Frame

* Single emote feature fix

* Manually sort overlapping elements for now

* Freetext and clearer choices

* Fix ESP32 InkHUD builds on the unify-tft branch (#7087)

* Remove BaseUI branding

* Capitalization is fun

* Revert Meshtastic Boot Frame Changes

* Add ANZ_433 LoRa region to picker

* Update settings.json

---------

Co-authored-by: HarukiToreda <116696711+HarukiToreda@users.noreply.github.com>
Co-authored-by: Ben Meadors <benmmeadors@gmail.com>
Co-authored-by: Jason P <applewiz@mac.com>
Co-authored-by: todd-herbert <herbert.todd@gmail.com>
Co-authored-by: Thomas Göttgens <tgoettgens@gmail.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
This commit is contained in:
Jonathan Bennett
2025-06-21 06:36:04 -05:00
committed by GitHub
parent 82b7cb5dd0
commit 4feaec651f
154 changed files with 9852 additions and 4501 deletions

318
src/input/ButtonThread.cpp Normal file
View File

@@ -0,0 +1,318 @@
#include "ButtonThread.h"
#include "meshUtils.h"
#include "configuration.h"
#if !MESHTASTIC_EXCLUDE_GPS
#include "GPS.h"
#endif
#include "MeshService.h"
#include "RadioLibInterface.h"
#include "buzz.h"
#include "input/InputBroker.h"
#include "main.h"
#include "modules/CannedMessageModule.h"
#include "modules/ExternalNotificationModule.h"
#include "power.h"
#include "sleep.h"
#ifdef ARCH_PORTDUINO
#include "platform/portduino/PortduinoGlue.h"
#endif
using namespace concurrency;
#if HAS_BUTTON
#endif
ButtonThread::ButtonThread(const char *name) : OSThread(name)
{
_originName = name;
}
bool ButtonThread::initButton(uint8_t pinNumber, bool activeLow, bool activePullup, uint32_t pullupSense, voidFuncPtr intRoutine,
input_broker_event singlePress, input_broker_event longPress, uint16_t longPressTime,
input_broker_event doublePress, input_broker_event longLongPress, uint16_t longLongPressTime,
input_broker_event triplePress, input_broker_event shortLong, bool touchQuirk)
{
if (inputBroker)
inputBroker->registerSource(this);
_longPressTime = longPressTime;
_longLongPressTime = longLongPressTime;
_pinNum = pinNumber;
_activeLow = activeLow;
_touchQuirk = touchQuirk;
_intRoutine = intRoutine;
_longLongPress = longLongPress;
userButton = OneButton(pinNumber, activeLow, activePullup);
if (pullupSense != 0) {
pinMode(pinNumber, pullupSense);
}
_singlePress = singlePress;
userButton.attachClick(
[](void *callerThread) -> void {
ButtonThread *thread = (ButtonThread *)callerThread;
thread->btnEvent = BUTTON_EVENT_PRESSED;
},
this);
if (longPress != INPUT_BROKER_NONE) {
_longPress = longPress;
userButton.attachLongPressStart(
[](void *callerThread) -> void {
ButtonThread *thread = (ButtonThread *)callerThread;
if (millis() > 30000) // hold off 30s after boot
thread->btnEvent = BUTTON_EVENT_LONG_PRESSED;
},
this);
userButton.attachLongPressStop(
[](void *callerThread) -> void {
ButtonThread *thread = (ButtonThread *)callerThread;
if (millis() > 30000) // hold off 30s after boot
thread->btnEvent = BUTTON_EVENT_LONG_RELEASED;
},
this);
}
if (doublePress != INPUT_BROKER_NONE) {
_doublePress = doublePress;
userButton.attachDoubleClick(
[](void *callerThread) -> void {
ButtonThread *thread = (ButtonThread *)callerThread;
thread->btnEvent = BUTTON_EVENT_DOUBLE_PRESSED;
},
this);
}
if (triplePress != INPUT_BROKER_NONE) {
_triplePress = triplePress;
userButton.attachMultiClick(
[](void *callerThread) -> void {
ButtonThread *thread = (ButtonThread *)callerThread;
thread->storeClickCount();
thread->btnEvent = BUTTON_EVENT_MULTI_PRESSED;
},
this);
}
if (shortLong != INPUT_BROKER_NONE) {
_shortLong = shortLong;
}
userButton.setDebounceMs(1);
userButton.setPressMs(_longPressTime);
if (screen) {
userButton.setClickMs(20);
} else {
userButton.setClickMs(BUTTON_CLICK_MS);
}
attachButtonInterrupts();
#ifdef ARCH_ESP32
// Register callbacks for before and after lightsleep
// Used to detach and reattach interrupts
lsObserver.observe(&notifyLightSleep);
lsEndObserver.observe(&notifyLightSleepEnd);
#endif
return true;
}
int32_t ButtonThread::runOnce()
{
// If the button is pressed we suppress CPU sleep until release
canSleep = true; // Assume we should not keep the board awake
// Check for combination timeout
if (waitingForLongPress && (millis() - shortPressTime) > BUTTON_COMBO_TIMEOUT_MS) {
waitingForLongPress = false;
}
userButton.tick();
canSleep &= userButton.isIdle();
// Check if we should play lead-up sound during long press
// Play lead-up when button has been held for BUTTON_LEADUP_MS but before long press triggers
bool buttonCurrentlyPressed = isButtonPressed(_pinNum);
// Detect start of button press
if (buttonCurrentlyPressed && !buttonWasPressed) {
buttonPressStartTime = millis();
leadUpPlayed = false;
leadUpSequenceActive = false;
resetLeadUpSequence();
}
// Progressive lead-up sound system
if (buttonCurrentlyPressed && (millis() - buttonPressStartTime) >= BUTTON_LEADUP_MS &&
(millis() - buttonPressStartTime) < _longLongPressTime) {
// Start the progressive sequence if not already active
if (!leadUpSequenceActive) {
leadUpSequenceActive = true;
lastLeadUpNoteTime = millis();
playNextLeadUpNote(); // Play the first note immediately
}
// Continue playing notes at intervals
else if ((millis() - lastLeadUpNoteTime) >= 400) { // 400ms interval between notes
if (playNextLeadUpNote()) {
lastLeadUpNoteTime = millis();
}
}
}
// Reset when button is released
if (!buttonCurrentlyPressed && buttonWasPressed) {
leadUpPlayed = false;
leadUpSequenceActive = false;
resetLeadUpSequence();
}
buttonWasPressed = buttonCurrentlyPressed;
// new behavior
if (btnEvent != BUTTON_EVENT_NONE) {
InputEvent evt;
evt.source = _originName;
evt.kbchar = 0;
evt.touchX = 0;
evt.touchY = 0;
switch (btnEvent) {
case BUTTON_EVENT_PRESSED: {
// Forward single press to InputBroker (but NOT as DOWN/SELECT, just forward a "button press" event)
evt.inputEvent = _singlePress;
// evt.kbchar = _singlePress; // todo: fix this. Some events are kb characters rather than event types
this->notifyObservers(&evt);
// Start tracking for potential combination
waitingForLongPress = true;
shortPressTime = millis();
break;
}
case BUTTON_EVENT_LONG_PRESSED: {
// Ignore if: TX in progress
// Uncommon T-Echo hardware bug, LoRa TX triggers touch button
if (_touchQuirk && RadioLibInterface::instance && RadioLibInterface::instance->isSending())
break;
// Check if this is part of a short-press + long-press combination
if (_shortLong != INPUT_BROKER_NONE && waitingForLongPress &&
(millis() - shortPressTime) <= BUTTON_COMBO_TIMEOUT_MS) {
evt.inputEvent = _shortLong;
// evt.kbchar = _shortLong;
this->notifyObservers(&evt);
// Play the combination tune
playComboTune();
break;
}
// Forward long press to InputBroker (but NOT as DOWN/SELECT, just forward a "button long press" event)
evt.inputEvent = _longPress;
this->notifyObservers(&evt);
// Reset combination tracking
waitingForLongPress = false;
break;
}
case BUTTON_EVENT_DOUBLE_PRESSED: { // not wired in if screen detected
LOG_INFO("Double press!");
// Reset combination tracking
waitingForLongPress = false;
evt.inputEvent = _doublePress;
// evt.kbchar = _doublePress;
this->notifyObservers(&evt);
playComboTune();
break;
}
case BUTTON_EVENT_MULTI_PRESSED: { // not wired in when screen is present
LOG_INFO("Mulitipress! %hux", multipressClickCount);
// Reset combination tracking
waitingForLongPress = false;
switch (multipressClickCount) {
case 3:
evt.inputEvent = _triplePress;
// evt.kbchar = _triplePress;
this->notifyObservers(&evt);
playComboTune();
break;
// No valid multipress action
default:
break;
} // end switch: click count
break;
} // end multipress event
// Do actual shutdown when button released, otherwise the button release
// may wake the board immediatedly.
case BUTTON_EVENT_LONG_RELEASED: {
LOG_INFO("LONG PRESS RELEASE");
if (_longLongPress != INPUT_BROKER_NONE && (millis() - buttonPressStartTime) >= _longLongPressTime) {
evt.inputEvent = _longLongPress;
this->notifyObservers(&evt);
}
// Reset combination tracking
waitingForLongPress = false;
break;
}
}
}
btnEvent = BUTTON_EVENT_NONE;
return 50;
}
/*
* Attach (or re-attach) hardware interrupts for buttons
* Public method. Used outside class when waking from MCU sleep
*/
void ButtonThread::attachButtonInterrupts()
{
// Interrupt for user button, during normal use. Improves responsiveness.
attachInterrupt(_pinNum, _intRoutine, CHANGE);
}
/*
* Detach the "normal" button interrupts.
* Public method. Used before attaching a "wake-on-button" interrupt for MCU sleep
*/
void ButtonThread::detachButtonInterrupts()
{
detachInterrupt(_pinNum);
}
#ifdef ARCH_ESP32
// Detach our class' interrupts before lightsleep
// Allows sleep.cpp to configure its own interrupts, which wake the device on user-button press
int ButtonThread::beforeLightSleep(void *unused)
{
detachButtonInterrupts();
return 0; // Indicates success
}
// Reconfigure our interrupts
// Our class' interrupts were disconnected during sleep, to allow the user button to wake the device from sleep
int ButtonThread::afterLightSleep(esp_sleep_wakeup_cause_t cause)
{
attachButtonInterrupts();
return 0; // Indicates success
}
#endif
// Non-static method, runs during callback. Grabs info while still valid
void ButtonThread::storeClickCount()
{
multipressClickCount = userButton.getNumberClicks();
}

113
src/input/ButtonThread.h Normal file
View File

@@ -0,0 +1,113 @@
#pragma once
#include "InputBroker.h"
#include "OneButton.h"
#include "concurrency/OSThread.h"
#include "configuration.h"
typedef void (*voidFuncPtr)(void);
#ifndef BUTTON_CLICK_MS
#define BUTTON_CLICK_MS 250
#endif
#ifndef BUTTON_TOUCH_MS
#define BUTTON_TOUCH_MS 400
#endif
#ifndef BUTTON_COMBO_TIMEOUT_MS
#define BUTTON_COMBO_TIMEOUT_MS 1000 // 1 second to complete the combination -- tap faster
#endif
#ifndef BUTTON_LEADUP_MS
#define BUTTON_LEADUP_MS 2200 // Play lead-up sound after 2.5 seconds of holding
#endif
class ButtonThread : public Observable<const InputEvent *>, public concurrency::OSThread
{
public:
const char *_originName;
static const uint32_t c_holdOffTime = 30000; // hold off 30s after boot
bool initButton(uint8_t pinNumber, bool activeLow, bool activePullup, uint32_t pullupSense, voidFuncPtr intRoutine,
input_broker_event singlePress, input_broker_event longPress = INPUT_BROKER_NONE,
uint16_t longPressTime = 500, input_broker_event doublePress = INPUT_BROKER_NONE,
input_broker_event longLongPress = INPUT_BROKER_NONE, uint16_t longLongPressTime = 5000,
input_broker_event triplePress = INPUT_BROKER_NONE, input_broker_event shortLong = INPUT_BROKER_NONE,
bool touchQuirk = false);
enum ButtonEventType {
BUTTON_EVENT_NONE,
BUTTON_EVENT_PRESSED,
BUTTON_EVENT_PRESSED_SCREEN,
BUTTON_EVENT_DOUBLE_PRESSED,
BUTTON_EVENT_MULTI_PRESSED,
BUTTON_EVENT_LONG_PRESSED,
BUTTON_EVENT_LONG_RELEASED,
BUTTON_EVENT_TOUCH_LONG_PRESSED,
BUTTON_EVENT_COMBO_SHORT_LONG,
};
ButtonThread(const char *name);
int32_t runOnce() override;
OneButton userButton;
void attachButtonInterrupts();
void detachButtonInterrupts();
void storeClickCount();
bool isButtonPressed(int buttonPin)
{
if (_activeLow)
return !digitalRead(buttonPin); // Active low: pressed = LOW
else
return digitalRead(buttonPin); // Most buttons are active low by default
}
// Disconnect and reconnect interrupts for light sleep
#ifdef ARCH_ESP32
int beforeLightSleep(void *unused);
int afterLightSleep(esp_sleep_wakeup_cause_t cause);
#endif
private:
input_broker_event _singlePress = INPUT_BROKER_NONE;
input_broker_event _longPress = INPUT_BROKER_NONE;
input_broker_event _longLongPress = INPUT_BROKER_NONE;
input_broker_event _doublePress = INPUT_BROKER_NONE;
input_broker_event _triplePress = INPUT_BROKER_NONE;
input_broker_event _shortLong = INPUT_BROKER_NONE;
voidFuncPtr _intRoutine = nullptr;
uint16_t _longPressTime = 500;
uint16_t _longLongPressTime = 5000;
int _pinNum = 0;
bool _activeLow = true;
bool _touchQuirk = false;
uint32_t buttonPressStartTime = 0;
bool buttonWasPressed = false;
#ifdef ARCH_ESP32
// Get notified when lightsleep begins and ends
CallbackObserver<ButtonThread, void *> lsObserver =
CallbackObserver<ButtonThread, void *>(this, &ButtonThread::beforeLightSleep);
CallbackObserver<ButtonThread, esp_sleep_wakeup_cause_t> lsEndObserver =
CallbackObserver<ButtonThread, esp_sleep_wakeup_cause_t>(this, &ButtonThread::afterLightSleep);
#endif
volatile ButtonEventType btnEvent = BUTTON_EVENT_NONE;
// Store click count during callback, for later use
volatile int multipressClickCount = 0;
// Combination tracking state
bool waitingForLongPress = false;
uint32_t shortPressTime = 0;
// Long press lead-up tracking
bool leadUpPlayed = false;
uint32_t lastLeadUpNoteTime = 0;
bool leadUpSequenceActive = false;
static void wakeOnIrq(int irq, int mode);
};
extern ButtonThread *buttonThread;

View File

@@ -146,31 +146,31 @@ void ExpressLRSFiveWay::determineAction(KeyType key, PressLength length)
{
switch (key) {
case LEFT:
if (inCannedMessageMenu()) // If in canned message menu
sendKey(CANCEL); // exit the menu (press imaginary cancel key)
if (inCannedMessageMenu()) // If in canned message menu
sendKey(INPUT_BROKER_CANCEL); // exit the menu (press imaginary cancel key)
else
sendKey(LEFT);
sendKey(INPUT_BROKER_LEFT);
break;
case RIGHT:
if (inCannedMessageMenu()) // If in canned message menu:
sendKey(CANCEL); // exit the menu (press imaginary cancel key)
if (inCannedMessageMenu()) // If in canned message menu:
sendKey(INPUT_BROKER_CANCEL); // exit the menu (press imaginary cancel key)
else
sendKey(RIGHT);
sendKey(INPUT_BROKER_RIGHT);
break;
case UP:
if (length == LONG)
toggleGPS();
else
sendKey(UP);
sendKey(INPUT_BROKER_UP);
break;
case DOWN:
if (length == LONG)
sendAdhocPing();
else
sendKey(DOWN);
sendKey(INPUT_BROKER_DOWN);
break;
case OK:
@@ -186,7 +186,7 @@ void ExpressLRSFiveWay::determineAction(KeyType key, PressLength length)
}
// Feed input to the canned messages module
void ExpressLRSFiveWay::sendKey(KeyType key)
void ExpressLRSFiveWay::sendKey(input_broker_event key)
{
InputEvent e;
e.source = inputSourceName;
@@ -243,15 +243,9 @@ void ExpressLRSFiveWay::shutdown()
shutdownAtMsec = millis() + 3000;
}
// Emulate user button, or canned message SELECT
// This is necessary as canned message module doesn't translate SELECT to user button presses if the module is disabled
// Contained as one method for easier remapping of buttons by user
void ExpressLRSFiveWay::click()
{
if (!moduleConfig.canned_message.enabled)
powerFSM.trigger(EVENT_PRESS);
else
sendKey(OK);
sendKey(INPUT_BROKER_SELECT);
}
ExpressLRSFiveWay *expressLRSFiveWayInput = nullptr;

View File

@@ -40,13 +40,13 @@ class ExpressLRSFiveWay : public Observable<const InputEvent *>, public concurre
// This merged an enum used by the ExpressLRS code, with meshtastic canned message values
// Key names are kept simple, to allow user customizaton
typedef enum {
UP = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_UP,
DOWN = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_DOWN,
LEFT = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_LEFT,
RIGHT = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_RIGHT,
OK = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_SELECT,
CANCEL = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_CANCEL,
NO_PRESS = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_NONE
UP = INPUT_BROKER_UP,
DOWN = INPUT_BROKER_DOWN,
LEFT = INPUT_BROKER_LEFT,
RIGHT = INPUT_BROKER_RIGHT,
OK = INPUT_BROKER_SELECT,
CANCEL = INPUT_BROKER_CANCEL,
NO_PRESS = INPUT_BROKER_NONE
} KeyType;
typedef enum { SHORT, LONG } PressLength;
@@ -63,7 +63,7 @@ class ExpressLRSFiveWay : public Observable<const InputEvent *>, public concurre
// Meshtastic code
void determineAction(KeyType key, PressLength length);
void sendKey(KeyType key);
void sendKey(input_broker_event key);
inline bool inCannedMessageMenu() { return cannedMessageModule->shouldDraw(); }
int32_t runOnce() override;

View File

@@ -12,7 +12,7 @@ void InputBroker::registerSource(Observable<const InputEvent *> *source)
int InputBroker::handleInputEvent(const InputEvent *event)
{
powerFSM.trigger(EVENT_INPUT);
powerFSM.trigger(EVENT_INPUT); // todo: not every input should wake, like long hold release
this->notifyObservers(event);
return 0;
}

View File

@@ -1,29 +1,40 @@
#pragma once
#include "Observer.h"
#define ANYKEY 0xFF
#define MATRIXKEY 0xFE
enum input_broker_event {
INPUT_BROKER_NONE = 0,
INPUT_BROKER_SELECT = 10,
INPUT_BROKER_UP = 17,
INPUT_BROKER_DOWN = 18,
INPUT_BROKER_LEFT = 19,
INPUT_BROKER_RIGHT = 20,
INPUT_BROKER_CANCEL = 24,
INPUT_BROKER_BACK = 27,
INPUT_BROKER_USER_PRESS,
INPUT_BROKER_ALT_PRESS,
INPUT_BROKER_ALT_LONG,
INPUT_BROKER_SHUTDOWN = 0x9b,
INPUT_BROKER_GPS_TOGGLE = 0x9e,
INPUT_BROKER_SEND_PING = 0xaf,
INPUT_BROKER_MATRIXKEY = 0xFE,
INPUT_BROKER_ANYKEY = 0xff
};
#define INPUT_BROKER_MSG_BRIGHTNESS_UP 0x11
#define INPUT_BROKER_MSG_BRIGHTNESS_DOWN 0x12
#define INPUT_BROKER_MSG_REBOOT 0x90
#define INPUT_BROKER_MSG_SHUTDOWN 0x9b
#define INPUT_BROKER_MSG_GPS_TOGGLE 0x9e
#define INPUT_BROKER_MSG_MUTE_TOGGLE 0xac
#define INPUT_BROKER_MSG_SEND_PING 0xaf
#define INPUT_BROKER_MSG_DISMISS_FRAME 0x8b
#define INPUT_BROKER_MSG_LEFT 0xb4
#define INPUT_BROKER_MSG_UP 0xb5
#define INPUT_BROKER_MSG_DOWN 0xb6
#define INPUT_BROKER_MSG_RIGHT 0xb7
#define INPUT_BROKER_MSG_FN_SYMBOL_ON 0xf1
#define INPUT_BROKER_MSG_FN_SYMBOL_OFF 0xf2
#define INPUT_BROKER_MSG_BLUETOOTH_TOGGLE 0xAA
#define INPUT_BROKER_MSG_TAB 0x09
#define INPUT_BROKER_MSG_EMOTE_LIST 0x8F
typedef struct _InputEvent {
const char *source;
char inputEvent;
char kbchar;
input_broker_event inputEvent;
unsigned char kbchar;
uint16_t touchX;
uint16_t touchY;
} InputEvent;
@@ -35,6 +46,7 @@ class InputBroker : public Observable<const InputEvent *>
public:
InputBroker();
void registerSource(Observable<const InputEvent *> *source);
void injectInputEvent(const InputEvent *event) { handleInputEvent(event); }
protected:
int handleInputEvent(const InputEvent *event);

View File

@@ -7,6 +7,7 @@
#include <errno.h>
#include <fcntl.h>
#include <linux/input.h>
#include <main.h>
#include <stdint.h>
#include <stdio.h>
#include <string>
@@ -50,6 +51,7 @@ int32_t LinuxInput::runOnce()
perror("unable to epoll add");
return disable();
}
kb_found = true;
// This is the first time the OSThread library has called this function, so do port setup
firstTime = 0;
}
@@ -72,7 +74,7 @@ int32_t LinuxInput::runOnce()
assert(rd > ((signed int)sizeof(struct input_event)));
for (int j = 0; j < rd / ((signed int)sizeof(struct input_event)); j++) {
InputEvent e;
e.inputEvent = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_NONE;
e.inputEvent = INPUT_BROKER_NONE;
e.source = this->_originName;
e.kbchar = 0;
unsigned int type, code;
@@ -131,36 +133,36 @@ int32_t LinuxInput::runOnce()
mod = 0x08;
break;
case KEY_ESC: // ESC
e.inputEvent = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_CANCEL;
e.inputEvent = INPUT_BROKER_CANCEL;
break;
case KEY_BACK: // Back
e.inputEvent = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_BACK;
e.inputEvent = INPUT_BROKER_BACK;
// e.kbchar = key;
break;
case KEY_UP: // Up
e.inputEvent = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_UP;
e.inputEvent = INPUT_BROKER_UP;
break;
case KEY_DOWN: // Down
e.inputEvent = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_DOWN;
e.inputEvent = INPUT_BROKER_DOWN;
break;
case KEY_LEFT: // Left
e.inputEvent = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_LEFT;
e.inputEvent = INPUT_BROKER_LEFT;
break;
e.kbchar = INPUT_BROKER_MSG_LEFT;
e.kbchar = INPUT_BROKER_LEFT;
case KEY_RIGHT: // Right
e.inputEvent = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_RIGHT;
e.inputEvent = INPUT_BROKER_RIGHT;
break;
e.kbchar = INPUT_BROKER_MSG_RIGHT;
e.kbchar = 0;
case KEY_ENTER: // Enter
e.inputEvent = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_SELECT;
e.inputEvent = INPUT_BROKER_SELECT;
break;
case KEY_POWER:
system("poweroff");
break;
default: // all other keys
if (keymap[code]) {
e.inputEvent = ANYKEY;
e.inputEvent = INPUT_BROKER_ANYKEY;
e.kbchar = keymap[code];
}
break;
@@ -173,8 +175,8 @@ int32_t LinuxInput::runOnce()
}
report[0] = modifiers;
}
if (e.inputEvent != meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_NONE) {
if (e.inputEvent == ANYKEY && (modifiers && 0x22))
if (e.inputEvent != INPUT_BROKER_NONE) {
if (e.inputEvent == INPUT_BROKER_ANYKEY && (modifiers && 0x22))
e.kbchar = uppers[e.kbchar]; // doesn't get punctuation. Meh.
this->notifyObservers(&e);
}

View File

@@ -7,7 +7,8 @@ RotaryEncoderInterruptBase::RotaryEncoderInterruptBase(const char *name) : concu
}
void RotaryEncoderInterruptBase::init(
uint8_t pinA, uint8_t pinB, uint8_t pinPress, char eventCw, char eventCcw, char eventPressed,
uint8_t pinA, uint8_t pinB, uint8_t pinPress, input_broker_event eventCw, input_broker_event eventCcw,
input_broker_event eventPressed,
// std::function<void(void)> onIntA, std::function<void(void)> onIntB, std::function<void(void)> onIntPress) :
void (*onIntA)(), void (*onIntB)(), void (*onIntPress)())
{
@@ -34,7 +35,7 @@ void RotaryEncoderInterruptBase::init(
int32_t RotaryEncoderInterruptBase::runOnce()
{
InputEvent e;
e.inputEvent = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_NONE;
e.inputEvent = INPUT_BROKER_NONE;
e.source = this->_originName;
if (this->action == ROTARY_ACTION_PRESSED) {
@@ -48,7 +49,7 @@ int32_t RotaryEncoderInterruptBase::runOnce()
e.inputEvent = this->_eventCcw;
}
if (e.inputEvent != meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_NONE) {
if (e.inputEvent != INPUT_BROKER_NONE) {
this->notifyObservers(&e);
}

View File

@@ -12,7 +12,8 @@ class RotaryEncoderInterruptBase : public Observable<const InputEvent *>, public
{
public:
explicit RotaryEncoderInterruptBase(const char *name);
void init(uint8_t pinA, uint8_t pinB, uint8_t pinPress, char eventCw, char eventCcw, char eventPressed,
void init(uint8_t pinA, uint8_t pinB, uint8_t pinPress, input_broker_event eventCw, input_broker_event eventCcw,
input_broker_event eventPressed,
// std::function<void(void)> onIntA, std::function<void(void)> onIntB, std::function<void(void)> onIntPress);
void (*onIntA)(), void (*onIntB)(), void (*onIntPress)());
void intPressHandler();
@@ -34,8 +35,8 @@ class RotaryEncoderInterruptBase : public Observable<const InputEvent *>, public
private:
uint8_t _pinA = 0;
uint8_t _pinB = 0;
char _eventCw = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_NONE;
char _eventCcw = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_NONE;
char _eventPressed = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_NONE;
input_broker_event _eventCw = INPUT_BROKER_NONE;
input_broker_event _eventCcw = INPUT_BROKER_NONE;
input_broker_event _eventPressed = INPUT_BROKER_NONE;
const char *_originName;
};

View File

@@ -16,9 +16,9 @@ bool RotaryEncoderInterruptImpl1::init()
uint8_t pinA = moduleConfig.canned_message.inputbroker_pin_a;
uint8_t pinB = moduleConfig.canned_message.inputbroker_pin_b;
uint8_t pinPress = moduleConfig.canned_message.inputbroker_pin_press;
char eventCw = static_cast<char>(moduleConfig.canned_message.inputbroker_event_cw);
char eventCcw = static_cast<char>(moduleConfig.canned_message.inputbroker_event_ccw);
char eventPressed = static_cast<char>(moduleConfig.canned_message.inputbroker_event_press);
input_broker_event eventCw = static_cast<input_broker_event>(moduleConfig.canned_message.inputbroker_event_cw);
input_broker_event eventCcw = static_cast<input_broker_event>(moduleConfig.canned_message.inputbroker_event_ccw);
input_broker_event eventPressed = static_cast<input_broker_event>(moduleConfig.canned_message.inputbroker_event_press);
// moduleConfig.canned_message.ext_notification_module_output
RotaryEncoderInterruptBase::init(pinA, pinB, pinPress, eventCw, eventCcw, eventPressed,

View File

@@ -1,230 +0,0 @@
#include "configuration.h"
// Normally these input methods are protected by guarding in setupModules
// In order to have the user button dismiss the canned message frame, this class lightly interacts with the Screen class
#if HAS_SCREEN
#include "ScanAndSelect.h"
#include "modules/CannedMessageModule.h"
#include <Throttle.h>
#ifdef ARCH_PORTDUINO // Only to check for pin conflict with user button
#include "platform/portduino/PortduinoGlue.h"
#endif
// Config
static const char name[] = "scanAndSelect"; // should match "allow input source" string
static constexpr uint32_t durationShortMs = 50;
static constexpr uint32_t durationLongMs = 1500;
static constexpr uint32_t durationAlertMs = 2000;
// Constructor: init base class
ScanAndSelectInput::ScanAndSelectInput() : concurrency::OSThread(name) {}
// Attempt to setup class; true if success.
// Called by setupModules method. Instance deleted if setup fails.
bool ScanAndSelectInput::init()
{
// Short circuit: Canned messages enabled?
if (!moduleConfig.canned_message.enabled)
return false;
// Short circuit: Using correct "input source"?
// Todo: protobuf enum instead of string?
if (strcasecmp(moduleConfig.canned_message.allow_input_source, name) != 0)
return false;
// Determine which pin to use for the single scan-and-select button
// User can specify this by setting any of the inputbroker pins
// If all values are zero, we'll assume the user *does* want GPIO0
if (moduleConfig.canned_message.inputbroker_pin_press)
pin = moduleConfig.canned_message.inputbroker_pin_press;
else if (moduleConfig.canned_message.inputbroker_pin_a)
pin = moduleConfig.canned_message.inputbroker_pin_a;
else if (moduleConfig.canned_message.inputbroker_pin_b)
pin = moduleConfig.canned_message.inputbroker_pin_b;
else
pin = 0; // GPIO 0 then
// Short circuit: if selected pin conficts with the user button
#if defined(ARCH_PORTDUINO)
int pinUserButton = 0;
if (settingsMap.count(user) != 0) {
pinUserButton = settingsMap[user];
}
#elif defined(USERPREFS_BUTTON_PIN)
int pinUserButton = config.device.button_gpio ? config.device.button_gpio : USERPREFS_BUTTON_PIN;
#elif defined(BUTTON_PIN)
int pinUserButton = config.device.button_gpio ? config.device.button_gpio : BUTTON_PIN;
#else
int pinUserButton = config.device.button_gpio;
#endif
if (pin == pinUserButton) {
LOG_ERROR("ScanAndSelect conflict with user button");
return false;
}
// Set-up the button
pinMode(pin, INPUT_PULLUP);
attachInterrupt(pin, handleChangeInterrupt, CHANGE);
// Connect our class to the canned message module
inputBroker->registerSource(this);
LOG_INFO("Initialized 'Scan and Select' input for Canned Messages, using pin %d", pin);
return true; // Init succeded
}
// Runs periodically, unless sleeping between presses
int32_t ScanAndSelectInput::runOnce()
{
uint32_t now = millis();
// If: "no messages added" alert screen currently shown
if (alertingNoMessage) {
// Dismiss the alert screen several seconds after it appears
if (!Throttle::isWithinTimespanMs(alertingSinceMs, durationAlertMs)) {
alertingNoMessage = false;
screen->endAlert();
}
}
// If: Button is pressed
if (digitalRead(pin) == LOW) {
// New press
if (!held) {
downSinceMs = now;
}
// Existing press
else {
// Longer than shortpress window
// Long press not yet fired (prevent repeat firing while held)
if (!longPressFired && !Throttle::isWithinTimespanMs(downSinceMs, durationLongMs)) {
longPressFired = true;
longPress();
}
}
// Record the change of state: button is down
held = true;
}
// If: Button is not pressed
else {
// Button newly released
// Long press event didn't already fire
if (held && !longPressFired) {
// Duration within shortpress window
// - longer than durationShortPress (debounce)
// - shorter than durationLongPress
if (!Throttle::isWithinTimespanMs(downSinceMs, durationShortMs)) {
shortPress();
}
}
// Record the change of state: button is up
held = false;
longPressFired = false; // Re-Arm: allow another long press
}
// If thread's job is done, let it sleep
if (!held && !alertingNoMessage) {
Thread::canSleep = true;
return OSThread::disable();
}
// Run this method again is a few ms
return durationShortMs;
}
void ScanAndSelectInput::longPress()
{
// (If canned messages set)
if (cannedMessageModule->hasMessages()) {
// If module frame displayed already, send the current message
if (cannedMessageModule->shouldDraw())
raiseEvent(meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_SELECT);
// Otherwise, initial long press opens the module frame
else
raiseEvent(meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_DOWN);
}
// (If canned messages not set) tell the user
else
alertNoMessage();
}
void ScanAndSelectInput::shortPress()
{
// (If canned messages set) scroll to next message
if (cannedMessageModule->hasMessages())
raiseEvent(meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_DOWN);
// (If canned messages not yet set) tell the user
else
alertNoMessage();
}
// Begin running runOnce at regular intervals
// Called from pin change interrupt
void ScanAndSelectInput::enableThread()
{
Thread::canSleep = false;
OSThread::enabled = true;
OSThread::setIntervalFromNow(0);
}
// Inform user (screen) that no canned messages have been added
// Automatically dismissed after several seconds
void ScanAndSelectInput::alertNoMessage()
{
alertingNoMessage = true;
alertingSinceMs = millis();
// Graphics code: the alert frame to show on screen
screen->startAlert([](OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y) -> void {
display->setTextAlignment(TEXT_ALIGN_CENTER_BOTH);
display->setFont(FONT_SMALL);
int16_t textX = display->getWidth() / 2;
int16_t textY = display->getHeight() / 2;
display->drawString(textX + x, textY + y, "No Canned Messages");
});
}
// Remove the canned message frame from screen
// Used to dismiss the module frame when user button pressed
// Returns true if the frame was previously displayed, and has now been closed
// Return value consumed by Screen class when determining how to handle user button
bool ScanAndSelectInput::dismissCannedMessageFrame()
{
if (cannedMessageModule->shouldDraw()) {
raiseEvent(meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_CANCEL);
return true;
}
return false;
}
// Feed input to the canned messages module
void ScanAndSelectInput::raiseEvent(_meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar key)
{
InputEvent e;
e.source = name;
e.inputEvent = key;
notifyObservers(&e);
}
// Pin change interrupt
void ScanAndSelectInput::handleChangeInterrupt()
{
// Because we need to detect both press and release (rising and falling edge), the interrupt itself can't determine the
// action. Instead, we start up the thread and get it to read the button for us
// The instance we're referring to here is created in setupModules()
scanAndSelectInput->enableThread();
}
ScanAndSelectInput *scanAndSelectInput = nullptr; // Instantiated in setupModules method. Deleted if unused, or init() fails
#endif

View File

@@ -1,50 +0,0 @@
/*
A "single button" input method for Canned Messages
- Short press to cycle through messages
- Long Press to send
To use:
- set "allow input source" to "scanAndSelect"
- set the single button's GPIO as either pin A, pin B, or pin Press
Originally designed to make use of "extra" built-in button on some boards.
Non-intrusive; suitable for use as a default module config.
*/
#pragma once
#include "concurrency/OSThread.h"
#include "main.h"
// Normally these input methods are protected by guarding in setupModules
// In order to have the user button dismiss the canned message frame, this class lightly interacts with the Screen class
#if HAS_SCREEN
class ScanAndSelectInput : public Observable<const InputEvent *>, public concurrency::OSThread
{
public:
ScanAndSelectInput(); // No-op constructor, only initializes OSThread base class
bool init(); // Attempt to setup class; true if success. Instance deleted if setup fails
bool dismissCannedMessageFrame(); // Remove the canned message frame from screen. True if frame was open, and now closed.
void alertNoMessage(); // Inform user (screen) that no canned messages have been added
protected:
int32_t runOnce() override; // Runs at regular intervals, when enabled
void enableThread(); // Begin running runOnce at regular intervals
static void handleChangeInterrupt(); // Calls enableThread from pin change interrupt
void shortPress(); // Code to run when short press fires
void longPress(); // Code to run when long press fires
void raiseEvent(_meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar key); // Feed input to canned message module
bool held = false; // Have we handled a change in button state?
bool longPressFired = false; // Long press fires while button still held. This bool ensures the release is no-op
uint32_t downSinceMs = 0; // Debouncing for short press, timing for long press
uint8_t pin = -1; // Read from cannned message config during init
bool alertingNoMessage = false; // Is the "no canned messages" alert shown on screen?
uint32_t alertingSinceMs = 0; // Used to dismiss the "no canned message" alert several seconds
};
extern ScanAndSelectInput *scanAndSelectInput; // Instantiated in setupModules method. Deleted if unused, or init() fails
#endif

View File

@@ -30,7 +30,7 @@ SerialKeyboard::SerialKeyboard(const char *name) : concurrency::OSThread(name)
void SerialKeyboard::erase()
{
InputEvent e;
e.inputEvent = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_BACK;
e.inputEvent = INPUT_BROKER_BACK;
e.kbchar = 0x08;
e.source = this->_originName;
this->notifyObservers(&e);
@@ -81,18 +81,18 @@ int32_t SerialKeyboard::runOnce()
if (keys < prevKeys) { // a new key has been pressed (and not released), doesn't works for multiple presses at once but
// shouldn't be a limitation
InputEvent e;
e.inputEvent = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_NONE;
e.inputEvent = INPUT_BROKER_NONE;
e.source = this->_originName;
// SELECT OR SEND OR CANCEL EVENT
if (!(shiftRegister2 & (1 << 3))) {
e.inputEvent = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_UP;
e.inputEvent = INPUT_BROKER_UP;
} else if (!(shiftRegister2 & (1 << 2))) {
e.inputEvent = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_RIGHT;
e.kbchar = INPUT_BROKER_MSG_RIGHT;
e.inputEvent = INPUT_BROKER_RIGHT;
e.kbchar = 0;
} else if (!(shiftRegister2 & (1 << 1))) {
e.inputEvent = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_SELECT;
e.inputEvent = INPUT_BROKER_SELECT;
} else if (!(shiftRegister2 & (1 << 0))) {
e.inputEvent = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_CANCEL;
e.inputEvent = INPUT_BROKER_CANCEL;
}
// TEXT INPUT EVENT
@@ -120,10 +120,10 @@ int32_t SerialKeyboard::runOnce()
// BACKSPACE or TAB
else if (!(shiftRegister1 & (1 << 7))) {
if (shift == 0 || shift == 2) { // BACKSPACE
e.inputEvent = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_BACK;
e.inputEvent = INPUT_BROKER_BACK;
e.kbchar = 0x08;
} else { // shift = 1 => TAB
e.inputEvent = ANYKEY;
e.inputEvent = INPUT_BROKER_ANYKEY;
e.kbchar = 0x09;
}
}
@@ -146,7 +146,7 @@ int32_t SerialKeyboard::runOnce()
if (keyPressed == lastKeyPressed && millis() - lastPressTime < 500) {
erase();
}
e.inputEvent = ANYKEY;
e.inputEvent = INPUT_BROKER_ANYKEY;
e.kbchar = char(KeyMap[shift][quickPress][keyPressed]);
} else { // then it's shift
shift += 1;
@@ -159,7 +159,7 @@ int32_t SerialKeyboard::runOnce()
keyPressed = 13;
}
if (e.inputEvent != meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_NONE) {
if (e.inputEvent != INPUT_BROKER_NONE) {
this->notifyObservers(&e);
}
}

View File

@@ -147,7 +147,6 @@ TCA8418Keyboard::TCA8418Keyboard() : m_wire(nullptr), m_addr(0), readCallback(nu
{
state = Init;
last_key = -1;
next_key = -1;
should_backspace = false;
last_tap = 0L;
char_idx = 0;

View File

@@ -21,7 +21,6 @@ class TCA8418Keyboard
KeyState state;
int8_t last_key;
int8_t next_key;
bool should_backspace;
uint32_t last_tap;
uint8_t char_idx;

View File

@@ -43,6 +43,8 @@ int32_t TouchScreenBase::runOnce()
// process touch events
int16_t x, y;
bool touched = getTouch(x, y);
if (x < 0 || y < 0) // T-deck can emit phantom touch events with a negative value when turing off the screen
touched = false;
if (touched) {
this->setInterval(20);
_last_x = x;
@@ -93,8 +95,6 @@ int32_t TouchScreenBase::runOnce()
if (duration > 0 && duration < TIME_LONG_PRESS) {
if (_tapped) {
_tapped = false;
e.touchEvent = static_cast<char>(TOUCH_ACTION_DOUBLE_TAP);
LOG_DEBUG("action DOUBLE TAP(%d/%d)", x, y);
} else {
_tapped = true;
}
@@ -124,7 +124,7 @@ int32_t TouchScreenBase::runOnce()
}
#else
// fire TAP event when no 2nd tap occured within time
if (_tapped && (time_t(millis()) - _start) > TIME_LONG_PRESS - 50) {
if (_tapped) {
_tapped = false;
e.touchEvent = static_cast<char>(TOUCH_ACTION_TAP);
LOG_DEBUG("action TAP(%d/%d)", _last_x, _last_y);

View File

@@ -28,7 +28,6 @@ class TouchScreenBase : public Observable<const InputEvent *>, public concurrenc
TOUCH_ACTION_LEFT,
TOUCH_ACTION_RIGHT,
TOUCH_ACTION_TAP,
TOUCH_ACTION_DOUBLE_TAP,
TOUCH_ACTION_LONG_PRESS
};

View File

@@ -49,41 +49,33 @@ void TouchScreenImpl1::onEvent(const TouchEvent &event)
{
InputEvent e;
e.source = event.source;
e.kbchar = 0;
e.touchX = event.x;
e.touchY = event.y;
switch (event.touchEvent) {
case TOUCH_ACTION_LEFT: {
e.inputEvent = static_cast<char>(meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_RIGHT);
e.inputEvent = INPUT_BROKER_LEFT;
break;
}
case TOUCH_ACTION_RIGHT: {
e.inputEvent = static_cast<char>(meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_LEFT);
e.inputEvent = INPUT_BROKER_RIGHT;
break;
}
case TOUCH_ACTION_UP: {
e.inputEvent = static_cast<char>(meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_UP);
e.inputEvent = INPUT_BROKER_UP;
break;
}
case TOUCH_ACTION_DOWN: {
e.inputEvent = static_cast<char>(meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_DOWN);
break;
}
case TOUCH_ACTION_DOUBLE_TAP: {
e.inputEvent = static_cast<char>(meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_SELECT);
e.inputEvent = INPUT_BROKER_DOWN;
break;
}
case TOUCH_ACTION_LONG_PRESS: {
e.inputEvent = static_cast<char>(meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_CANCEL);
e.inputEvent = INPUT_BROKER_SELECT;
break;
}
case TOUCH_ACTION_TAP: {
if (moduleConfig.external_notification.enabled && (externalNotificationModule->nagCycleCutoff != UINT32_MAX)) {
externalNotificationModule->stopNow();
} else {
powerFSM.trigger(EVENT_INPUT);
}
e.inputEvent = INPUT_BROKER_USER_PRESS;
break;
}
default:

View File

@@ -4,9 +4,9 @@
TrackballInterruptBase::TrackballInterruptBase(const char *name) : concurrency::OSThread(name), _originName(name) {}
void TrackballInterruptBase::init(uint8_t pinDown, uint8_t pinUp, uint8_t pinLeft, uint8_t pinRight, uint8_t pinPress,
char eventDown, char eventUp, char eventLeft, char eventRight, char eventPressed,
void (*onIntDown)(), void (*onIntUp)(), void (*onIntLeft)(), void (*onIntRight)(),
void (*onIntPress)())
input_broker_event eventDown, input_broker_event eventUp, input_broker_event eventLeft,
input_broker_event eventRight, input_broker_event eventPressed, void (*onIntDown)(),
void (*onIntUp)(), void (*onIntLeft)(), void (*onIntRight)(), void (*onIntPress)())
{
this->_pinDown = pinDown;
this->_pinUp = pinUp;
@@ -18,17 +18,26 @@ void TrackballInterruptBase::init(uint8_t pinDown, uint8_t pinUp, uint8_t pinLef
this->_eventRight = eventRight;
this->_eventPressed = eventPressed;
pinMode(pinPress, INPUT_PULLUP);
pinMode(this->_pinDown, INPUT_PULLUP);
pinMode(this->_pinUp, INPUT_PULLUP);
pinMode(this->_pinLeft, INPUT_PULLUP);
pinMode(this->_pinRight, INPUT_PULLUP);
attachInterrupt(pinPress, onIntPress, RISING);
attachInterrupt(this->_pinDown, onIntDown, RISING);
attachInterrupt(this->_pinUp, onIntUp, RISING);
attachInterrupt(this->_pinLeft, onIntLeft, RISING);
attachInterrupt(this->_pinRight, onIntRight, RISING);
if (pinPress != 255) {
pinMode(pinPress, INPUT_PULLUP);
attachInterrupt(pinPress, onIntPress, RISING);
}
if (this->_pinDown != 255) {
pinMode(this->_pinDown, INPUT_PULLUP);
attachInterrupt(this->_pinDown, onIntDown, RISING);
}
if (this->_pinUp != 255) {
pinMode(this->_pinUp, INPUT_PULLUP);
attachInterrupt(this->_pinUp, onIntUp, RISING);
}
if (this->_pinLeft != 255) {
pinMode(this->_pinLeft, INPUT_PULLUP);
attachInterrupt(this->_pinLeft, onIntLeft, RISING);
}
if (this->_pinRight != 255) {
pinMode(this->_pinRight, INPUT_PULLUP);
attachInterrupt(this->_pinRight, onIntRight, RISING);
}
LOG_DEBUG("Trackball GPIO initialized (%d, %d, %d, %d, %d)", this->_pinUp, this->_pinDown, this->_pinLeft, this->_pinRight,
pinPress);
@@ -39,8 +48,25 @@ void TrackballInterruptBase::init(uint8_t pinDown, uint8_t pinUp, uint8_t pinLef
int32_t TrackballInterruptBase::runOnce()
{
InputEvent e;
e.inputEvent = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_NONE;
e.inputEvent = INPUT_BROKER_NONE;
#if defined(T_DECK) // T-deck gets a super-simple debounce on trackball
if (this->action == TB_ACTION_PRESSED) {
// LOG_DEBUG("Trackball event Press");
e.inputEvent = this->_eventPressed;
} else if (this->action == TB_ACTION_UP && lastEvent == TB_ACTION_UP) {
// LOG_DEBUG("Trackball event UP");
e.inputEvent = this->_eventUp;
} else if (this->action == TB_ACTION_DOWN && lastEvent == TB_ACTION_DOWN) {
// LOG_DEBUG("Trackball event DOWN");
e.inputEvent = this->_eventDown;
} else if (this->action == TB_ACTION_LEFT && lastEvent == TB_ACTION_LEFT) {
// LOG_DEBUG("Trackball event LEFT");
e.inputEvent = this->_eventLeft;
} else if (this->action == TB_ACTION_RIGHT && lastEvent == TB_ACTION_RIGHT) {
// LOG_DEBUG("Trackball event RIGHT");
e.inputEvent = this->_eventRight;
}
#else
if (this->action == TB_ACTION_PRESSED) {
// LOG_DEBUG("Trackball event Press");
e.inputEvent = this->_eventPressed;
@@ -57,13 +83,14 @@ int32_t TrackballInterruptBase::runOnce()
// LOG_DEBUG("Trackball event RIGHT");
e.inputEvent = this->_eventRight;
}
#endif
if (e.inputEvent != meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_NONE) {
if (e.inputEvent != INPUT_BROKER_NONE) {
e.source = this->_originName;
e.kbchar = 0x00;
this->notifyObservers(&e);
}
lastEvent = action;
this->action = TB_ACTION_NONE;
return 100;

View File

@@ -7,9 +7,10 @@ class TrackballInterruptBase : public Observable<const InputEvent *>, public con
{
public:
explicit TrackballInterruptBase(const char *name);
void init(uint8_t pinDown, uint8_t pinUp, uint8_t pinLeft, uint8_t pinRight, uint8_t pinPress, char eventDown, char eventUp,
char eventLeft, char eventRight, char eventPressed, void (*onIntDown)(), void (*onIntUp)(), void (*onIntLeft)(),
void (*onIntRight)(), void (*onIntPress)());
void init(uint8_t pinDown, uint8_t pinUp, uint8_t pinLeft, uint8_t pinRight, uint8_t pinPress, input_broker_event eventDown,
input_broker_event eventUp, input_broker_event eventLeft, input_broker_event eventRight,
input_broker_event eventPressed, void (*onIntDown)(), void (*onIntUp)(), void (*onIntLeft)(), void (*onIntRight)(),
void (*onIntPress)());
void intPressHandler();
void intDownHandler();
void intUpHandler();
@@ -35,10 +36,11 @@ class TrackballInterruptBase : public Observable<const InputEvent *>, public con
uint8_t _pinUp = 0;
uint8_t _pinLeft = 0;
uint8_t _pinRight = 0;
char _eventDown = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_NONE;
char _eventUp = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_NONE;
char _eventLeft = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_NONE;
char _eventRight = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_NONE;
char _eventPressed = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_NONE;
input_broker_event _eventDown = INPUT_BROKER_NONE;
input_broker_event _eventUp = INPUT_BROKER_NONE;
input_broker_event _eventLeft = INPUT_BROKER_NONE;
input_broker_event _eventRight = INPUT_BROKER_NONE;
input_broker_event _eventPressed = INPUT_BROKER_NONE;
const char *_originName;
TrackballInterruptBaseActionType lastEvent = TB_ACTION_NONE;
};

View File

@@ -6,30 +6,19 @@ TrackballInterruptImpl1 *trackballInterruptImpl1;
TrackballInterruptImpl1::TrackballInterruptImpl1() : TrackballInterruptBase("trackball1") {}
void TrackballInterruptImpl1::init()
void TrackballInterruptImpl1::init(uint8_t pinDown, uint8_t pinUp, uint8_t pinLeft, uint8_t pinRight, uint8_t pinPress)
{
#if !HAS_TRACKBALL
// Input device is disabled.
return;
#else
uint8_t pinUp = TB_UP;
uint8_t pinDown = TB_DOWN;
uint8_t pinLeft = TB_LEFT;
uint8_t pinRight = TB_RIGHT;
uint8_t pinPress = TB_PRESS;
char eventDown = static_cast<char>(meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_DOWN);
char eventUp = static_cast<char>(meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_UP);
char eventLeft = static_cast<char>(meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_LEFT);
char eventRight = static_cast<char>(meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_RIGHT);
char eventPressed = static_cast<char>(meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_SELECT);
input_broker_event eventDown = INPUT_BROKER_DOWN;
input_broker_event eventUp = INPUT_BROKER_UP;
input_broker_event eventLeft = INPUT_BROKER_LEFT;
input_broker_event eventRight = INPUT_BROKER_RIGHT;
input_broker_event eventPressed = INPUT_BROKER_SELECT;
TrackballInterruptBase::init(pinDown, pinUp, pinLeft, pinRight, pinPress, eventDown, eventUp, eventLeft, eventRight,
eventPressed, TrackballInterruptImpl1::handleIntDown, TrackballInterruptImpl1::handleIntUp,
TrackballInterruptImpl1::handleIntLeft, TrackballInterruptImpl1::handleIntRight,
TrackballInterruptImpl1::handleIntPressed);
inputBroker->registerSource(this);
#endif
}
void TrackballInterruptImpl1::handleIntDown()

View File

@@ -5,7 +5,7 @@ class TrackballInterruptImpl1 : public TrackballInterruptBase
{
public:
TrackballInterruptImpl1();
void init();
void init(uint8_t pinDown, uint8_t pinUp, uint8_t pinLeft, uint8_t pinRight, uint8_t pinPress);
static void handleIntDown();
static void handleIntUp();
static void handleIntLeft();

View File

@@ -6,8 +6,9 @@ UpDownInterruptBase::UpDownInterruptBase(const char *name) : concurrency::OSThre
this->_originName = name;
}
void UpDownInterruptBase::init(uint8_t pinDown, uint8_t pinUp, uint8_t pinPress, char eventDown, char eventUp, char eventPressed,
void (*onIntDown)(), void (*onIntUp)(), void (*onIntPress)())
void UpDownInterruptBase::init(uint8_t pinDown, uint8_t pinUp, uint8_t pinPress, input_broker_event eventDown,
input_broker_event eventUp, input_broker_event eventPressed, void (*onIntDown)(),
void (*onIntUp)(), void (*onIntPress)())
{
this->_pinDown = pinDown;
this->_pinUp = pinUp;
@@ -31,7 +32,7 @@ void UpDownInterruptBase::init(uint8_t pinDown, uint8_t pinUp, uint8_t pinPress,
int32_t UpDownInterruptBase::runOnce()
{
InputEvent e;
e.inputEvent = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_NONE;
e.inputEvent = INPUT_BROKER_NONE;
if (this->action == UPDOWN_ACTION_PRESSED) {
LOG_DEBUG("GPIO event Press");
@@ -44,9 +45,9 @@ int32_t UpDownInterruptBase::runOnce()
e.inputEvent = this->_eventDown;
}
if (e.inputEvent != meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_NONE) {
if (e.inputEvent != INPUT_BROKER_NONE) {
e.source = this->_originName;
e.kbchar = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_NONE;
e.kbchar = INPUT_BROKER_NONE;
this->notifyObservers(&e);
}

View File

@@ -7,8 +7,8 @@ class UpDownInterruptBase : public Observable<const InputEvent *>, public concur
{
public:
explicit UpDownInterruptBase(const char *name);
void init(uint8_t pinDown, uint8_t pinUp, uint8_t pinPress, char eventDown, char eventUp, char eventPressed,
void (*onIntDown)(), void (*onIntUp)(), void (*onIntPress)());
void init(uint8_t pinDown, uint8_t pinUp, uint8_t pinPress, input_broker_event eventDown, input_broker_event eventUp,
input_broker_event eventPressed, void (*onIntDown)(), void (*onIntUp)(), void (*onIntPress)());
void intPressHandler();
void intDownHandler();
void intUpHandler();
@@ -23,8 +23,8 @@ class UpDownInterruptBase : public Observable<const InputEvent *>, public concur
private:
uint8_t _pinDown = 0;
uint8_t _pinUp = 0;
char _eventDown = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_NONE;
char _eventUp = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_NONE;
char _eventPressed = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_NONE;
input_broker_event _eventDown = INPUT_BROKER_NONE;
input_broker_event _eventUp = INPUT_BROKER_NONE;
input_broker_event _eventPressed = INPUT_BROKER_NONE;
const char *_originName;
};

View File

@@ -17,9 +17,9 @@ bool UpDownInterruptImpl1::init()
uint8_t pinDown = moduleConfig.canned_message.inputbroker_pin_b;
uint8_t pinPress = moduleConfig.canned_message.inputbroker_pin_press;
char eventDown = static_cast<char>(meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_DOWN);
char eventUp = static_cast<char>(meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_UP);
char eventPressed = static_cast<char>(meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_SELECT);
input_broker_event eventDown = INPUT_BROKER_DOWN;
input_broker_event eventUp = INPUT_BROKER_UP;
input_broker_event eventPressed = INPUT_BROKER_SELECT;
UpDownInterruptBase::init(pinDown, pinUp, pinPress, eventDown, eventUp, eventPressed, UpDownInterruptImpl1::handleIntDown,
UpDownInterruptImpl1::handleIntUp, UpDownInterruptImpl1::handleIntPressed);

View File

@@ -75,94 +75,94 @@ int32_t KbI2cBase::runOnce()
const BBQ10Keyboard::KeyEvent key = Q10keyboard.keyEvent();
if ((key.key != 0x00) && (key.state == BBQ10Keyboard::StateRelease)) {
InputEvent e;
e.inputEvent = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_NONE;
e.inputEvent = INPUT_BROKER_NONE;
e.source = this->_originName;
switch (key.key) {
case 'p': // TAB
case 't': // TAB as well
if (is_sym) {
e.inputEvent = ANYKEY;
e.inputEvent = INPUT_BROKER_ANYKEY;
e.kbchar = 0x09; // TAB Scancode
is_sym = false; // reset sym state after second keypress
} else {
e.inputEvent = ANYKEY;
e.inputEvent = INPUT_BROKER_ANYKEY;
e.kbchar = key.key;
}
break;
case 'q': // ESC
if (is_sym) {
e.inputEvent = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_CANCEL;
e.kbchar = 0x1b;
e.inputEvent = INPUT_BROKER_CANCEL;
e.kbchar = 0;
is_sym = false; // reset sym state after second keypress
} else {
e.inputEvent = ANYKEY;
e.inputEvent = INPUT_BROKER_ANYKEY;
e.kbchar = key.key;
}
break;
case 0x08: // Back
e.inputEvent = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_BACK;
e.inputEvent = INPUT_BROKER_BACK;
e.kbchar = key.key;
break;
case 'e': // sym e
if (is_sym) {
e.inputEvent = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_UP;
e.kbchar = INPUT_BROKER_MSG_UP;
e.inputEvent = INPUT_BROKER_UP;
e.kbchar = INPUT_BROKER_UP;
is_sym = false; // reset sym state after second keypress
} else {
e.inputEvent = ANYKEY;
e.inputEvent = INPUT_BROKER_ANYKEY;
e.kbchar = key.key;
}
break;
case 'x': // sym x
if (is_sym) {
e.inputEvent = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_DOWN;
e.kbchar = INPUT_BROKER_MSG_DOWN;
e.inputEvent = INPUT_BROKER_DOWN;
e.kbchar = 0;
is_sym = false; // reset sym state after second keypress
} else {
e.inputEvent = ANYKEY;
e.inputEvent = INPUT_BROKER_ANYKEY;
e.kbchar = key.key;
}
break;
case 's': // sym s
if (is_sym) {
e.inputEvent = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_LEFT;
e.inputEvent = INPUT_BROKER_LEFT;
e.kbchar = 0x00; // tweak for destSelect
is_sym = false; // reset sym state after second keypress
} else {
e.inputEvent = ANYKEY;
e.inputEvent = INPUT_BROKER_ANYKEY;
e.kbchar = key.key;
}
break;
case 'f': // sym f
if (is_sym) {
e.inputEvent = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_RIGHT;
e.inputEvent = INPUT_BROKER_RIGHT;
e.kbchar = 0x00; // tweak for destSelect
is_sym = false; // reset sym state after second keypress
} else {
e.inputEvent = ANYKEY;
e.inputEvent = INPUT_BROKER_ANYKEY;
e.kbchar = key.key;
}
break;
case 0x13: // Code scanner says the SYM key is 0x13
is_sym = !is_sym;
e.inputEvent = ANYKEY;
e.inputEvent = INPUT_BROKER_ANYKEY;
e.kbchar = is_sym ? INPUT_BROKER_MSG_FN_SYMBOL_ON // send 0xf1 to tell CannedMessages to display that
: INPUT_BROKER_MSG_FN_SYMBOL_OFF; // the modifier key is active
break;
case 0x0a: // apparently Enter on Q10 is a line feed instead of carriage return
e.inputEvent = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_SELECT;
e.inputEvent = INPUT_BROKER_SELECT;
break;
case 0x00: // nopress
e.inputEvent = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_NONE;
e.inputEvent = INPUT_BROKER_NONE;
break;
default: // all other keys
e.inputEvent = ANYKEY;
e.inputEvent = INPUT_BROKER_ANYKEY;
e.kbchar = key.key;
is_sym = false; // reset sym state after second keypress
break;
}
if (e.inputEvent != meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_NONE) {
if (e.inputEvent != INPUT_BROKER_NONE) {
this->notifyObservers(&e);
}
}
@@ -175,57 +175,57 @@ int32_t KbI2cBase::runOnce()
while (MPRkeyboard.hasEvent()) {
char nextEvent = MPRkeyboard.dequeueEvent();
e.inputEvent = ANYKEY;
e.inputEvent = INPUT_BROKER_ANYKEY;
e.kbchar = 0x00;
e.source = this->_originName;
switch (nextEvent) {
case 0x00: // MPR121_NONE
e.inputEvent = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_NONE;
e.inputEvent = INPUT_BROKER_NONE;
e.kbchar = 0x00;
break;
case 0x90: // MPR121_REBOOT
e.inputEvent = ANYKEY;
e.inputEvent = INPUT_BROKER_ANYKEY;
e.kbchar = INPUT_BROKER_MSG_REBOOT;
break;
case 0xb4: // MPR121_LEFT
e.inputEvent = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_LEFT;
e.inputEvent = INPUT_BROKER_LEFT;
e.kbchar = 0x00;
break;
case 0xb5: // MPR121_UP
e.inputEvent = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_UP;
e.inputEvent = INPUT_BROKER_UP;
e.kbchar = 0x00;
break;
case 0xb6: // MPR121_DOWN
e.inputEvent = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_DOWN;
e.inputEvent = INPUT_BROKER_DOWN;
e.kbchar = 0x00;
break;
case 0xb7: // MPR121_RIGHT
e.inputEvent = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_RIGHT;
e.inputEvent = INPUT_BROKER_RIGHT;
e.kbchar = 0x00;
break;
case 0x1b: // MPR121_ESC
e.inputEvent = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_CANCEL;
e.kbchar = 0x1b;
e.inputEvent = INPUT_BROKER_CANCEL;
e.kbchar = 0;
break;
case 0x08: // MPR121_BSP
e.inputEvent = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_BACK;
e.inputEvent = INPUT_BROKER_BACK;
e.kbchar = 0x08;
break;
case 0x0d: // MPR121_SELECT
e.inputEvent = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_SELECT;
e.kbchar = 0x0d;
e.inputEvent = INPUT_BROKER_SELECT;
e.kbchar = 0x00;
break;
default:
if (nextEvent > 127) {
e.inputEvent = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_NONE;
e.inputEvent = INPUT_BROKER_NONE;
e.kbchar = 0x00;
break;
}
e.inputEvent = ANYKEY;
e.inputEvent = INPUT_BROKER_ANYKEY;
e.kbchar = nextEvent;
break;
}
if (e.inputEvent != meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_NONE) {
if (e.inputEvent != INPUT_BROKER_NONE) {
LOG_DEBUG("MP121 Notifying: %i Char: %i", e.inputEvent, e.kbchar);
this->notifyObservers(&e);
}
@@ -237,57 +237,57 @@ int32_t KbI2cBase::runOnce()
InputEvent e;
while (TCAKeyboard.hasEvent()) {
char nextEvent = TCAKeyboard.dequeueEvent();
e.inputEvent = ANYKEY;
e.inputEvent = INPUT_BROKER_ANYKEY;
e.kbchar = 0x00;
e.source = this->_originName;
switch (nextEvent) {
case _TCA8418_NONE:
e.inputEvent = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_NONE;
e.inputEvent = INPUT_BROKER_NONE;
e.kbchar = 0x00;
break;
case _TCA8418_REBOOT:
e.inputEvent = ANYKEY;
e.inputEvent = INPUT_BROKER_ANYKEY;
e.kbchar = INPUT_BROKER_MSG_REBOOT;
break;
case _TCA8418_LEFT:
e.inputEvent = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_LEFT;
e.inputEvent = INPUT_BROKER_LEFT;
e.kbchar = 0x00;
break;
case _TCA8418_UP:
e.inputEvent = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_UP;
e.inputEvent = INPUT_BROKER_UP;
e.kbchar = 0x00;
break;
case _TCA8418_DOWN:
e.inputEvent = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_DOWN;
e.inputEvent = INPUT_BROKER_DOWN;
e.kbchar = 0x00;
break;
case _TCA8418_RIGHT:
e.inputEvent = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_RIGHT;
e.inputEvent = INPUT_BROKER_RIGHT;
e.kbchar = 0x00;
break;
case _TCA8418_BSP:
e.inputEvent = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_BACK;
e.inputEvent = INPUT_BROKER_BACK;
e.kbchar = 0x08;
break;
case _TCA8418_SELECT:
e.inputEvent = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_SELECT;
e.kbchar = 0x0d;
e.inputEvent = INPUT_BROKER_SELECT;
e.kbchar = 0x00;
break;
case _TCA8418_ESC:
e.inputEvent = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_CANCEL;
e.kbchar = 0x1b;
e.inputEvent = INPUT_BROKER_CANCEL;
e.kbchar = 0;
break;
default:
if (nextEvent > 127) {
e.inputEvent = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_NONE;
e.inputEvent = INPUT_BROKER_NONE;
e.kbchar = 0x00;
break;
}
e.inputEvent = ANYKEY;
e.inputEvent = INPUT_BROKER_ANYKEY;
e.kbchar = nextEvent;
break;
}
if (e.inputEvent != meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_NONE) {
if (e.inputEvent != INPUT_BROKER_NONE) {
LOG_DEBUG("TCA8418 Notifying: %i Char: %c", e.inputEvent, e.kbchar);
this->notifyObservers(&e);
}
@@ -310,7 +310,7 @@ int32_t KbI2cBase::runOnce()
if (PrintDataBuf != 0) {
LOG_DEBUG("RAK14004 key 0x%x pressed", PrintDataBuf);
InputEvent e;
e.inputEvent = MATRIXKEY;
e.inputEvent = INPUT_BROKER_MATRIXKEY;
e.source = this->_originName;
e.kbchar = PrintDataBuf;
this->notifyObservers(&e);
@@ -325,138 +325,150 @@ int32_t KbI2cBase::runOnce()
if (i2cBus->available()) {
char c = i2cBus->read();
InputEvent e;
e.inputEvent = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_NONE;
e.inputEvent = INPUT_BROKER_NONE;
e.source = this->_originName;
switch (c) {
case 0x71: // This is the button q. If modifier and q pressed, it cancels the input
if (is_sym) {
is_sym = false;
e.inputEvent = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_CANCEL;
e.inputEvent = INPUT_BROKER_CANCEL;
} else {
e.inputEvent = ANYKEY;
e.inputEvent = INPUT_BROKER_ANYKEY;
e.kbchar = c;
}
break;
case 0x74: // letter t. if modifier and t pressed call 'tab'
if (is_sym) {
is_sym = false;
e.inputEvent = ANYKEY;
e.inputEvent = INPUT_BROKER_ANYKEY;
e.kbchar = 0x09; // TAB Scancode
} else {
e.inputEvent = ANYKEY;
e.inputEvent = INPUT_BROKER_ANYKEY;
e.kbchar = c;
}
break;
case 0x6d: // letter m. Modifier makes it mute notifications
if (is_sym) {
is_sym = false;
e.inputEvent = ANYKEY;
e.inputEvent = INPUT_BROKER_ANYKEY;
e.kbchar = INPUT_BROKER_MSG_MUTE_TOGGLE; // mute notifications
} else {
e.inputEvent = ANYKEY;
e.inputEvent = INPUT_BROKER_ANYKEY;
e.kbchar = c;
}
break;
case 0x6f: // letter o(+). Modifier makes screen increase in brightness
if (is_sym) {
is_sym = false;
e.inputEvent = ANYKEY;
e.inputEvent = INPUT_BROKER_ANYKEY;
e.kbchar = INPUT_BROKER_MSG_BRIGHTNESS_UP; // Increase Brightness code
} else {
e.inputEvent = ANYKEY;
e.inputEvent = INPUT_BROKER_ANYKEY;
e.kbchar = c;
}
break;
case 0x69: // letter i(-). Modifier makes screen decrease in brightness
if (is_sym) {
is_sym = false;
e.inputEvent = ANYKEY;
e.inputEvent = INPUT_BROKER_ANYKEY;
e.kbchar = INPUT_BROKER_MSG_BRIGHTNESS_DOWN; // Decrease Brightness code
} else {
e.inputEvent = ANYKEY;
e.inputEvent = INPUT_BROKER_ANYKEY;
e.kbchar = c;
}
break;
case 0x20: // Space. Send network ping like double press does
if (is_sym) {
is_sym = false;
e.inputEvent = ANYKEY;
e.kbchar = INPUT_BROKER_MSG_SEND_PING; // (fn + space)
e.inputEvent = INPUT_BROKER_ANYKEY;
e.kbchar = INPUT_BROKER_SEND_PING; // (fn + space)
} else {
e.inputEvent = ANYKEY;
e.inputEvent = INPUT_BROKER_ANYKEY;
e.kbchar = c;
}
break;
case 0x67: // letter g. toggle gps
if (is_sym) {
is_sym = false;
e.inputEvent = ANYKEY;
e.kbchar = INPUT_BROKER_MSG_GPS_TOGGLE;
e.inputEvent = INPUT_BROKER_GPS_TOGGLE;
e.kbchar = INPUT_BROKER_GPS_TOGGLE;
} else {
e.inputEvent = ANYKEY;
e.inputEvent = INPUT_BROKER_ANYKEY;
e.kbchar = c;
}
break;
case 0x1b: // ESC
e.inputEvent = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_CANCEL;
e.inputEvent = INPUT_BROKER_CANCEL;
break;
case 0x08: // Back
e.inputEvent = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_BACK;
e.kbchar = c;
e.inputEvent = INPUT_BROKER_BACK;
e.kbchar = 0;
break;
case 0xb5: // Up
e.inputEvent = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_UP;
e.kbchar = INPUT_BROKER_MSG_UP;
e.inputEvent = INPUT_BROKER_UP;
e.kbchar = 0;
break;
case 0xb6: // Down
e.inputEvent = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_DOWN;
e.kbchar = INPUT_BROKER_MSG_DOWN;
e.inputEvent = INPUT_BROKER_DOWN;
e.kbchar = 0;
break;
case 0xb4: // Left
e.inputEvent = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_LEFT;
e.kbchar = INPUT_BROKER_MSG_LEFT;
e.inputEvent = INPUT_BROKER_LEFT;
e.kbchar = 0;
break;
case 0xb7: // Right
e.inputEvent = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_RIGHT;
e.kbchar = INPUT_BROKER_MSG_RIGHT;
e.inputEvent = INPUT_BROKER_RIGHT;
e.kbchar = 0;
break;
case 0xc: // Modifier key: 0xc is alt+c (Other options could be: 0xea = shift+mic button or 0x4 shift+$(speaker))
// toggle moddifiers button.
is_sym = !is_sym;
e.inputEvent = ANYKEY;
e.inputEvent = INPUT_BROKER_ANYKEY;
e.kbchar = is_sym ? INPUT_BROKER_MSG_FN_SYMBOL_ON // send 0xf1 to tell CannedMessages to display that the
: INPUT_BROKER_MSG_FN_SYMBOL_OFF; // modifier key is active
break;
case 0x9e: // fn+g INPUT_BROKER_GPS_TOGGLE
e.inputEvent = INPUT_BROKER_GPS_TOGGLE;
e.kbchar = c;
break;
case 0xaf: // fn+space INPUT_BROKER_SEND_PING
e.inputEvent = INPUT_BROKER_SEND_PING;
e.kbchar = c;
break;
case 0x9b: // fn+s INPUT_BROKER_MSG_SHUTDOWN
e.inputEvent = INPUT_BROKER_SHUTDOWN;
e.kbchar = c;
break;
case 0x90: // fn+r INPUT_BROKER_MSG_REBOOT
case 0x91: // fn+t
case 0x9b: // fn+s INPUT_BROKER_MSG_SHUTDOWN
case 0xac: // fn+m INPUT_BROKER_MSG_MUTE_TOGGLE
case 0x9e: // fn+g INPUT_BROKER_MSG_GPS_TOGGLE
case 0xaf: // fn+space INPUT_BROKER_MSG_SEND_PING
case 0x8b: // fn+del INPUT_BROKEN_MSG_DISMISS_FRAME
case 0xAA: // fn+b INPUT_BROKER_MSG_BLUETOOTH_TOGGLE
case 0x8F: // fn+e INPUT_BROKER_MSG_EMOTE_LIST
// just pass those unmodified
e.inputEvent = ANYKEY;
e.inputEvent = INPUT_BROKER_ANYKEY;
e.kbchar = c;
break;
case 0x0d: // Enter
e.inputEvent = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_SELECT;
e.inputEvent = INPUT_BROKER_SELECT;
break;
case 0x00: // nopress
e.inputEvent = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_NONE;
e.inputEvent = INPUT_BROKER_NONE;
break;
default: // all other keys
if (c > 127) { // bogus key value
e.inputEvent = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_NONE;
e.inputEvent = INPUT_BROKER_NONE;
break;
}
e.inputEvent = ANYKEY;
e.inputEvent = INPUT_BROKER_ANYKEY;
e.kbchar = c;
is_sym = false;
break;
}
if (e.inputEvent != meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_NONE) {
if (e.inputEvent != INPUT_BROKER_NONE) {
this->notifyObservers(&e);
}
}

View File

@@ -73,35 +73,35 @@ int32_t KbMatrixBase::runOnce()
LOG_DEBUG("Key 0x%x pressed", key);
// reset shift now that we have a keypress
InputEvent e;
e.inputEvent = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_NONE;
e.inputEvent = INPUT_BROKER_NONE;
e.source = this->_originName;
switch (key) {
case 0x1b: // ESC
e.inputEvent = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_CANCEL;
e.inputEvent = INPUT_BROKER_CANCEL;
break;
case 0x08: // Back
e.inputEvent = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_BACK;
e.kbchar = key;
e.inputEvent = INPUT_BROKER_BACK;
e.kbchar = 0;
break;
case 0xb5: // Up
e.inputEvent = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_UP;
e.inputEvent = INPUT_BROKER_UP;
break;
case 0xb6: // Down
e.inputEvent = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_DOWN;
e.inputEvent = INPUT_BROKER_DOWN;
break;
case 0xb4: // Left
e.inputEvent = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_LEFT;
e.kbchar = key;
e.inputEvent = INPUT_BROKER_LEFT;
e.kbchar = 0;
break;
case 0xb7: // Right
e.inputEvent = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_RIGHT;
e.kbchar = key;
e.inputEvent = INPUT_BROKER_RIGHT;
e.kbchar = 0;
break;
case 0x0d: // Enter
e.inputEvent = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_SELECT;
e.inputEvent = INPUT_BROKER_SELECT;
break;
case 0x00: // nopress
e.inputEvent = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_NONE;
e.inputEvent = INPUT_BROKER_NONE;
break;
case 0x1a: // Shift
shift++;
@@ -110,11 +110,11 @@ int32_t KbMatrixBase::runOnce()
}
break;
default: // all other keys
e.inputEvent = ANYKEY;
e.inputEvent = INPUT_BROKER_ANYKEY;
e.kbchar = key;
break;
}
if (e.inputEvent != meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_NONE) {
if (e.inputEvent != INPUT_BROKER_NONE) {
this->notifyObservers(&e);
}
}