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

Emoji fix #1890

Closed
wants to merge 4 commits into from
Closed

Emoji fix #1890

wants to merge 4 commits into from

Conversation

juancampa
Copy link
Contributor

@juancampa juancampa commented Jan 7, 2019

Problems

There were multiple problems with emoji

  1. Opening the emoji dialog was possible but it appeared at a weird location. This was due to the textarea we use for input was not being kept in sync with the cursor position unless a composition (i.e. IME input) was underway.
  2. No emoji was received by the terminal.

Solutions

  1. Now the textarea always moves with the cursor.
  2. Added handler for the input event, only for emoji handling. Also, the textarea needs to have a lineheight > 0 for this event to fire, at least in Chromium.

Testing

  • MacOS
    • Emojis are inserted from the emoji input popup
    • The popup shows at the right location
    • Pasting still works fine. Including pasting emoji
    • Chrome
    • Firefox
    • Safari
    • IMEs still work (jp/ko/ch) including inserting emoji from Pinyin IME
  • Windows
    • Emojis are inserted from the emoji input popup
    • The popup shows at the right location
    • Pasting still works fine. Including pasting emoji
    • Chrome
    • Firefox
    • Safari
    • IE (support dropped)
    • IMEs still work (jp/ko/ch) including inserting emoji from Pinyin IME
  • Electron (via Hyper)

2019-01-04_16-24

@Tyriar
Copy link
Member

Tyriar commented Jan 7, 2019

The position is still broken on Windows:

win+.

image

Actual input doesn't seem to work either, but that's probably related to shell/pty problems.

image

@Tyriar
Copy link
Member

Tyriar commented Jan 7, 2019

macOS/firefox

Opens the emoji ime in the wrong spot:

screen shot 2019-01-07 at 11 27 50 am

screen shot 2019-01-07 at 11 28 39 am

@juancampa
Copy link
Contributor Author

juancampa commented Jan 7, 2019

The position is still broken on Windows:

Unfortunately I don't have a good way to test on Windows at the moment. Trying to get access to a remote desktop machine.

macOS/firefox

Looking into it, it seems to work sometimes 🤔

@@ -26,6 +26,11 @@
resolved "https://registry.yarnpkg.com/@types/chai/-/chai-3.5.2.tgz#c11cd2817d3a401b7ba0f5a420f35c56139b1c1e"
integrity sha1-wRzSgX06QBt7oPWkIPNcVhObHB4=

"@types/dom-inputevent@^1.0.3":
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should be undone since we're not using anymore

*/
export interface IInputEvent {
readonly data?: string;
readonly inputType?: string;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's missing from the type probably because support is bad (no Firefox), do you know why it appears to work on Firefox despite this? https://developer.mozilla.org/en-US/docs/Web/API/InputEvent/inputType#Browser_compatibility

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Tyriar The data attribute is not supported on Firefox. As per my previous comment, inputting emojis somewhat works with Firefox even without the code on this branch: #469 (comment)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Interesting. I'll run it with the debugger to understand what's happening on Firefox

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I did a bit of investigation on Firefox:

  • An alternative to data is to use event.target.value but only if we're clearing the textarea on every change
  • Firefox positioning of the Emoji popup is buggy in that, if you move the textarea around, the emoji popup's position (later, when it shows) will use the previous position of the textarea. A work-around I found is to manually set textarea.value to something (doesn't matter what), which seems to force firefox to recalculate the position used for emoji popup. Seems like a cache invalidation bug.
  • Firefox treats emoji input as composition while chrome doesn't 🤷‍♂️

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • Oh, and finally, and this might be a deal breaker, there's no inputType on Firefox, which we're using to detect when text is inserted vs. when text is pasted. There might be a way to work around this, by treating it as a composition but I haven't looked deeper into it

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we can't easily do it reliably on Firefox, I think at least doing it on Chrome would definitely be an improvement.

// https://stackoverflow.com/questions/30757193/
// For a complete list of all assigned codepoints, go to:
// https://unicode.org/Public/emoji/11.0/emoji-data.txt
export function isEmoji(str: string): boolean {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's move this into CharWidth.ts, this will later be renamed to Unicode*.ts so i think it makes sense to live there.

if (!this._isComposing) {
return;
}

if (this._terminal.buffer.isCursorInViewport) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why did you need to remove this? I don't think it's meant to move when composing (after it becomes visible)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure I follow. If that were the case, shouldn't the if be if (this._isComposing). My understanding is that this if avoids unnecessarily moving the textarea when is not needed (not composing anything), but I might be wrong 😝

The idea here is that we need a textarea to follow the cursor at all times so that the emoji popup shows at the right position (right under the text area).

Copy link
Contributor Author

@juancampa juancampa Jan 9, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thinking about this a bit more, it might be better to move the positioning of the textarea to Terminal.ts since it's not a composition thing anymore, and we wouldn't be moving the composition view unnecessarily (which I think is what you meant initially)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This function is only meant to do anything after compositionstart and before compositionend, I think you're right that maybe this should be moved out.

// For a complete list of all assigned codepoints, go to:
// https://unicode.org/Public/emoji/11.0/emoji-data.txt
export function isEmoji(str: string): boolean {
if (str.codePointAt === undefined) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please add:

// TODO: Remove when IE11 support is dropped

* There's a @types/dom-inputevent but at the moment it's outdated and missing
* some properties (e.g. inputType). So in the meantime we're using this instead
*/
export interface IInputEvent {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's call this IDomInputEvent to be clear as IKeyboardEvent above is an xterm.js thing

@Tyriar Tyriar added the work-in-progress Do not merge label Jan 7, 2019
@Tyriar
Copy link
Member

Tyriar commented Jan 26, 2019

@jerch do you know why if you press space twice after inserting an emoji a . appears?

screen shot 2019-01-26 at 12 51 59 pm

This even happens on master when you paste an emoji

This was referenced Feb 25, 2019
@Tyriar
Copy link
Member

Tyriar commented May 21, 2019

Ping @juancampa, you'll have difficulty keeping this page up to date in Hyper if it doesn't get merged in

@@ -206,11 +202,13 @@ export class CompositionHelper {
// Sync the textarea to the exact position of the composition view so the IME knows where the
// text is.
const compositionViewBounds = this._compositionView.getBoundingClientRect();
const width = Math.max(compositionViewBounds.width, this._terminal.charMeasure.width);
const height = Math.max(compositionViewBounds.height, this._terminal.charMeasure.height);
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm sure these two lines are wrong.
It will cause bug totally unrelated with emoji.
I have tested it in my environment.
Hope you can reconsider it.
Maybe we need Math.min or something?

@Tyriar
Copy link
Member

Tyriar commented Jun 28, 2019

Closing off since this needed a bunch of changes and has diverged a lot. A new attempt at fixing should probably start on a fresh branch.

@Tyriar Tyriar closed this Jun 28, 2019
@Tyriar Tyriar added reference A closed issue/pr that is expected to be useful later as a reference and removed work-in-progress Do not merge labels Jun 28, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
reference A closed issue/pr that is expected to be useful later as a reference
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants