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:
3 files changed
+14
-20
No files matched your search
@@ -666,7 +666,13 @@ void VirtualKeyboard::handleLongPress()
|
||||
break;
|
||||
case VK_ESC:
|
||||
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;
|
||||
default:
|
||||
|
||||
@@ -18,22 +18,12 @@ OnScreenKeyboardModule &OnScreenKeyboardModule::instance()
|
||||
return inst;
|
||||
}
|
||||
|
||||
OnScreenKeyboardModule::~OnScreenKeyboardModule()
|
||||
{
|
||||
if (keyboard) {
|
||||
delete keyboard;
|
||||
keyboard = nullptr;
|
||||
}
|
||||
}
|
||||
OnScreenKeyboardModule::~OnScreenKeyboardModule() = default;
|
||||
|
||||
void OnScreenKeyboardModule::start(const char *header, const char *initialText, uint32_t durationMs,
|
||||
std::function<void(const std::string &)> cb)
|
||||
{
|
||||
if (keyboard) {
|
||||
delete keyboard;
|
||||
keyboard = nullptr;
|
||||
}
|
||||
keyboard = new VirtualKeyboard();
|
||||
keyboard = std::make_unique<VirtualKeyboard>();
|
||||
callback = cb;
|
||||
if (header)
|
||||
keyboard->setHeader(header);
|
||||
@@ -50,7 +40,7 @@ void OnScreenKeyboardModule::start(const char *header, const char *initialText,
|
||||
});
|
||||
|
||||
// Maintain legacy compatibility hooks
|
||||
NotificationRenderer::virtualKeyboard = keyboard;
|
||||
NotificationRenderer::virtualKeyboard = keyboard.get();
|
||||
NotificationRenderer::textInputCallback = callback;
|
||||
}
|
||||
|
||||
@@ -58,10 +48,7 @@ void OnScreenKeyboardModule::stop(bool callEmptyCallback)
|
||||
{
|
||||
auto cb = callback;
|
||||
callback = nullptr;
|
||||
if (keyboard) {
|
||||
delete keyboard;
|
||||
keyboard = nullptr;
|
||||
}
|
||||
keyboard.reset();
|
||||
// Keep NotificationRenderer legacy pointers in sync
|
||||
NotificationRenderer::virtualKeyboard = nullptr;
|
||||
NotificationRenderer::textInputCallback = nullptr;
|
||||
@@ -74,7 +61,7 @@ void OnScreenKeyboardModule::handleInput(const InputEvent &event)
|
||||
if (!keyboard)
|
||||
return;
|
||||
|
||||
if (processVirtualKeyboardInput(event, keyboard))
|
||||
if (processVirtualKeyboardInput(event, keyboard.get()))
|
||||
return;
|
||||
|
||||
if (event.inputEvent == INPUT_BROKER_CANCEL)
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
#include "graphics/VirtualKeyboard.h"
|
||||
#include <OLEDDisplay.h>
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
namespace graphics
|
||||
@@ -34,7 +35,7 @@ class OnScreenKeyboardModule
|
||||
void onSubmit(const std::string &text);
|
||||
void onCancel();
|
||||
|
||||
VirtualKeyboard *keyboard = nullptr;
|
||||
std::unique_ptr<VirtualKeyboard> keyboard;
|
||||
std::function<void(const std::string &)> callback;
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user