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

Compatible with input methods that commit text with alphabets under macOS #4219

Closed
page-down opened this issue Nov 10, 2021 · 24 comments
Closed

Comments

@page-down
Copy link
Contributor

Is your feature request related to a problem? Please describe.
There is a text input method in which the first candidate will be confirmed when there is no match for the last entered character. The last character will immediately be used as the pre-edit text for the next word.

This type of text input is very efficient and widely used, and is commonly used in fixed-length table input methods.

However, in kitty, there will be a misalignment at this point. After the first candidate word is submitted, the last character is rendered in its original position as pre-edit text. I found this compatibility issue in kitty today while occasionally working with multilingual documents.

The following kitt has two candidates, kitty and kitten.

After entering t, kitty is automatically submitted since there are no kittt matches.
However, at this point t is rendered in the original position when the input method state was entered.


Describe the solution you'd like
After submitting the text, render the pre-edit text with the latest cursor position.

Describe alternatives you've considered
n/a

Additional context

This is reproduced using rime, an open source input engine mentioned in another IME issue thread.

Screen recording

Use the space to confirm the candidate, everything works fine.

Press: native_key: 0x11 (t) glfw_key: 0x74 mods: none char_count: 1 deadKeyState: 0 repeat: 0 text: <none> glfw_key: t marked_text: kitt
on_key_input: glfw key: 0x74 native_code: 0x11 action: PRESS mods: none text: 'kitt' state: 1 updateIMEState: 50.000000, 384.000000, 8.000000, 17.000000
updated pre-edit text: 'kitt'
Release: native_key: 0x11 (t) glfw_key: 0x74 mods: none 
on_key_input: glfw key: 0x74 native_code: 0x11 action: RELEASE mods: none text: '' state: 0 updateIMEState: 58.000000, 384.000000, 8.000000, 17.000000

Press: native_key: 0x31 ( ) glfw_key: 0x20 mods: none char_count: 1 deadKeyState: 0 repeat: 0 text: 0x6b 0x69 0x74 0x74 0x79 glfw_key:   marked_text: 
on_key_input: glfw key: 0x20 native_code: 0x31 action: PRESS mods: none text: '' state: 1 updateIMEState: 58.000000, 384.000000, 8.000000, 17.000000
updated pre-edit text: ''
on_key_input: glfw key: 0x20 native_code: 0x31 action: REPEAT mods: none text: 'kitty' state: 0 updateIMEState: 26.000000, 384.000000, 8.000000, 17.000000
sent key as text to child
Release: native_key: 0x31 ( ) glfw_key: 0x20 mods: none 
on_key_input: glfw key: 0x20 native_code: 0x31 action: RELEASE mods: none text: '' state: 0 updateIMEState: 66.000000, 384.000000, 8.000000, 17.000000

Enter the initial t of the next word and let the first candidate confirm automatically. At this point the pre-edit text is not at the latest cursor position. It looks like this is because the pre-edit text is updated first in a keypress event, and then the text is output to the child.

Press: native_key: 0x28 (k) glfw_key: 0x6b mods: none char_count: 1 deadKeyState: 0 repeat: 0 text: <none> glfw_key: k marked_text: k
on_key_input: glfw key: 0x6b native_code: 0x28 action: PRESS mods: none text: 'k' state: 1 updateIMEState: 26.000000, 418.000000, 8.000000, 17.000000
updated pre-edit text: 'k'
Release: native_key: 0x28 (k) glfw_key: 0x6b mods: none 
on_key_input: glfw key: 0x6b native_code: 0x28 action: RELEASE mods: none text: '' state: 0 updateIMEState: 34.000000, 418.000000, 8.000000, 17.000000

Press: native_key: 0x22 (i) glfw_key: 0x69 mods: none char_count: 1 deadKeyState: 0 repeat: 0 text: <none> glfw_key: i marked_text: ki
on_key_input: glfw key: 0x69 native_code: 0x22 action: PRESS mods: none text: 'ki' state: 1 updateIMEState: 34.000000, 418.000000, 8.000000, 17.000000
updated pre-edit text: 'ki'
Release: native_key: 0x22 (i) glfw_key: 0x69 mods: none 
on_key_input: glfw key: 0x69 native_code: 0x22 action: RELEASE mods: none text: '' state: 0 updateIMEState: 42.000000, 418.000000, 8.000000, 17.000000

Press: native_key: 0x11 (t) glfw_key: 0x74 mods: none char_count: 1 deadKeyState: 0 repeat: 0 text: <none> glfw_key: t marked_text: kit
on_key_input: glfw key: 0x74 native_code: 0x11 action: PRESS mods: none text: 'kit' state: 1 updateIMEState: 42.000000, 418.000000, 8.000000, 17.000000
updated pre-edit text: 'kit'
Release: native_key: 0x11 (t) glfw_key: 0x74 mods: none 
on_key_input: glfw key: 0x74 native_code: 0x11 action: RELEASE mods: none text: '' state: 0 updateIMEState: 50.000000, 418.000000, 8.000000, 17.000000

Press: native_key: 0x11 (t) glfw_key: 0x74 mods: none char_count: 1 deadKeyState: 0 repeat: 0 text: <none> glfw_key: t marked_text: kitt
on_key_input: glfw key: 0x74 native_code: 0x11 action: PRESS mods: none text: 'kitt' state: 1 updateIMEState: 50.000000, 418.000000, 8.000000, 17.000000
updated pre-edit text: 'kitt'
Release: native_key: 0x11 (t) glfw_key: 0x74 mods: none 
on_key_input: glfw key: 0x74 native_code: 0x11 action: RELEASE mods: none text: '' state: 0 updateIMEState: 58.000000, 418.000000, 8.000000, 17.000000

Press: native_key: 0x11 (t) glfw_key: 0x74 mods: none char_count: 1 deadKeyState: 0 repeat: 0 text: 0x6b 0x69 0x74 0x74 0x79 glfw_key: t marked_text: t
on_key_input: glfw key: 0x74 native_code: 0x11 action: PRESS mods: none text: 't' state: 1 updateIMEState: 58.000000, 418.000000, 8.000000, 17.000000
updated pre-edit text: 't'
on_key_input: glfw key: 0x74 native_code: 0x11 action: REPEAT mods: none text: 'kitty' state: 0 updateIMEState: 34.000000, 418.000000, 8.000000, 17.000000
sent key as text to child
Release: native_key: 0x11 (t) glfw_key: 0x74 mods: none 
on_key_input: glfw key: 0x74 native_code: 0x11 action: RELEASE mods: none text: '' state: 0 updateIMEState: 74.000000, 418.000000, 8.000000, 17.000000

Press: native_key: 0x12 (1) glfw_key: 0x31 mods: none char_count: 1 deadKeyState: 0 repeat: 0 text: 0x74 0x65 0x72 0x6d 0x69 0x6e 0x61 0x6c glfw_key: 1 marked_text: 
on_key_input: glfw key: 0x31 native_code: 0x12 action: PRESS mods: none text: '' state: 1 updateIMEState: 74.000000, 418.000000, 8.000000, 17.000000
updated pre-edit text: ''
on_key_input: glfw key: 0x31 native_code: 0x12 action: REPEAT mods: none text: 'terminal' state: 0 updateIMEState: 26.000000, 418.000000, 8.000000, 17.000000
sent key as text to child
Release: native_key: 0x12 (1) glfw_key: 0x31 mods: none 
on_key_input: glfw key: 0x31 native_code: 0x12 action: RELEASE mods: none text: '' state: 0 updateIMEState: 90.000000, 418.000000, 8.000000, 17.000000

I'm looking at cocoa_window.m keyDown.

    ...
    if (!window->ns.deadKeyState) {
        if ([self hasMarkedText]) {
            glfw_keyevent.text = [[markedText string] UTF8String]; // `kitt` -> `t`
            glfw_keyevent.ime_state = GLFW_IME_PREEDIT_CHANGED;
            _glfwInputKeyboard(window, &glfw_keyevent); // update pre-edit text
        } else ... { ... }
    }
    glfw_keyevent.text = _glfw.ns.text; // ---> `kitty`
    glfw_keyevent.ime_state = GLFW_IME_NONE;
    add_alternate_keys(&glfw_keyevent, event);
    _glfwInputKeyboard(window, &glfw_keyevent);
    }

I'm not quite sure if there is the most appropriate way to handle this situation, any help is greatly appreciated.

@kovidgoyal
Copy link
Owner

I doubt there is a good way to handle this given the limitations of the Cocoa API available to us. What we need is for Cocoa to tell us to commit the current word and start the next one. hasMarkedtext is obviously insufficient for this. Later down in that file look for "unmarkText" if that is called by cocoa then we can use that instead.

And it would help if you posted some instructions for how to setup this IME so I can test it for myself.

@page-down
Copy link
Contributor Author

page-down commented Nov 11, 2021

In keyDown, unmark is called every time: [self unmarkText];. Print the logs to prove it as well.
It does not appear to be usable for differentiation.

I noticed that:

text: <none> glfw_key: t marked_text: kitt
->
text: 0x6b 0x69 0x74 0x74 0x79 (`kitty`, first candidate) glfw_key: t marked_text: t

Perhaps this should also be a clear indication of the confirmation?

Here is how to configure this input method.

Click to expand ...

Installation

Download and double-click the unzipped pkg from GitHub Release to install.
https://github.com/rime/squirrel/releases
Or compile from source.
https://github.com/rime/squirrel/blob/master/INSTALL.md

Open system preferences -> keyboard -> input sources, click the plus button in the bottom left corner, search for Squirrel in the search box in the bottom left corner, and add the input method.

open /System/Library/PreferencePanes/Keyboard.prefPane

If it does not work, you may need to log out of the current user and log in again.

Uninstallation

Remove the input method from the above (Input Sources) and delete the following directory. Log out of the user account and log in again.

/Library/Input Methods/Squirrel.app
~/Library/Rime

In case you are using QEMU to run the macOS VM, you can also use qemu-system-x86_64 -snapshot ... to boot directly as a temporary snapshot.

Configure the input scheme

Delete all files under ~/Library/Rime/, or create an empty folder if it does not exist.
Put the following 3 files in.
In macOS Menubar switch the input method to Squirrel, click the icon again, and select Deploy in the menubar drop-down menu.
At this point you should see a macOS Notification indicating that the configuration has been updated.
When this input method is enabled, two candidates should appear when you type kitt.

default.custom.yaml

patch:
  schema_list:
    - schema: table-auto-select
  ascii_composer/switch_key: {}
  key_binder/bindings: {}
  switcher/hotkeys: {}

demo.dict.yaml

---
name: demo
version: "0.1"
sort: original
...
# the following is separated by tab "\t"
# so be careful when copying

kitty	kitt
kitten	kitt
terminal	t

table-auto-select.schema.yaml

schema:
  schema_id: table-auto-select
  name: table-auto-select

switches:
  - name: ascii_mode
    reset: 0
  - name: ascii_punct
    reset: 0

engine:
  processors:
    - ascii_composer
    - speller
    - selector
    - navigator
    - express_editor
  segmentors:
    - ascii_segmentor
    - abc_segmentor
    - fallback_segmentor
  translators:
    - table_translator

speller:
  alphabet: 'zyxwvutsrqponmlkjihgfedcba'
  initials: 'abcdefghijklmnopqrstuvwxyz'
  max_code_length: 4
  auto_select: true
  auto_select_pattern: ^\w{4}$
  auto_clear: max_length

translator:
  dictionary: demo
  db_class: stabledb
  enable_charset_filter: false
  enable_sentence: false
  enable_completion: false
  enable_user_dict: false

style:
  horizontal: true

@kovidgoyal
Copy link
Owner

I know unmarkText is called by keyDown itself. I meant is it also called by cocoa when you pass it the third t key (and more generally on pre-edit completion. If cocoa calls it when any pre-edit sequence completes we can use it. Even if we call it ourselves, we can detect when cocoa calls it too.

In order to use text != NULL and marked_text != NULL as a signal to send commit pre-edit message we have to know if that combination does not ever occur with other IME methods during normal operation. I cant find any documentation on it, which is typical for Apple, so that leaves experimentation.

@kovidgoyal
Copy link
Owner

kovidgoyal commented Nov 11, 2021

Try this: ca9fdad

it will show us if we can use unmarkText as a signal.

@kovidgoyal
Copy link
Owner

kovidgoyal commented Nov 11, 2021

The call to unmark the text on every keydown event was authored by @blahgeek so maybe he can comment if removing it breaks anything e36e44a

@page-down
Copy link
Contributor Author

page-down commented Nov 11, 2021

I think I'm experiencing the breakage now.

After typing kitt, press "Backspace" to delete, the last k cannot be deleted. At this time the keys do not work properly, including ctrl+c .

Press: native_key: 0x33 (<cc>) glfw_key: 0xe003 mods: none char_count: 1 deadKeyState: 0 repeat: 0 text: <none> glfw_key: BACKSPACE unmark_called: 0 marked_text: (kit)
on_key_input: glfw key: 0xe003 native_code: 0x33 action: PRESS mods: none text: 'kit' state: 1 updateIMEState: 354.000000, 17.000000, 8.000000, 17.000000
updated pre-edit text: 'kit'
Release: native_key: 0x33 (<cc>) glfw_key: 0xe003 mods: none 
on_key_input: glfw key: 0xe003 native_code: 0x33 action: RELEASE mods: none text: '' state: 0 updateIMEState: 346.000000, 17.000000, 8.000000, 17.000000

Press: native_key: 0x33 (<cc>) glfw_key: 0xe003 mods: none char_count: 1 deadKeyState: 0 repeat: 0 text: <none> glfw_key: BACKSPACE unmark_called: 0 marked_text: (ki)
on_key_input: glfw key: 0xe003 native_code: 0x33 action: PRESS mods: none text: 'ki' state: 1 updateIMEState: 346.000000, 17.000000, 8.000000, 17.000000
updated pre-edit text: 'ki'
Release: native_key: 0x33 (<cc>) glfw_key: 0xe003 mods: none 
on_key_input: glfw key: 0xe003 native_code: 0x33 action: RELEASE mods: none text: '' state: 0 updateIMEState: 338.000000, 17.000000, 8.000000, 17.000000

Press: native_key: 0x33 (<cc>) glfw_key: 0xe003 mods: none char_count: 1 deadKeyState: 0 repeat: 0 text: <none> glfw_key: BACKSPACE unmark_called: 0 marked_text: (k)
on_key_input: glfw key: 0xe003 native_code: 0x33 action: PRESS mods: none text: 'k' state: 1 updateIMEState: 338.000000, 17.000000, 8.000000, 17.000000
updated pre-edit text: 'k'
Release: native_key: 0x33 (<cc>) glfw_key: 0xe003 mods: none 
on_key_input: glfw key: 0xe003 native_code: 0x33 action: RELEASE mods: none text: '' state: 0 updateIMEState: 330.000000, 17.000000, 8.000000, 17.000000

Press: native_key: 0x33 (<cc>) glfw_key: 0xe003 mods: none char_count: 1 deadKeyState: 0 repeat: 0 text: <none> glfw_key: BACKSPACE unmark_called: 0 marked_text: (k)
on_key_input: glfw key: 0xe003 native_code: 0x33 action: PRESS mods: none text: 'k' state: 1 updateIMEState: 330.000000, 17.000000, 8.000000, 17.000000
updated pre-edit text: 'k'
Release: native_key: 0x33 (<cc>) glfw_key: 0xe003 mods: none 
on_key_input: glfw key: 0xe003 native_code: 0x33 action: RELEASE mods: none text: '' state: 0 updateIMEState: 330.000000, 17.000000, 8.000000, 17.000000

Press: native_key: 0x33 (<cc>) glfw_key: 0xe003 mods: none char_count: 1 deadKeyState: 0 repeat: 0 text: <none> glfw_key: BACKSPACE unmark_called: 0 marked_text: (k)
on_key_input: glfw key: 0xe003 native_code: 0x33 action: PRESS mods: none text: 'k' state: 1 updateIMEState: 330.000000, 17.000000, 8.000000, 17.000000
updated pre-edit text: 'k'
Release: native_key: 0x33 (<cc>) glfw_key: 0xe003 mods: none 

When t is pressed and the "space" key is used to select the candidate terminal, t is still marked on the screen.

@kovidgoyal
Copy link
Owner

yeah, not clearing the markedtext on keydown causes the last backspace
to cancel the pre-edit to not work. This could possibly be fixed, who
knows.

@page-down
Copy link
Contributor Author

I think his patch still applies.
Tested the Japanese input method that comes with macOS and they don't seem to be working properly...
I have not seen Unmark Text called yet. The official input methods are used.

@kovidgoyal
Copy link
Owner

That is easily fixed by 8644fed

unmarkText is not official anymore (it used to be in older cocoa versions) however it is currently called by setMarkedText. I see it called when using the cangjie chines IME for instance.

@page-down
Copy link
Contributor Author

Thanks for the clarification, then it seems that this part of the code does need to be updated.

This solves the backspace problem.

The next step is to see how to solve this problem of getting stuck after selecting a candidate. Not only does the marked text remain, but enter and ctrl+c are not responding.

It really does take a lot of experimentation.

@kovidgoyal
Copy link
Owner

That should be fixed by: f34cc18

@page-down
Copy link
Contributor Author

Yes, it did work out. In the meantime, the problem that was initially raised is still appearing.

So I try out this solution. Only the third t cannot be rendered in the last position. And I don't know yet if it causes other IME problems.

diff --git a/glfw/cocoa_window.m b/glfw/cocoa_window.m
index 1d84395c..757dd795 100644
--- a/glfw/cocoa_window.m
+++ b/glfw/cocoa_window.m
@@ -1216,6 +1216,9 @@ - (void)updateTrackingAreas
 
 - (void)keyDown:(NSEvent *)event
 {
+    // DEBUG
+    const bool previous_has_text = _glfw.ns.text[0] != 0;
+
     const bool previous_has_marked_text = [self hasMarkedText];
     NSTextInputContext *inpctx = [NSTextInputContext currentInputContext];
     if (inpctx && (!input_source_at_last_key_event || ![input_source_at_last_key_event isEqualToString:inpctx.selectedKeyboardInputSource])) {
@@ -1295,6 +1298,19 @@ - (void)keyDown:(NSEvent *)event
             format_text(_glfw.ns.text), _glfwGetKeyName(key), unmark_text_called, [[markedText string] UTF8String]);
     if (!window->ns.deadKeyState) {
         if ([self hasMarkedText]) {
+            // DEBUG
+            if (!previous_has_text && _glfw.ns.text[0] != 0 && previous_has_marked_text) {
+                glfw_keyevent.text = _glfw.ns.text;
+                glfw_keyevent.ime_state = GLFW_IME_COMMIT_TEXT;
+                _glfwInputKeyboard(window, &glfw_keyevent);
+
+                // issue: missing current marked text,
+                // If the pre-edit text is updated here, it will be rendered in the wrong position.
+                glfw_keyevent.text = NULL;
+                glfw_keyevent.ime_state = GLFW_IME_PREEDIT_CHANGED;
+                _glfwInputKeyboard(window, &glfw_keyevent); // clear pre-edit text
+                return;
+            }
             glfw_keyevent.text = [[markedText string] UTF8String];
             glfw_keyevent.ime_state = GLFW_IME_PREEDIT_CHANGED;
             _glfwInputKeyboard(window, &glfw_keyevent); // update pre-edit text

@kovidgoyal
Copy link
Owner

Can you post the log running from current HEAD and typing

kittt

@page-down
Copy link
Contributor Author

page-down commented Nov 11, 2021

fac76dd

Press: native_key: 0x28 (k) glfw_key: 0x6b mods: none char_count: 1 deadKeyState: 0 repeat: 0 
	setMarkedText: k selectedRange: (1, 0) replacementRange: (9223372036854775807, 0)
text: <none> glfw_key: k unmark_called: 0 marked_text: (k)
on_key_input: glfw key: 0x6b native_code: 0x28 action: PRESS mods: none text: 'k' state: 1 updateIMEState: 322.000000, 17.000000, 8.000000, 17.000000
updated pre-edit text: 'k'
Release: native_key: 0x28 (k) glfw_key: 0x6b mods: none 
on_key_input: glfw key: 0x6b native_code: 0x28 action: RELEASE mods: none text: '' state: 0 updateIMEState: 330.000000, 17.000000, 8.000000, 17.000000

Press: native_key: 0x22 (i) glfw_key: 0x69 mods: none char_count: 1 deadKeyState: 0 repeat: 0 
	setMarkedText: ki selectedRange: (2, 0) replacementRange: (9223372036854775807, 0)
text: <none> glfw_key: i unmark_called: 0 marked_text: (ki)
on_key_input: glfw key: 0x69 native_code: 0x22 action: PRESS mods: none text: 'ki' state: 1 updateIMEState: 330.000000, 17.000000, 8.000000, 17.000000
updated pre-edit text: 'ki'
Release: native_key: 0x22 (i) glfw_key: 0x69 mods: none 
on_key_input: glfw key: 0x69 native_code: 0x22 action: RELEASE mods: none text: '' state: 0 updateIMEState: 338.000000, 17.000000, 8.000000, 17.000000

Press: native_key: 0x11 (t) glfw_key: 0x74 mods: none char_count: 1 deadKeyState: 0 repeat: 0 
	setMarkedText: kit selectedRange: (3, 0) replacementRange: (9223372036854775807, 0)
text: <none> glfw_key: t unmark_called: 0 marked_text: (kit)
on_key_input: glfw key: 0x74 native_code: 0x11 action: PRESS mods: none text: 'kit' state: 1 updateIMEState: 338.000000, 17.000000, 8.000000, 17.000000
updated pre-edit text: 'kit'
Release: native_key: 0x11 (t) glfw_key: 0x74 mods: none 
on_key_input: glfw key: 0x74 native_code: 0x11 action: RELEASE mods: none text: '' state: 0 updateIMEState: 346.000000, 17.000000, 8.000000, 17.000000

Press: native_key: 0x11 (t) glfw_key: 0x74 mods: none char_count: 1 deadKeyState: 0 repeat: 0 
	setMarkedText: kitt selectedRange: (4, 0) replacementRange: (9223372036854775807, 0)
text: <none> glfw_key: t unmark_called: 0 marked_text: (kitt)
on_key_input: glfw key: 0x74 native_code: 0x11 action: PRESS mods: none text: 'kitt' state: 1 updateIMEState: 346.000000, 17.000000, 8.000000, 17.000000
updated pre-edit text: 'kitt'
Release: native_key: 0x11 (t) glfw_key: 0x74 mods: none 
on_key_input: glfw key: 0x74 native_code: 0x11 action: RELEASE mods: none text: '' state: 0 updateIMEState: 354.000000, 17.000000, 8.000000, 17.000000

Press: native_key: 0x11 (t) glfw_key: 0x74 mods: none char_count: 1 deadKeyState: 0 repeat: 0 
	insertText: kitty replacementRange: (9223372036854775807, 0)

	setMarkedText: t selectedRange: (1, 0) replacementRange: (9223372036854775807, 0)
text: 0x6b 0x69 0x74 0x74 0x79 glfw_key: t unmark_called: 1 marked_text: (t)
on_key_input: glfw key: 0x74 native_code: 0x11 action: PRESS mods: none text: 't' state: 1 updateIMEState: 354.000000, 17.000000, 8.000000, 17.000000
updated pre-edit text: 't'
on_key_input: glfw key: 0x74 native_code: 0x11 action: REPEAT mods: none text: 'kitty' state: 0 updateIMEState: 330.000000, 17.000000, 8.000000, 17.000000
sent key as text to child
Release: native_key: 0x11 (t) glfw_key: 0x74 mods: none 
on_key_input: glfw key: 0x74 native_code: 0x11 action: RELEASE mods: none text: '' state: 0 updateIMEState: 362.000000, 17.000000, 8.000000, 17.000000

Press: native_key: 0x31 ( ) glfw_key: 0x20 mods: none char_count: 1 deadKeyState: 0 repeat: 0 
	insertText: terminal replacementRange: (9223372036854775807, 0)
text: 0x74 0x65 0x72 0x6d 0x69 0x6e 0x61 0x6c glfw_key:   unmark_called: 1 marked_text: ()
on_key_input: glfw key: 0x20 native_code: 0x31 action: PRESS mods: none text: '' state: 1 updateIMEState: 362.000000, 17.000000, 8.000000, 17.000000
updated pre-edit text: ''
on_key_input: glfw key: 0x20 native_code: 0x31 action: REPEAT mods: none text: 'terminal' state: 0 updateIMEState: 322.000000, 17.000000, 8.000000, 17.000000
sent key as text to child
Release: native_key: 0x31 ( ) glfw_key: 0x20 mods: none 
on_key_input: glfw key: 0x20 native_code: 0x31 action: RELEASE mods: none text: '' state: 0 updateIMEState: 426.000000, 17.000000, 8.000000, 17.000000

on_key_input: glfw key: 0xe064 native_code: 0x37 action: PRESS mods: super text: '' state: 0 updateIMEState: 426.000000, 17.000000, 8.000000, 17.000000

on_key_input: glfw key: 0xe064 native_code: 0x37 action: RELEASE mods: none text: '' state: 0 updateIMEState: 426.000000, 17.000000, 8.000000, 17.000000

updateIMEState: 0.000000, 0.000000, 0.000000, 0.000000

@kovidgoyal
Copy link
Owner

That's two t presses, I need three

@page-down
Copy link
Contributor Author

I edited the log above. Pressed the space at the end.

@kovidgoyal
Copy link
Owner

As we can see after the third t, as I suspected unmark_called: 1 so we can use that as a signal, I think.

@page-down
Copy link
Contributor Author

Yes, put GLFW_IME_COMMIT_TEXT in, and the text is inserted properly. I see that all that remains is to update the new pre-edit text position with the text.

@page-down
Copy link
Contributor Author

Thanks for the update. I pulled the latest and tried it.

In fish shell, there is a problem.

When the third t is entered, the cursor is at the far right of the screen.

Press: native_key: 0x28 (k) glfw_key: 0x6b mods: none char_count: 1 deadKeyState: 0 repeat: 0 
	setMarkedText: k selectedRange: (1, 0) replacementRange: (9223372036854775807, 0)
text: <none> glfw_key: k marked_text: (k)
on_key_input: glfw key: 0x6b native_code: 0x28 action: PRESS mods: none text: 'k' state: 1 updateIMEState: left=322.000000, top=17.000000, width=8.000000, height=17.000000
updated pre-edit text: 'k'
Release: native_key: 0x28 (k) glfw_key: 0x6b mods: none 
on_key_input: glfw key: 0x6b native_code: 0x28 action: RELEASE mods: none text: '' state: 0 updateIMEState: left=330.000000, top=17.000000, width=8.000000, height=17.000000

Press: native_key: 0x22 (i) glfw_key: 0x69 mods: none char_count: 1 deadKeyState: 0 repeat: 0 
	setMarkedText: ki selectedRange: (2, 0) replacementRange: (9223372036854775807, 0)
text: <none> glfw_key: i marked_text: (ki)
on_key_input: glfw key: 0x69 native_code: 0x22 action: PRESS mods: none text: 'ki' state: 1 updateIMEState: left=330.000000, top=17.000000, width=8.000000, height=17.000000
updated pre-edit text: 'ki'
Release: native_key: 0x22 (i) glfw_key: 0x69 mods: none 
on_key_input: glfw key: 0x69 native_code: 0x22 action: RELEASE mods: none text: '' state: 0 updateIMEState: left=338.000000, top=17.000000, width=8.000000, height=17.000000

Press: native_key: 0x11 (t) glfw_key: 0x74 mods: none char_count: 1 deadKeyState: 0 repeat: 0 
	setMarkedText: kit selectedRange: (3, 0) replacementRange: (9223372036854775807, 0)
text: <none> glfw_key: t marked_text: (kit)
on_key_input: glfw key: 0x74 native_code: 0x11 action: PRESS mods: none text: 'kit' state: 1 updateIMEState: left=338.000000, top=17.000000, width=8.000000, height=17.000000
updated pre-edit text: 'kit'
Release: native_key: 0x11 (t) glfw_key: 0x74 mods: none 
on_key_input: glfw key: 0x74 native_code: 0x11 action: RELEASE mods: none text: '' state: 0 updateIMEState: left=346.000000, top=17.000000, width=8.000000, height=17.000000

Press: native_key: 0x11 (t) glfw_key: 0x74 mods: none char_count: 1 deadKeyState: 0 repeat: 0 
	setMarkedText: kitt selectedRange: (4, 0) replacementRange: (9223372036854775807, 0)
text: <none> glfw_key: t marked_text: (kitt)
on_key_input: glfw key: 0x74 native_code: 0x11 action: PRESS mods: none text: 'kitt' state: 1 updateIMEState: left=346.000000, top=17.000000, width=8.000000, height=17.000000
updated pre-edit text: 'kitt'
Release: native_key: 0x11 (t) glfw_key: 0x74 mods: none 
on_key_input: glfw key: 0x74 native_code: 0x11 action: RELEASE mods: none text: '' state: 0 updateIMEState: left=354.000000, top=17.000000, width=8.000000, height=17.000000

Press: native_key: 0x11 (t) glfw_key: 0x74 mods: none char_count: 1 deadKeyState: 0 repeat: 0 
	insertText: kitten replacementRange: (9223372036854775807, 0)

	setMarkedText: t selectedRange: (1, 0) replacementRange: (9223372036854775807, 0)
text: 0x6b 0x69 0x74 0x74 0x65 0x6e glfw_key: t marked_text: (t)
on_key_input: glfw key: 0x74 native_code: 0x11 action: PRESS mods: none text: '' state: 1 updateIMEState: left=354.000000, top=17.000000, width=8.000000, height=17.000000
updated pre-edit text: ''
on_key_input: glfw key: 0x74 native_code: 0x11 action: REPEAT mods: none text: 'kitten' state: 0 updateIMEState: left=322.000000, top=17.000000, width=8.000000, height=17.000000
sent key as text to child
on_key_input: glfw key: 0x74 native_code: 0x11 action: REPEAT mods: none text: 't' state: 1 updateIMEState: left=322.000000, top=17.000000, width=8.000000, height=17.000000
updated pre-edit text: 't'
Received char (0x6b) from child while overlay active. Overlay contents: t
updateIMEState: left=338.000000, top=17.000000, width=8.000000, height=17.000000
Received char (0x69) from child while overlay active. Overlay contents: t
updateIMEState: left=346.000000, top=17.000000, width=8.000000, height=17.000000
Received char (0x74) from child while overlay active. Overlay contents: t
updateIMEState: left=354.000000, top=17.000000, width=8.000000, height=17.000000
Received char (0x74) from child while overlay active. Overlay contents: t
updateIMEState: left=362.000000, top=17.000000, width=8.000000, height=17.000000
Received char (0x65) from child while overlay active. Overlay contents: t
updateIMEState: left=370.000000, top=17.000000, width=8.000000, height=17.000000
Received char (0x6e) from child while overlay active. Overlay contents: t
updateIMEState: left=378.000000, top=17.000000, width=8.000000, height=17.000000
Received char (0x6b) from child while overlay active. Overlay contents: t
updateIMEState: left=602.000000, top=17.000000, width=8.000000, height=17.000000
Received char (0x69) from child while overlay active. Overlay contents: t
updateIMEState: left=610.000000, top=17.000000, width=8.000000, height=17.000000
Received char (0x74) from child while overlay active. Overlay contents: t
updateIMEState: left=618.000000, top=17.000000, width=8.000000, height=17.000000
Received char (0x74) from child while overlay active. Overlay contents: t
updateIMEState: left=626.000000, top=17.000000, width=8.000000, height=17.000000
Received char (0x65) from child while overlay active. Overlay contents: t
updateIMEState: left=634.000000, top=17.000000, width=8.000000, height=17.000000
Received char (0x6e) from child while overlay active. Overlay contents: t
updateIMEState: left=642.000000, top=17.000000, width=8.000000, height=17.000000
Received char (0x73) from child while overlay active. Overlay contents: t
updateIMEState: left=642.000000, top=17.000000, width=8.000000, height=17.000000
Release: native_key: 0x11 (t) glfw_key: 0x74 mods: none 
on_key_input: glfw key: 0x74 native_code: 0x11 action: RELEASE mods: none text: '' state: 0 updateIMEState: left=370.000000, top=34.000000, width=8.000000, height=17.000000

Press: native_key: 0x31 ( ) glfw_key: 0x20 mods: none char_count: 1 deadKeyState: 0 repeat: 0 
	insertText: terminal replacementRange: (9223372036854775807, 0)
text: 0x74 0x65 0x72 0x6d 0x69 0x6e 0x61 0x6c glfw_key:   marked_text: ()
on_key_input: glfw key: 0x20 native_code: 0x31 action: PRESS mods: none text: '' state: 1 updateIMEState: left=370.000000, top=34.000000, width=8.000000, height=17.000000
updated pre-edit text: ''
on_key_input: glfw key: 0x20 native_code: 0x31 action: REPEAT mods: none text: 'terminal' state: 0 updateIMEState: left=370.000000, top=34.000000, width=8.000000, height=17.000000
sent key as text to child
Release: native_key: 0x31 ( ) glfw_key: 0x20 mods: none 
on_key_input: glfw key: 0x20 native_code: 0x31 action: RELEASE mods: none text: '' state: 0 updateIMEState: left=434.000000, top=34.000000, width=8.000000, height=17.000000

In vim, the third t of kittt is not shown, and when kittte is entered, te is shown as marked text.

@kovidgoyal
Copy link
Owner

Run with --dump-commands figure out what commands these programs are
sending to draw "kitty" and add SAVE_CURSOR_LINE at the start of those
functions in screen.c and you should be fine.

And let me just note for posterity, IME is the worlds worst idea.

@page-down
Copy link
Contributor Author

page-down commented Nov 12, 2021

The functions involved are the following.

diff --git a/kitty/screen.c b/kitty/screen.c
index 8918cb5b..6f219d44 100644
--- a/kitty/screen.c
+++ b/kitty/screen.c
@@ -794,6 +794,7 @@ screen_alignment_display(Screen *self) {
 
 void
 select_graphic_rendition(Screen *self, int *params, unsigned int count, Region *region_) {
+    SAVE_OVERLAY_LINE(select_graphic_rendition);
     if (region_) {
         Region region = *region_;
         if (!region.top) region.top = 1;
@@ -1052,6 +1053,7 @@ set_mode_from_const(Screen *self, unsigned int mode, bool val) {
 
 void
 screen_set_mode(Screen *self, unsigned int mode) {
+    SAVE_OVERLAY_LINE(screen_set_mode);
     set_mode_from_const(self, mode, true);
 }
 
@@ -1062,6 +1064,7 @@ screen_decsace(Screen *self, unsigned int val) {
 
 void
 screen_reset_mode(Screen *self, unsigned int mode) {
+    SAVE_OVERLAY_LINE(screen_reset_mode);
     set_mode_from_const(self, mode, false);
 }
 
@@ -1329,6 +1332,7 @@ screen_reverse_scroll_and_fill_from_scrollback(Screen *self, unsigned int count)
 
 void
 screen_carriage_return(Screen *self) {
+    SAVE_OVERLAY_LINE(screen_carriage_return);
     if (self->cursor->x != 0) {
         self->cursor->x = 0;
     }

Also in programs like vim, the IME position changes along with the text for obvious reasons as the cursor needs to be moved to other positions (status bar) to update the text. Hope everything is working fine.

And let me just note for posterity, IME is the worlds worst idea.

This is no joke. I've debugged some IMEs before and had a ton of issues on Linux, Windows as well.

As mentioned in the previous issue, if contributors implement "IME" (keystrokes to Unicode Text) in kitty, it will be a very smooth development experience. Users wouldn't have to suffer so much.

@kovidgoyal
Copy link
Owner

I dont think all those are necessary, I have committed a slightly
different version, please let me know if it works.

@page-down
Copy link
Contributor Author

I dont think all those are necessary, I have committed a slightly different version, please let me know if it works.

If it is not handled in select_graphic_rendition, it will come out using the color of the previous text. For example, a command that does not exist in fish is red, causing the background color of the marked text to be red as well. So this may have to be handled elsewhere.

Also in the screenshot below, I see draw s/, not sure where it comes from at the moment, but it's probably fish's auto-complete, auto-color marker, which is the text underneath the marked text.

After updating to the latest, vim shows the third t as marked text and it works fine.

Also I found that during IME input, if I switch to another window and switch back, it doesn't work properly.

@kovidgoyal
Copy link
Owner

kovidgoyal commented Nov 12, 2021 via email

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

No branches or pull requests

2 participants