-
Notifications
You must be signed in to change notification settings - Fork 610
[linux] Implements basic ASCII text input #46
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice!
#include <string> | ||
|
||
namespace flutter_desktop_embedding { | ||
|
||
typedef std::function<void(const std::string &, const Json::Value &)> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could you comment this? E.g., meanings of the arguments.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
@@ -31,14 +36,24 @@ class Plugin { | |||
// |input_blocking| Determines whether user input should be blocked during the | |||
// duration of this plugin's platform callback handler (in most cases this | |||
// can be set to false). | |||
explicit Plugin(std::string channel, bool input_blocking = false) | |||
: channel_(channel), input_blocking_(input_blocking) {} | |||
explicit Plugin(std::string channel, PlatformCallback platform_callback, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For now (things may change in the API revamp), how about eliminating platform_callback and having the logic for building and sending a response message given the channel and JSON be part of the Plugin base class?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm confused about what this means. The plugin can't make a call to the engine unless it has an instance of it. Should we then be including a field with a pointer to the flutter engine in the base class?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, either way it's tied to the engine; I think making it explicit with the engine pointer is reasonable since a plugin is fundamentally a channel for talking to the engine.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Updated this to take a setter method. Unsure if this is what you had in mind.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The client is still responsible providing the callback, not just the engine as discussed above. Summarizing from the offline discussion earlier, my take on this is:
- The callback logic is always going to be the same modulo the engine pointer.
- That logic is fundamentally about the details of the message format used by the engine.
- The core purpose of the Plugin class is to provide a higher-level abstraction around communicating with the engine.
Given that, a protected method within Plugin seems like the right place for that logic to live, rather than requiring something outside of Plugin to implement it and provide that implementation.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ping on this. I accidentally replied as a separate comment rather than as part of the review, so I'm guessing it was lost.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Alright, got it in. This required a minor change to the file chooser plugin, btw (just need it to call the engine callback instead of returning the info as part of the HandlePlatformMessage response).
@@ -52,10 +57,20 @@ class PluginHandler { | |||
std::function<void(void)> input_block_cb = [] {}, | |||
std::function<void(void)> input_unblock_cb = [] {}); | |||
|
|||
const std::vector<KeyboardHookFunction>& keyboard_hooks() const { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These need declaration comments explaining what they are.
But as with the comments on Plugin, ideally we should move these out of the core class.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Removed! 👍
int client_id = client_id_json.asInt(); | ||
if (input_models_.find(client_id) == input_models_.end()) { | ||
input_models_.insert(std::make_pair( | ||
client_id, std::make_unique<TextInputModel>(client_id))); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should we cap the size of this? Wasn't there some discussion of the ID always going up over time even for the same set of text fields?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we should, yes. However inflating text ID fields should be fixed once we send back valid callback responses via HandlePlatformMessage (instead of returning null).
virtual ~Plugin() {} | ||
|
||
// A function for hooking into keyboard input. | ||
virtual void KeyboardHook(GLFWwindow *window, int key, int scancode, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Making things specific to the text plugin part of Plugin would be unfortunate, since other plugins shouldn't need this. Since at some point text input will be a specific API rather than part of the plugin system I'd rather we treat this specially up front. We can have this be part of the subclass, and the main embedding code can know about the text input plugin as a specific object rather than just a generic plugin.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Moved to an abstract class that the text input plugin now uses.
@@ -72,6 +76,22 @@ static void GLFWwindowSizeCallback(GLFWwindow *window, int width, int height) { | |||
FlutterEngineSendWindowMetricsEvent(state->engine, &event); | |||
} | |||
|
|||
// Callback invoked when a plugin wants to send a message to the Flutter Engine. | |||
static void GLFWOnPlatformCallback(GLFWwindow *window, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It seems confusing to have this named using the same style as the engine callbacks. Why not just SendFlutterEngineMessage or something like that?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I was a bit on the fence about the naming of this function myself. I think that works.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed.
.message_size = output.size(), | ||
}; | ||
FlutterEngineSendPlatformMessage(state->engine, &platform_message_response); | ||
// TODO(awdavies): This needs updating for Issue #45. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we need this code as part of this patch? The macOS text input plugin always sends back null for now just like the other ones, so I would expect we could leave this out and revisit later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Removed.
|
||
#include <flutter_desktop_embedding/common/platform_protocol.h> | ||
|
||
static constexpr char kComposingBaseKey[] = "composingBase"; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's put a comment referencing #47 on these constants (which I'll do on the macOS side as well sometime soon). I want to make sure anyone looking at the code is aware that this isn't actually supported.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
private: | ||
void DeleteSelected(); | ||
|
||
std::string rep_; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No abbreviations in variable names, per style guide.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
|
||
void TextInputModel::DeleteSelected() { | ||
selection_extent_ = rep_.erase(selection_base_, selection_extent_); | ||
selection_base_ = selection_extent_; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Per offline discussion let's change to:
selection_base_ = ...
selection_extent_ = selection_base_
since it seemed more confusing to me as written.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same with some other spots below.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed! 😀
@stuartmorgan PTAL Addressed comments. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just a couple notes left; looking really good!
|
||
void KeyboardHook(GLFWwindow *window, int key, int scancode, int action, | ||
int mods) override; | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Given that there are multiple parents, I'd use labelled clusters for the overrides to make it clearer what's what:
// Plugin
Json::Value HandlePlatformMessage(const Json::Value &message) override;
// KeyboardHookHandler:
void KeyboardHook(GLFWwindow *window, int key, int scancode, int action,
int mods) override;
void CharHook(GLFWwindow *window, unsigned int code_point) override;
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sounds good! Of all the C++ I've done this is the first time I've actually used multiple inheritance
.message = reinterpret_cast<const uint8_t *>(output.c_str()), | ||
.message_size = output.size(), | ||
}; | ||
FlutterEngineSendPlatformMessage(state->engine, &platform_message_response); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since this is all duplicate code with line 89, extract to a static helper? (Eventually I think this will move into Plugin, but I can revisit that when reworking the plugin API across platforms.)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think just calling the static function would be sufficient, no? The code is the same, for sure.
@stuartmorgan Last pass! (maybe) |
// Contains a channel string for the plugin and a JSON value to pass to the | ||
// engine. | ||
typedef std::function<void(const std::string &, const Json::Value &)> | ||
PlatformCallback; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This can be removed now, right?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Woops! Forgot that was there. Good catch
virtual void set_flutter_engine(FlutterEngine engine) { engine_ = engine; } | ||
|
||
protected: | ||
// Runs the platform callback. Noop if the callback is not set. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This comment is out of date. Also, maybe this function should be called SendMessageToEngine or something similar now, since it's not really clear what CallPlatformCallback means in this structure.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Updated!
|
||
protected: | ||
// Runs the platform callback. Noop if the callback is not set. | ||
void CallPlatformCallback(const Json::Value &json) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's move this to a .cc, since it doesn't need to be in the header and we don't want it inlined.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
CC file made!
Text input supports:
-- Deleting highlighted sections of text (highlight must be done w/ the mouse pointer for now).
-- Writing basic ASCII
-- Moving the cursor left and right.
-- Home/End keys to go to the beginning/end of a line.
This change also adds some header guard cleanup since paths have changed.