Skip to content
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

Add IME support, extended actions, customize appearance #178

Open
wants to merge 7 commits into
base: main
Choose a base branch
from

Conversation

Riateche
Copy link

I was trying to implement a text input that works the same way as a native text input on desktop platforms. I would like to contribute the changes I had to make to cosmic-text.

IME support

Input method editors are required for convenient text input in some languages, so its support is essential for good user experience. While it's possible to implement some of the following changes in a wrapper around cosmic-text, I think it would be better to incorporate them here and provide this support to all users.

  1. Added SetPreedit action that inserts text with a special is_preedit flag in the attributes and clears any previous preedit. This is the most straightforward way to show a preedit inline, so that it works naturally with shaping and word wrapping. The downside is that the buffer's text is not the same as the document text anymore. For example, if the user wants to retrieve the text from the buffer, they should delete the part corresponding to the preedit (or clear the preedit). To help with this, I added Buffer::text_without_preedit() and BufferLine::text_without_preedit().
  2. Added Edit::cursor_position() method to retrieve the coordinates of the visual cursor. This is required to set the IME position, so that the input method window is displayed close to the cursor. The current implementation simply reuses the Editor::draw() code (moved out to a function). This can probably be done more efficiently.

There are also some aspects that I decided to implement outside of cosmic-text for now:

  1. Handling mouse events while there is an active preedit. There are some applications where it's possible to set the IME cursor position by clicking inside the preedit area, but in the most cases the applications just ignore mouse clicks and drags initiated over the preedit area. However, if you click outside of the preedit, the current preedit is usually just committed, and the IME state is reset. This reset action is a problem because it means we cannot simply implement it in the editor's action handler. There has to be a way for the editor to communicate to the host application that an IME reset is needed. There are ways to modify the API for that, but I decided that it's out of scope of this PR.
  2. Drawing underline of the preedit, which seems to be the most common way to represent it visually. It's possible to add support for underline styling to Buffer (for example, by integrating with line-straddler), at which point it would be pretty easy to change the default preedit attributes to underline instead of the current color change.

Hiding text cursor

  1. Cursor is now hidden when there is a selection.
  2. Cursor is now hidden when there is an IME preedit that specifies that there should be no cursor.
  3. Added Edit::set_cursor_hidden() to hide cursor manually, which can be used to implement cursor blinking, and to hide cursor when the input is unfocused or read only.

While I generally prefer "positive" boolean flags (e.g. set_cursor_visible() would generally be better), in this case the logic looks simpler when we use the hidden flag: cursor_hidden = has_selection || has_preedit_without_cursor || set_cursor_hidden.

Extended mouse and keyboard actions

I was aiming to implement all standard keyboard shortcuts and mouse actions that are usually present on desktop systems.

  1. Added missing actions: DocumentStart, DocumentEnd, SelectAll, DeleteStartOfWord, DeleteEndOfWord, SelectWord, SelectParagraph.
  2. Added select flag to Edit::action() to implement hotkeys with Shift modifier (e.g. Shift + ArrowRight to create or extend the selection) and fix hotkeys without Shift (e.g. ArrowRight previously didn't clear existing selection). I think this is the simplest way to implement it currently. It's not ideal because this flag only makes sense for some actions, but refactoring this API would be more dirsuptive.
  3. Fixed Previous and Next behavior when there is a selection. They now clear selection and put the cursor to the start and end of the selection, respectively.
  4. Fixed NextWord action to go to the end of line if there are no more word boundaries. Previously, it could get stuck and not move forward at all in some cases.

All new actions can be tested in the editor-orbclient example (I chose it because it already had some keyboard modifiers support, unlike the other examples).

More styling options

  1. Added an option to change the selection color (it was previously hardcoded).
  2. Added an option to set the selected text color. This is often needed to replicate the appearance of native widgets.

@Riateche
Copy link
Author

I would appreciate any feedback on this.

@jackpot51
Copy link
Member

This needs to be rebased to resolve conflicts first

@Riateche Riateche force-pushed the ime-actions-and-customize branch 3 times, most recently from 062304e to d04b3f2 Compare April 6, 2024 20:22
@Riateche
Copy link
Author

Riateche commented Apr 6, 2024

I rebased and updated the PR (it wasn't easy after half a year :D). Thanks to the added separation between Action and Motion, the select flag implementation is now much cleaner. I also updated the editor example to showcase all the new features. Please take a look.

@Riateche
Copy link
Author

I fixed the cargo fmt check, but not sure what I can do about the double syn dependency failure in CI. It seems unrelated to the PR.

@Riateche
Copy link
Author

Riateche commented May 5, 2024

Let me know if I can do something to help move this forward.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants