xx-input-method-v2: Add actions including selection finishing

This update solves the mobile problem of the "enter" key.
It also makes precise cursor placement possible from the IME.

Signed-off-by: Dorota Czaplejewicz
This commit is contained in:
dcz 2025-07-01 04:57:25 +00:00 committed by DorotaC
parent a0387bdc70
commit 9b0e303048
2 changed files with 181 additions and 38 deletions

View file

@ -47,7 +47,7 @@
mechanism is discouraged. mechanism is discouraged.
</description> </description>
<interface name="xx_input_method_v1" version="2"> <interface name="xx_input_method_v1" version="3">
<description summary="input method"> <description summary="input method">
An input method object allows for clients to compose text. An input method object allows for clients to compose text.
@ -168,7 +168,7 @@
The initial value of cause is input_method. The initial value of cause is input_method.
</description> </description>
<arg name="cause" type="uint" enum="zwp_text_input_v3.change_cause"/> <arg name="cause" type="uint" enum="xx_text_input_v3.change_cause"/>
</event> </event>
<event name="content_type"> <event name="content_type">
@ -183,8 +183,38 @@
The initial value for hint is none, and the initial value for purpose The initial value for hint is none, and the initial value for purpose
is normal. is normal.
</description> </description>
<arg name="hint" type="uint" enum="zwp_text_input_v3.content_hint"/> <arg name="hint" type="uint" enum="xx_text_input_v3.content_hint"/>
<arg name="purpose" type="uint" enum="zwp_text_input_v3.content_purpose"/> <arg name="purpose" type="uint" enum="xx_text_input_v3.content_purpose"/>
</event>
<event name="set_available_actions" since="3">
<description summary="announce the available actions">
Announces the actions available for the currently active text input.
Values set with this event are double-buffered. They will get applied
on the next .done event.
They get reset to the initial value on the next committed deactivate event.
The initial value is an empty set: no actions are available.
Values in the available_actions array come from text-input-v3.action.
</description>
<arg name="available_actions" type="array" summary="available actions"/>
</event>
<event name="announce_supported_features" since="3">
<description summary="announce extra supported features">
Notifies the input method what the currently active text input client is able to do.
This event should come within the same .done sequence as .activate. Otherwise, the input method may ignore it.
Values set with this event are double-buffered. They will get applied
on the next .done event.
They get reset to initial on the next committed deactivate event.
The initial value for features is none.
</description>
<arg name="features" type="uint" enum="xx_text_input_v3.supported_features"/>
</event> </event>
<event name="done"> <event name="done">
@ -209,6 +239,18 @@
</description> </description>
</event> </event>
<request name="perform_action" since="3">
<description summary="perform action">
Perform an action on this text input.
Values set with this event are double-buffered. They must be applied
and reset to initial on the next commit request.
The initial value of action is none.
</description>
<arg name="action" type="uint" enum="xx_text_input_v3.action" summary="action to perform"/>
</request>
<request name="commit_string"> <request name="commit_string">
<description summary="commit string"> <description summary="commit string">
Send the commit string text for insertion to the application. Send the commit string text for insertion to the application.
@ -283,6 +325,34 @@
<arg name="after_length" type="uint"/> <arg name="after_length" type="uint"/>
</request> </request>
<request name="move_cursor" since="3">
<description summary="move cursor and change selection">
Unselects text, moves the cursor and selects text.
This is equivalent to dragging the mouse over some text: it deselects whatever might be currently selected and selects a new range of text.
The offsets used in arguments are in bytes relative to the current cursor position. Cursor is the new position of the cursor, and anchor is the opposite end of selection. If there's no selection, anchor should be equal to cursor.
The offsets do not take preedit contents into account, nor is preedit changed in any way with this request.
Both cursor and anchor must fall on code point boundaries, otherwise text input client may ignore the request. It is therefore not recommended for an input method to move any of them beyond the text received in surrounding_text.
When surrounding_text is not supported, the offsets must not be interpreted as bytes, but as some human-readable unit at least as big as a code point, for example a grapheme.
The cursor and anchor arguments can also take the following special values:
BEGINNING := 0x8000_0000 = i32::MIN
END := 0x7fff_ffff = i32::MAX
meaning, respectively, the beginning and the end of of all text in the input field.
Values set with this event are double-buffered. They must be applied
and reset to initial on the next commit request.
The initial values of both cursor and anchor are 0.
</description>
<arg name="cursor" type="int"/>
<arg name="anchor" type="int"/>
</request>
<request name="commit"> <request name="commit">
<description summary="apply state"> <description summary="apply state">
Apply state changes from commit_string, set_preedit_string and Apply state changes from commit_string, set_preedit_string and
@ -298,10 +368,14 @@
1. Replace existing preedit string with the cursor. 1. Replace existing preedit string with the cursor.
2. Delete requested surrounding text. 2. Delete requested surrounding text.
3. Insert commit string with the cursor at its end. 3. Insert commit string with the cursor at its end.
4. Calculate surrounding text to send. 4. Move the cursor and selection.
5. Insert new preedit text in cursor position. 5. Calculate surrounding text to send.
6. Place cursor inside preedit text. 6. Insert new preedit text in cursor position.
7. Place cursor inside preedit text.
8. Perform the requested action.
Note that the input method can not receive more than 4000 bytes of selection text, which might be the case for example when the entire document is selected. Nevertheless, the text input must delete the entire selected range before inserting the commit string.
The serial number reflects the last state of the xx_input_method_v1 The serial number reflects the last state of the xx_input_method_v1
object known to the client. The value of the serial argument must be object known to the client. The value of the serial argument must be
equal to the number of done events already issued by that object. When equal to the number of done events already issued by that object. When
@ -793,7 +867,7 @@
</request> </request>
</interface> </interface>
<interface name="xx_input_method_manager_v2" version="2"> <interface name="xx_input_method_manager_v2" version="3">
<description summary="input method manager"> <description summary="input method manager">
The input method manager allows the client to become the input method on The input method manager allows the client to become the input method on
a chosen seat. a chosen seat.

View file

@ -402,6 +402,43 @@
<arg name="after_length" type="uint" summary="length of text after current cursor position"/> <arg name="after_length" type="uint" summary="length of text after current cursor position"/>
</event> </event>
<event name="move_cursor" since="2">
<description summary="move cursor and change selection">
Unselects text, moves the cursor and selects text.
This is equivalent to dragging the mouse over some text: it deselects whatever might be currently selected and selects a new range of text.
The offsets used in arguments are in bytes relative to the current cursor position. Cursor is the new position of the cursor, and anchor is the opposite end of selection. If there's no selection, anchor should be equal to cursor.
In terms of dragging the mouse, the anchor is the start, and cursor the end.
The offsets do not take preedit contents into account, nor is preedit changed in any way with this request.
Both cursor and anchor must fall on code point boundaries, otherwise text input client may ignore the request. It is therefore not recommended for an input method to move any of them beyond the text received in surrounding_text.
<!-- Code point boundary checking must happen in the application because no one else is obliged to track the contents.
There are two ways to handle it:
1. add a request from the application informing the compositor of the mistake, so that the compositor can send an error and crash the input method, giving it the chance to reset and go back to normal
2. just ignore the request and hope the input method can resynchronize through surrounding_text
Choosing 2. because it's easier to implement.
-->
When surrounding_text is not supported, the offsets must not be interpreted as bytes, but as some human-readable unit at least as big as a code point, for example a grapheme.
The cursor and anchor arguments can also take the following special values:
BEGINNING := 0x8000_0000 = i32::MIN
END := 0x7fff_ffff = i32::MAX
meaning, respectively, the beginning and the end of of all text in the input field.
Values set with this event are double-buffered. They must be applied
and reset to initial on the next commit request.
The initial values of both cursor and anchor are 0.
</description>
<arg name="cursor" type="int"/>
<arg name="anchor" type="int"/>
</event>
<event name="done"> <event name="done">
<description summary="apply changes"> <description summary="apply changes">
Instruct the application to apply changes to state requested by the Instruct the application to apply changes to state requested by the
@ -417,10 +454,11 @@
1. Replace existing preedit string with the cursor. 1. Replace existing preedit string with the cursor.
2. Delete requested surrounding text. 2. Delete requested surrounding text.
3. Insert commit string with the cursor at its end. 3. Insert commit string with the cursor at its end.
4. Calculate surrounding text to send. 4. Move the cursor and selection.
5. Insert new preedit text in cursor position. 5. Calculate surrounding text to send.
6. Place cursor inside preedit text. 6. Insert new preedit text in cursor position.
7. Perform the requested action. 7. Place cursor inside preedit text.
8. Perform the requested action.
The serial number reflects the last state of the xx_text_input_v3 The serial number reflects the last state of the xx_text_input_v3
object known to the compositor. The value of the serial argument must object known to the compositor. The value of the serial argument must
@ -437,51 +475,82 @@
<arg name="serial" type="uint"/> <arg name="serial" type="uint"/>
</event> </event>
<enum name="error" since="2">
<entry name="invalid_action" value="0" summary="an invalid or duplicate action was specified"/>
</enum>
<enum name="action" since="2"> <enum name="action" since="2">
<description summary="action"> <description summary="action">
A possible action to perform on a text input. A possible action to perform on a text input.
The backspace and delete actions should be handled in a similar manner
to backpace and delete keys being pressed on a keyboard.
</description> </description>
<entry name="none" value="0" summary="no action"/> <!-- Notably missing: moving cursor, deleting and setting a selection. They are nicer to use as part of the text manipulation interface: ranges can be selected there.
<entry name="submit" value="1" summary="submit"/> Exceptions: the IME doesn't know where lines start or end. The IME will not get to see the entire 4MB document so it can't select all through the text interface. But this doesn't seem urgent. -->
<entry name="backspace" value="2" summary="delete one unit before the cursor"/>
<entry name="delete" value="3" summary="delete one unit after the cursor"/>
</enum>
<event name="action" since="2"> <!-- types of finish actions are better communicated as a hint: this triggers a URL navigation, this sends a search query, this sends a message, etc. The input method can then choose the appropriate buttons to display -->
<entry name="finish" value="0">
<description summary="trigger appropriate action for the completion of editing">
This should be triggered when the user is done with editing the field and wants to move on. For example, the query was typed and the user wants the search result. Or the name was entered and the address needs to be typed next.
The action to perform depends on the application, and should match the value of the current content_purpose.
All clients SHOULD implement this action. Without it, on-screen keyboards don't work as expected.
</description>
</entry>
</enum>
<event name="perform_action" since="2">
<description summary="action performed"> <description summary="action performed">
An action was performed on this text input. The input method issued an action to perform on this text input.
Values set with this event are double-buffered. They must be applied Values set with this event are double-buffered. They must be applied
and reset to initial on the next zwp_text_input_v4.done event. and reset to initial on the next .done event.
The initial value of action is none. The initial value of action is none.
</description> </description>
<arg name="action" type="uint" enum="action" summary="action performed"/> <arg name="action" type="uint" enum="action" summary="action performed"/>
<arg name="serial" type="uint" summary="serial number of the action event"/> </event>
</enum>
<request name="set_available_actions" since="2"> <request name="set_available_actions" since="2">
<description summary="set the available actions"> <description summary="announce the available actions">
Set the actions available for this text input. Announces the actions available for the currently active text input.
Values set with this request are double-buffered. They will get applied Values set with this event are double-buffered. They will get applied
on the next zwp_text_input_v4.commit request. on the next .done event.
They get reset to the initial value on the next committed deactivate event.
If the available_actions array contains the none action, or contains the The initial value is an empty set: no actions are available.
same action multiple times, the compositor must raise the invalid_action
protocol error. Values in the available_actions array come from text-input-v3.action.
Initially, no actions are available.
</description> </description>
<!-- Removed the protocol error on none and duplicates because a client has no interest in crashing for slight compositor misbehaviour. Ignoring extraneous values should not be a problem for any half-competent library. -->
<arg name="available_actions" type="array" summary="available actions"/> <arg name="available_actions" type="array" summary="available actions"/>
<!-- Should this be a bitmap instead of an array? 32 generic actions should be enough, and client-specific actions would need a new protocol anyway -->
</request>
<enum name="supported_features" bitfield="true" since="2">
<description summary="possible supported features">
Client functionality over the baseline that isn't indicated implicitly.
This does not include events coming with .enable: when the input method receives such an event, it is clear the text input supports it, e.g. content_type, available_actions.
Baseline functionality like commit_string, set_preedit_string must always be supported for the protocol to be useful.
The flags match text-input protocol versions, but should be kept general enough to support other protocols.
</description>
<entry name="none" value="0x0" summary="no extra functionality supported"/>
<entry name="move_cursor" value="0x1" summary="the move_cursor request"/>
</enum> </enum>
<request name="announce_supported_features" since="2">
<description summary="announce extra supported features">
Notifies the input method what the currently active text input client is able to do.
This event should come within the same .done sequence as .activate. Otherwise, the input method may ignore it.
Values set with this event are double-buffered. They will get applied
on the next .done event.
They get reset to initial on the next committed deactivate event.
The initial value for features is none.
</description>
<arg name="features" type="uint" enum="xx_text_input_v3.supported_features"/>
</request>
</interface> </interface>
<interface name="xx_text_input_manager_v3" version="2"> <interface name="xx_text_input_manager_v3" version="2">