mirror of
https://github.com/alexhopeoconnor/firmware.git
synced 2026-10-04 03:18:10 +10:00
fix(graphics): make on-screen keyboard lifecycle safe and RAII-managed (#11460)
- VirtualKeyboard::handleLongPress VK_ESC invoked the onTextEntered member std::function directly, but that callback path reaches OnScreenKeyboardModule::stop(), which destroys the keyboard - and with it the std::function whose invocation is still on the stack. handlePress and submitText already deliberately copy-and-clear before invoking for exactly this reason (CannedMessageModule documents the same hazard); do the same here. - OnScreenKeyboardModule's keyboard becomes unique_ptr, replacing the delete-in-destructor / delete-then-new-in-start / delete-in-stop bookkeeping that runs on every keyboard open/close. The NotificationRenderer legacy hook receives a non-owning raw pointer, as before.
This commit is contained in:
@@ -666,7 +666,13 @@ void VirtualKeyboard::handleLongPress()
|
|||||||
break;
|
break;
|
||||||
case VK_ESC:
|
case VK_ESC:
|
||||||
if (onTextEntered) {
|
if (onTextEntered) {
|
||||||
onTextEntered("");
|
// Copy-and-clear before invoking, like handlePress/submitText: the callback can
|
||||||
|
// destroy this keyboard (OnScreenKeyboardModule::stop), so the member must not be
|
||||||
|
// the std::function still executing on the stack.
|
||||||
|
std::function<void(const std::string &)> callback = onTextEntered;
|
||||||
|
onTextEntered = nullptr;
|
||||||
|
inputText = "";
|
||||||
|
callback("");
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
|||||||
@@ -18,22 +18,12 @@ OnScreenKeyboardModule &OnScreenKeyboardModule::instance()
|
|||||||
return inst;
|
return inst;
|
||||||
}
|
}
|
||||||
|
|
||||||
OnScreenKeyboardModule::~OnScreenKeyboardModule()
|
OnScreenKeyboardModule::~OnScreenKeyboardModule() = default;
|
||||||
{
|
|
||||||
if (keyboard) {
|
|
||||||
delete keyboard;
|
|
||||||
keyboard = nullptr;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void OnScreenKeyboardModule::start(const char *header, const char *initialText, uint32_t durationMs,
|
void OnScreenKeyboardModule::start(const char *header, const char *initialText, uint32_t durationMs,
|
||||||
std::function<void(const std::string &)> cb)
|
std::function<void(const std::string &)> cb)
|
||||||
{
|
{
|
||||||
if (keyboard) {
|
keyboard = std::make_unique<VirtualKeyboard>();
|
||||||
delete keyboard;
|
|
||||||
keyboard = nullptr;
|
|
||||||
}
|
|
||||||
keyboard = new VirtualKeyboard();
|
|
||||||
callback = cb;
|
callback = cb;
|
||||||
if (header)
|
if (header)
|
||||||
keyboard->setHeader(header);
|
keyboard->setHeader(header);
|
||||||
@@ -50,7 +40,7 @@ void OnScreenKeyboardModule::start(const char *header, const char *initialText,
|
|||||||
});
|
});
|
||||||
|
|
||||||
// Maintain legacy compatibility hooks
|
// Maintain legacy compatibility hooks
|
||||||
NotificationRenderer::virtualKeyboard = keyboard;
|
NotificationRenderer::virtualKeyboard = keyboard.get();
|
||||||
NotificationRenderer::textInputCallback = callback;
|
NotificationRenderer::textInputCallback = callback;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -58,10 +48,7 @@ void OnScreenKeyboardModule::stop(bool callEmptyCallback)
|
|||||||
{
|
{
|
||||||
auto cb = callback;
|
auto cb = callback;
|
||||||
callback = nullptr;
|
callback = nullptr;
|
||||||
if (keyboard) {
|
keyboard.reset();
|
||||||
delete keyboard;
|
|
||||||
keyboard = nullptr;
|
|
||||||
}
|
|
||||||
// Keep NotificationRenderer legacy pointers in sync
|
// Keep NotificationRenderer legacy pointers in sync
|
||||||
NotificationRenderer::virtualKeyboard = nullptr;
|
NotificationRenderer::virtualKeyboard = nullptr;
|
||||||
NotificationRenderer::textInputCallback = nullptr;
|
NotificationRenderer::textInputCallback = nullptr;
|
||||||
@@ -74,7 +61,7 @@ void OnScreenKeyboardModule::handleInput(const InputEvent &event)
|
|||||||
if (!keyboard)
|
if (!keyboard)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (processVirtualKeyboardInput(event, keyboard))
|
if (processVirtualKeyboardInput(event, keyboard.get()))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (event.inputEvent == INPUT_BROKER_CANCEL)
|
if (event.inputEvent == INPUT_BROKER_CANCEL)
|
||||||
|
|||||||
@@ -7,6 +7,7 @@
|
|||||||
#include "graphics/VirtualKeyboard.h"
|
#include "graphics/VirtualKeyboard.h"
|
||||||
#include <OLEDDisplay.h>
|
#include <OLEDDisplay.h>
|
||||||
#include <functional>
|
#include <functional>
|
||||||
|
#include <memory>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
namespace graphics
|
namespace graphics
|
||||||
@@ -34,7 +35,7 @@ class OnScreenKeyboardModule
|
|||||||
void onSubmit(const std::string &text);
|
void onSubmit(const std::string &text);
|
||||||
void onCancel();
|
void onCancel();
|
||||||
|
|
||||||
VirtualKeyboard *keyboard = nullptr;
|
std::unique_ptr<VirtualKeyboard> keyboard;
|
||||||
std::function<void(const std::string &)> callback;
|
std::function<void(const std::string &)> callback;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user