Selection mode: Move each ends of selection separately with slider

When the selection mode is activated, the space bar sliders change how
they affect the selection:

- The left side of the slider moves the left position of the selection.
  To shrink the selection from the left side, the slider must be
  activated by sliding to the left, extending the selection
  temporarilly, then by sliding to the right.

- The right side of the slider affects the right position if the
  selection.
This commit is contained in:
Jules Aguillon 2025-03-01 16:34:20 +01:00
parent 68c4ba96b7
commit 13988ba2fe
3 changed files with 60 additions and 15 deletions

View File

@ -254,15 +254,17 @@ public final class KeyEventHandler
return conn.getExtractedText(_move_cursor_req, 0); return conn.getExtractedText(_move_cursor_req, 0);
} }
/** [repeatition] might be negative, in which case the direction is reversed. */ /** [r] might be negative, in which case the direction is reversed. */
void handle_slider(KeyValue.Slider s, int repeatition) void handle_slider(KeyValue.Slider s, int r)
{ {
switch (s) switch (s)
{ {
case Cursor_left: move_cursor(-repeatition); break; case Cursor_left: move_cursor(-r); break;
case Cursor_right: move_cursor(repeatition); break; case Cursor_right: move_cursor(r); break;
case Cursor_up: move_cursor_vertical(-repeatition); break; case Cursor_up: move_cursor_vertical(-r); break;
case Cursor_down: move_cursor_vertical(repeatition); break; case Cursor_down: move_cursor_vertical(r); break;
case Selection_cursor_left: move_cursor_sel(r, true); break;
case Selection_cursor_right: move_cursor_sel(r, false); break;
} }
} }
@ -276,12 +278,7 @@ public final class KeyEventHandler
if (conn == null) if (conn == null)
return; return;
ExtractedText et = get_cursor_pos(conn); ExtractedText et = get_cursor_pos(conn);
int system_mods = if (et != null && can_set_selection(conn))
KeyEvent.META_CTRL_ON | KeyEvent.META_ALT_ON | KeyEvent.META_META_ON;
// Fallback to sending key events if system modifiers are activated or
// ExtractedText is not supported, for example on Termux.
if (!_move_cursor_force_fallback && et != null
&& (_meta_state & system_mods) == 0)
{ {
int sel_start = et.selectionStart; int sel_start = et.selectionStart;
int sel_end = et.selectionEnd; int sel_end = et.selectionEnd;
@ -300,8 +297,45 @@ public final class KeyEventHandler
sel_start = sel_end; sel_start = sel_end;
} }
if (conn.setSelection(sel_start, sel_end)) if (conn.setSelection(sel_start, sel_end))
return; // [setSelection] succeeded, don't fallback to key events return; // Fallback to sending key events if [setSelection] failed
} }
move_cursor_fallback(d);
}
/** Move one of the two side of a selection. If [sel_left] is true, the left
position is moved, otherwise the right position is moved. */
void move_cursor_sel(int d, boolean sel_left)
{
InputConnection conn = _recv.getCurrentInputConnection();
if (conn == null)
return;
ExtractedText et = get_cursor_pos(conn);
if (et != null && can_set_selection(conn))
{
int sel_start = et.selectionStart;
int sel_end = et.selectionEnd;
if (sel_left == (sel_start <= sel_end))
sel_start += d;
else
sel_end += d;
if (conn.setSelection(sel_start, sel_end))
return; // Fallback to sending key events if [setSelection] failed
}
move_cursor_fallback(d);
}
/** Returns whether the selection can be set using [conn.setSelection()].
This can happen on Termux or when system modifiers are activated for
example. */
boolean can_set_selection(InputConnection conn)
{
final int system_mods =
KeyEvent.META_CTRL_ON | KeyEvent.META_ALT_ON | KeyEvent.META_META_ON;
return !_move_cursor_force_fallback && (_meta_state & system_mods) == 0;
}
void move_cursor_fallback(int d)
{
if (d < 0) if (d < 0)
send_key_down_up_repeat(KeyEvent.KEYCODE_DPAD_LEFT, -d); send_key_down_up_repeat(KeyEvent.KEYCODE_DPAD_LEFT, -d);
else else

View File

@ -397,6 +397,13 @@ public final class KeyModifier
case ' ': name = "selection_cancel"; break; case ' ': name = "selection_cancel"; break;
} }
break; break;
case Slider:
switch (k.getSlider())
{
case Cursor_left: name = "selection_cursor_left"; break;
case Cursor_right: name = "selection_cursor_right"; break;
}
break;
case Keyevent: case Keyevent:
switch (k.getKeyevent()) switch (k.getKeyevent())
{ {

View File

@ -713,6 +713,9 @@ public final class KeyValue implements Comparable<KeyValue>
case "cursor_right": return sliderKey(Slider.Cursor_right, 1); case "cursor_right": return sliderKey(Slider.Cursor_right, 1);
case "cursor_up": return sliderKey(Slider.Cursor_up, 1); case "cursor_up": return sliderKey(Slider.Cursor_up, 1);
case "cursor_down": return sliderKey(Slider.Cursor_down, 1); case "cursor_down": return sliderKey(Slider.Cursor_down, 1);
case "selection_cancel": return editingKey("Esc", Editing.SELECTION_CANCEL, FLAG_SMALLER_FONT);
case "selection_cursor_left": return sliderKey(Slider.Selection_cursor_left, -1); // Move the left side of the selection
case "selection_cursor_right": return sliderKey(Slider.Selection_cursor_right, 1);
// These keys are not used // These keys are not used
case "replaceText": return editingKey("repl", Editing.REPLACE); case "replaceText": return editingKey("repl", Editing.REPLACE);
case "textAssist": return editingKey(0xE038, Editing.ASSIST); case "textAssist": return editingKey(0xE038, Editing.ASSIST);
@ -764,7 +767,6 @@ public final class KeyValue implements Comparable<KeyValue>
/* Internal keys */ /* Internal keys */
case "selection_mode": return makeInternalModifier(Modifier.SELECTION_MODE); case "selection_mode": return makeInternalModifier(Modifier.SELECTION_MODE);
case "selection_cancel": return editingKey("Esc", Editing.SELECTION_CANCEL, FLAG_SMALLER_FONT);
default: return null; default: return null;
} }
@ -782,7 +784,9 @@ public final class KeyValue implements Comparable<KeyValue>
Cursor_left(0xE008), Cursor_left(0xE008),
Cursor_right(0xE006), Cursor_right(0xE006),
Cursor_up(0xE005), Cursor_up(0xE005),
Cursor_down(0xE007); Cursor_down(0xE007),
Selection_cursor_left(0xE008),
Selection_cursor_right(0xE006);
final String symbol; final String symbol;