Added modifier key combination to allow keyboard shortcuts on t-deck (#3668)

* Updated kbI2cBase.cpp

Updated keyboard settings for t-deck to allow a modifier key to trigger 'tab', mute notifications, or quit. To trigger the modifier press the shift key and mic (0) button at the same time. Then press q (quit), m (mute), or t (tab).

* Update kbI2cBase.cpp

* fixed formatting issues in kbI2cBase.cpp

* Removed keyboard shortcut code that doesnt work

alt+t does not work on a t-deck so I removed it to avoid confusion.

* Updated kbI2cBase.cpp

Updated keyboard settings for t-deck to allow a modifier key to trigger 'tab', mute notifications, or quit. To trigger the modifier press the shift key and mic (0) button at the same time. Then press q (quit), m (mute), or t (tab).

* Update kbI2cBase.cpp

* fixed formatting issues in kbI2cBase.cpp

* Removed keyboard shortcut code that doesnt work

alt+t does not work on a t-deck so I removed it to avoid confusion.

* Changed modifier key to alt+c

* Added screen brightness functionality

Use modifier key with o(+) to increase brightness or i(-) to decrease.

Currently there are 4 levels of brightness, (L, ML, MH, H). I would like to add a popup message to tell you the brightness.

* Added checks to disable screen brightness changes on unsupported hardware

* Setting the brightness code to work on only applicable devices

* Added "function symbol" display to bottom right corner of screen. Now shows when mute is active or modifier key is pressed. Also fixed some other minor issues.

* commented out a log

* Reworked how modifier functions worked, added

I wasn’t  happy with my previous implementation, and I think it would have caused issues with other devices. This should work on all devices.

* Added back the function I moved causing issue with versions

* Fixed the version conflicts, everything seems to work fine now

---------

Co-authored-by: Ben Meadors <benmmeadors@gmail.com>
Co-authored-by: Thomas Göttgens <tgoettgens@gmail.com>
pull/3842/head
Nicholas Baddorf 2024-05-08 08:37:50 -04:00 zatwierdzone przez GitHub
rodzic 5371f134ba
commit 147de75a02
Nie znaleziono w bazie danych klucza dla tego podpisu
ID klucza GPG: B5690EEEBB952194
7 zmienionych plików z 253 dodań i 48 usunięć

Wyświetl plik

@ -94,6 +94,11 @@ std::vector<MeshModule *> moduleFrames;
// Stores the last 4 of our hardware ID, to make finding the device for pairing easier
static char ourId[5];
// vector where symbols (string) are displayed in bottom corner of display.
std::vector<std::string> functionSymbals;
// string displayed in bottom right corner of display. Created from elements in functionSymbals vector
std::string functionSymbalString = "";
#if HAS_GPS
// GeoCoord object for the screen
GeoCoord geoCoord;
@ -260,6 +265,18 @@ static void drawWelcomeScreen(OLEDDisplay *display, OLEDDisplayUiState *state, i
#endif
}
// draw overlay in bottom right corner of screen to show when notifications are muted or modifier key is active
static void drawFunctionOverlay(OLEDDisplay *display, OLEDDisplayUiState *state)
{
// LOG_DEBUG("Drawing function overlay\n");
if (functionSymbals.begin() != functionSymbals.end()) {
char buf[64];
display->setFont(FONT_SMALL);
snprintf(buf, sizeof(buf), "%s", functionSymbalString.c_str());
display->drawString(SCREEN_WIDTH - display->getStringWidth(buf), SCREEN_HEIGHT - FONT_HEIGHT_SMALL, buf);
}
}
#ifdef USE_EINK
/// Used on eink displays while in deep sleep
static void drawDeepSleepScreen(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y)
@ -1023,7 +1040,14 @@ void Screen::handleSetOn(bool on, FrameCallback einkScreensaver)
#if !ARCH_PORTDUINO
dispdev->displayOn();
#endif
#if defined(ST7789_CS) && \
!defined(M5STACK) // set display brightness when turning on screens. Just moved function from TFTDisplay to here.
static_cast<TFTDisplay *>(dispdev)->setDisplayBrightness(brightness);
#endif
dispdev->displayOn();
enabled = true;
setInterval(0); // Draw ASAP
runASAP = true;
@ -1490,6 +1514,11 @@ void Screen::setFrames()
ui->setFrames(normalFrames, numframes);
ui->enableAllIndicators();
// Add function overlay here. This can show when notifications muted, modifier key is active etc
static OverlayCallback functionOverlay[] = {drawFunctionOverlay};
static const int functionOverlayCount = sizeof(functionOverlay) / sizeof(functionOverlay[0]);
ui->setOverlays(functionOverlay, functionOverlayCount);
prevFrame = -1; // Force drawNodeInfo to pick a new node (because our list
// just changed)
@ -1573,9 +1602,55 @@ void Screen::blink()
delay(50);
count = count - 1;
}
// The dispdev->setBrightness does not work for t-deck display, it seems to run the setBrightness function in OLEDDisplay.
dispdev->setBrightness(brightness);
}
void Screen::increaseBrightness()
{
brightness = ((brightness + 62) > 254) ? brightness : (brightness + 62);
#if defined(ST7789_CS)
// run the setDisplayBrightness function. This works on t-decks
static_cast<TFTDisplay *>(dispdev)->setDisplayBrightness(brightness);
#endif
/* TO DO: add little popup in center of screen saying what brightness level it is set to*/
}
void Screen::decreaseBrightness()
{
brightness = (brightness < 70) ? brightness : (brightness - 62);
#if defined(ST7789_CS)
static_cast<TFTDisplay *>(dispdev)->setDisplayBrightness(brightness);
#endif
/* TO DO: add little popup in center of screen saying what brightness level it is set to*/
}
void Screen::setFunctionSymbal(std::string sym)
{
if (std::find(functionSymbals.begin(), functionSymbals.end(), sym) == functionSymbals.end()) {
functionSymbals.push_back(sym);
functionSymbalString = "";
for (auto symbol : functionSymbals) {
functionSymbalString = symbol + " " + functionSymbalString;
}
setFastFramerate();
}
}
void Screen::removeFunctionSymbal(std::string sym)
{
functionSymbals.erase(std::remove(functionSymbals.begin(), functionSymbals.end(), sym), functionSymbals.end());
functionSymbalString = "";
for (auto symbol : functionSymbals) {
functionSymbalString = symbol + " " + functionSymbalString;
}
setFastFramerate();
}
std::string Screen::drawTimeDelta(uint32_t days, uint32_t hours, uint32_t minutes, uint32_t seconds)
{
std::string uptime;
@ -1998,4 +2073,4 @@ int Screen::handleInputEvent(const InputEvent *event)
} // namespace graphics
#else
graphics::Screen::Screen(ScanI2C::DeviceAddress, meshtastic_Config_DisplayConfig_OledType, OLEDDISPLAY_GEOMETRY) {}
#endif // HAS_SCREEN
#endif // HAS_SCREEN

Wyświetl plik

@ -166,9 +166,6 @@ class Screen : public concurrency::OSThread
void showPrevFrame() { enqueueCmd(ScreenCmd{.cmd = Cmd::SHOW_PREV_FRAME}); }
void showNextFrame() { enqueueCmd(ScreenCmd{.cmd = Cmd::SHOW_NEXT_FRAME}); }
// Implementation to Adjust Brightness
uint8_t brightness = BRIGHTNESS_DEFAULT;
/// Starts showing the Bluetooth PIN screen.
//
// Switches over to a static frame showing the Bluetooth pairing screen
@ -202,6 +199,13 @@ class Screen : public concurrency::OSThread
enqueueCmd(cmd);
}
// functions for display brightness
void increaseBrightness();
void decreaseBrightness();
void setFunctionSymbal(std::string sym);
void removeFunctionSymbal(std::string sym);
/// Stops showing the bluetooth PIN screen.
void stopBluetoothPinScreen() { enqueueCmd(ScreenCmd{.cmd = Cmd::STOP_BLUETOOTH_PIN_SCREEN}); }
@ -395,6 +399,9 @@ class Screen : public concurrency::OSThread
// Bluetooth PIN screen)
bool showingNormalScreen = false;
// Implementation to Adjust Brightness
uint8_t brightness = BRIGHTNESS_DEFAULT; // H = 254, MH = 192, ML = 130 L = 103
/// Holds state for debug information
DebugInfo debugInfo;

Wyświetl plik

@ -596,7 +596,7 @@ void TFTDisplay::sendCommand(uint8_t com)
unphone.backlight(true); // using unPhone library
#endif
#ifdef RAK14014
#elif !defined(M5STACK)
#elif !defined(M5STACK) && !defined(ST7789_CS) // T-Deck gets brightness set in Screen.cpp in the handleSetOn function
tft->setBrightness(172);
#endif
break;
@ -640,6 +640,12 @@ void TFTDisplay::sendCommand(uint8_t com)
// Drop all other commands to device (we just update the buffer)
}
void TFTDisplay::setDisplayBrightness(uint8_t _brightness)
{
tft->setBrightness(_brightness);
LOG_DEBUG("Brightness is set to value: %i \n", _brightness);
}
void TFTDisplay::flipScreenVertically()
{
#if defined(T_WATCH_S3)

Wyświetl plik

@ -30,6 +30,9 @@ class TFTDisplay : public OLEDDisplay
static bool hasTouch(void);
static bool getTouch(int16_t *x, int16_t *y);
// Functions for changing display brightness
void setDisplayBrightness(uint8_t);
/**
* shim to make the abstraction happy
*

Wyświetl plik

@ -1,5 +1,4 @@
#include "kbI2cBase.h"
#include "configuration.h"
#include "detect/ScanI2C.h"
@ -138,6 +137,9 @@ int32_t KbI2cBase::runOnce()
break;
case 0x13: // Code scanner says the SYM key is 0x13
is_sym = !is_sym;
e.inputEvent = ANYKEY;
e.kbchar =
is_sym ? 0xf1 : 0xf2; // send 0xf1 to tell CannedMessages to display that 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;
@ -193,6 +195,75 @@ int32_t KbI2cBase::runOnce()
e.inputEvent = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_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;
} else {
e.inputEvent = 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.kbchar = 0x09; // TAB Scancode
} else {
e.inputEvent = ANYKEY;
e.kbchar = c;
}
break;
case 0x6d: // letter m. Modifier makes it mute notifications
if (is_sym) {
is_sym = false;
e.inputEvent = ANYKEY;
e.kbchar = 0xac; // mute notifications
} else {
e.inputEvent = 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.kbchar = 0x11; // Increase Brightness code
} else {
e.inputEvent = 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.kbchar = 0x12; // Decrease Brightness code
} else {
e.inputEvent = 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 = 0xaf; // (fn + space)
} else {
e.inputEvent = ANYKEY;
e.kbchar = c;
}
break;
case 0x67: // letter g. toggle gps
if (is_sym) {
is_sym = false;
e.inputEvent = ANYKEY;
e.kbchar = 0x9e;
} else {
e.inputEvent = ANYKEY;
e.kbchar = c;
}
break;
case 0x1b: // ESC
e.inputEvent = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_CANCEL;
break;
@ -216,6 +287,12 @@ int32_t KbI2cBase::runOnce()
e.inputEvent = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_RIGHT;
e.kbchar = 0xb7;
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.kbchar = is_sym ? 0xf1 : 0xf2; // send 0xf1 to tell CannedMessages to display that the modifier key is active
break;
case 0x90: // fn+r
case 0x91: // fn+t
case 0x9b: // fn+s
@ -239,6 +316,7 @@ int32_t KbI2cBase::runOnce()
}
e.inputEvent = ANYKEY;
e.kbchar = c;
is_sym = false;
break;
}

Wyświetl plik

@ -180,11 +180,75 @@ int CannedMessageModule::handleInputEvent(const InputEvent *event)
(this->runState == CANNED_MESSAGE_RUN_STATE_DISABLED)) {
this->runState = CANNED_MESSAGE_RUN_STATE_FREETEXT;
}
// pass the pressed key
// LOG_DEBUG("Canned message ANYKEY (%x)\n", event->kbchar);
this->payload = event->kbchar;
this->lastTouchMillis = millis();
validEvent = true;
validEvent = false; // If key is normal than it will be set to true.
// Run modifier key code below, (doesnt inturrupt typing or reset to start screen page)
switch (event->kbchar) {
case 0x11: // make screen brighter
if (screen)
screen->increaseBrightness();
LOG_DEBUG("increasing Screen Brightness\n");
break;
case 0x12: // make screen dimmer
if (screen)
screen->decreaseBrightness();
LOG_DEBUG("Decreasing Screen Brightness\n");
break;
case 0xf1: // draw modifier (function) symbal
if (screen)
screen->setFunctionSymbal("Fn");
break;
case 0xf2: // remove modifier (function) symbal
if (screen)
screen->removeFunctionSymbal("Fn");
break;
// mute (switch off/toggle) external notifications on fn+m
case 0xac:
if (moduleConfig.external_notification.enabled == true) {
if (externalNotificationModule->getMute()) {
externalNotificationModule->setMute(false);
showTemporaryMessage("Notifications \nEnabled");
if (screen)
screen->removeFunctionSymbal("M"); // remove the mute symbol from the bottom right corner
} else {
externalNotificationModule->stopNow(); // this will turn off all GPIO and sounds and idle the loop
externalNotificationModule->setMute(true);
showTemporaryMessage("Notifications \nDisabled");
if (screen)
screen->setFunctionSymbal("M"); // add the mute symbol to the bottom right corner
}
}
break;
case 0x9e: // toggle GPS like triple press does
#if !MESHTASTIC_EXCLUDE_GPS
if (gps != nullptr) {
gps->toggleGpsMode();
}
if (screen)
screen->forceDisplay();
showTemporaryMessage("GPS Toggled");
#endif
break;
case 0xaf: // fn+space send network ping like double press does
service.refreshLocalMeshNode();
if (service.trySendPosition(NODENUM_BROADCAST, true)) {
showTemporaryMessage("Position \nUpdate Sent");
} else {
showTemporaryMessage("Node Info \nUpdate Sent");
}
break;
default:
// pass the pressed key
// LOG_DEBUG("Canned message ANYKEY (%x)\n", event->kbchar);
this->payload = event->kbchar;
this->lastTouchMillis = millis();
validEvent = true;
break;
}
if (screen && (event->kbchar != 0xf1)) {
screen->removeFunctionSymbal("Fn"); // remove modifier (function) symbal
}
}
if (event->inputEvent == static_cast<char>(MATRIXKEY)) {
LOG_DEBUG("Canned message event Matrix key pressed\n");
@ -390,8 +454,9 @@ int32_t CannedMessageModule::runOnce()
}
if (this->runState == CANNED_MESSAGE_RUN_STATE_FREETEXT) {
e.frameChanged = true;
switch (this->payload) {
case 0x08: // backspace
switch (this->payload) { // code below all trigger the freetext window (where you type to send a message) or reset the
// display back to the default window
case 0x08: // backspace
if (this->freetext.length() > 0) {
if (this->cursor == this->freetext.length()) {
this->freetext = this->freetext.substring(0, this->freetext.length() - 1);
@ -403,7 +468,6 @@ int32_t CannedMessageModule::runOnce()
}
break;
case 0x09: // tab
case 0x91: // alt+t for T-Deck that doesn't have a tab key
if (this->destSelect == CANNED_MESSAGE_DESTINATION_TYPE_CHANNEL) {
this->destSelect = CANNED_MESSAGE_DESTINATION_TYPE_NONE;
} else if (this->destSelect == CANNED_MESSAGE_DESTINATION_TYPE_NODE) {
@ -416,7 +480,7 @@ int32_t CannedMessageModule::runOnce()
case 0xb7: // right
// already handled above
break;
// handle fn+s for shutdown
// handle fn+s for shutdown
case 0x9b:
if (screen)
screen->startShutdownScreen();
@ -430,37 +494,6 @@ int32_t CannedMessageModule::runOnce()
rebootAtMsec = millis() + DEFAULT_REBOOT_SECONDS * 1000;
runState = CANNED_MESSAGE_RUN_STATE_INACTIVE;
break;
case 0x9e: // toggle GPS like triple press does
#if !MESHTASTIC_EXCLUDE_GPS
if (gps != nullptr) {
gps->toggleGpsMode();
}
if (screen)
screen->forceDisplay();
showTemporaryMessage("GPS Toggled");
#endif
break;
// mute (switch off/toggle) external notifications on fn+m
case 0xac:
if (moduleConfig.external_notification.enabled == true) {
if (externalNotificationModule->getMute()) {
externalNotificationModule->setMute(false);
showTemporaryMessage("Notifications \nEnabled");
} else {
externalNotificationModule->stopNow(); // this will turn off all GPIO and sounds and idle the loop
externalNotificationModule->setMute(true);
showTemporaryMessage("Notifications \nDisabled");
}
}
break;
case 0xaf: // fn+space send network ping like double press does
service.refreshLocalMeshNode();
if (service.trySendPosition(NODENUM_BROADCAST, true)) {
showTemporaryMessage("Position \nUpdate Sent");
} else {
showTemporaryMessage("Node Info \nUpdate Sent");
}
break;
default:
if (this->cursor == this->freetext.length()) {
this->freetext += this->payload;
@ -476,6 +509,8 @@ int32_t CannedMessageModule::runOnce()
}
break;
}
if (screen)
screen->removeFunctionSymbal("Fn");
}
this->lastTouchMillis = millis();
@ -787,4 +822,4 @@ String CannedMessageModule::drawWithCursor(String text, int cursor)
return result;
}
#endif
#endif

Wyświetl plik

@ -18,6 +18,7 @@
#define TFT_OFFSET_ROTATION 0
#define SCREEN_ROTATE
#define SCREEN_TRANSITION_FRAMERATE 5
#define BRIGHTNESS_DEFAULT 130 // Medium Low Brightness
#define HAS_TOUCHSCREEN 1
#define SCREEN_TOUCH_INT 16
@ -96,4 +97,4 @@
#define SX126X_DIO2_AS_RF_SWITCH
#define SX126X_DIO3_TCXO_VOLTAGE 1.8
// Internally the TTGO module hooks the SX1262-DIO2 in to control the TX/RX switch (which is the default for the sx1262interface
// code)
// code)