mirror of
https://github.com/meshtastic/firmware.git
synced 2025-12-31 23:21:06 +00:00
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:
318
src/input/ButtonThread.cpp
Normal file
318
src/input/ButtonThread.cpp
Normal 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(¬ifyLightSleep);
|
||||
lsEndObserver.observe(¬ifyLightSleepEnd);
|
||||
#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
113
src/input/ButtonThread.h
Normal 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;
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
};
|
||||
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user