Skip to content

Commit 4e579b7

Browse files
n0samuDinnerbone
authored andcommitted
core: Move left/right arrow handling to text_control_input
1 parent 0dbb4c4 commit 4e579b7

File tree

6 files changed

+107
-85
lines changed

6 files changed

+107
-85
lines changed

core/src/display_object/edit_text.rs

Lines changed: 58 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ use crate::display_object::interactive::{
1717
};
1818
use crate::display_object::{DisplayObjectBase, DisplayObjectPtr, TDisplayObject};
1919
use crate::drawing::Drawing;
20-
use crate::events::{ButtonKeyCode, ClipEvent, ClipEventResult, KeyCode, TextControlCode};
20+
use crate::events::{ClipEvent, ClipEventResult, TextControlCode};
2121
use crate::font::{round_down_to_pixel, Glyph, TextRenderSettings};
2222
use crate::html::{BoxBounds, FormatSpans, LayoutBox, LayoutContent, LayoutMetrics, TextFormat};
2323
use crate::prelude::*;
@@ -1203,6 +1203,46 @@ impl<'gc> EditText<'gc> {
12031203
let mut changed = false;
12041204
let is_selectable = self.is_selectable();
12051205
match control_code {
1206+
TextControlCode::MoveLeft => {
1207+
let new_pos = if selection.is_caret() && selection.to > 0 {
1208+
string_utils::prev_char_boundary(&self.text(), selection.to)
1209+
} else {
1210+
selection.start()
1211+
};
1212+
self.set_selection(
1213+
Some(TextSelection::for_position(new_pos)),
1214+
context.gc_context,
1215+
);
1216+
}
1217+
TextControlCode::MoveRight => {
1218+
let new_pos = if selection.is_caret() && selection.to < self.text().len() {
1219+
string_utils::next_char_boundary(&self.text(), selection.to)
1220+
} else {
1221+
selection.end()
1222+
};
1223+
self.set_selection(
1224+
Some(TextSelection::for_position(new_pos)),
1225+
context.gc_context,
1226+
);
1227+
}
1228+
TextControlCode::SelectLeft => {
1229+
if is_selectable && selection.to > 0 {
1230+
let new_pos = string_utils::prev_char_boundary(&self.text(), selection.to);
1231+
self.set_selection(
1232+
Some(TextSelection::for_range(selection.from, new_pos)),
1233+
context.gc_context,
1234+
);
1235+
}
1236+
}
1237+
TextControlCode::SelectRight => {
1238+
if is_selectable && selection.to < self.text().len() {
1239+
let new_pos = string_utils::next_char_boundary(&self.text(), selection.to);
1240+
self.set_selection(
1241+
Some(TextSelection::for_range(selection.from, new_pos)),
1242+
context.gc_context,
1243+
)
1244+
}
1245+
}
12061246
TextControlCode::SelectAll => {
12071247
if is_selectable {
12081248
self.set_selection(
@@ -1222,11 +1262,16 @@ impl<'gc> EditText<'gc> {
12221262
// TODO: To match Flash Player, we should truncate pasted text that is longer than max_chars
12231263
// instead of canceling the paste action entirely
12241264
if text.len() <= self.available_chars() {
1225-
self.replace_text(selection.start(), selection.end(), &WString::from_utf8(text), context);
1226-
let new_start = selection.start() + text.len();
1265+
self.replace_text(
1266+
selection.start(),
1267+
selection.end(),
1268+
&WString::from_utf8(text),
1269+
context,
1270+
);
1271+
let new_pos = selection.start() + text.len();
12271272
if is_selectable {
12281273
self.set_selection(
1229-
Some(TextSelection::for_position(new_start)),
1274+
Some(TextSelection::for_position(new_pos)),
12301275
context.gc_context,
12311276
);
12321277
} else {
@@ -1243,7 +1288,12 @@ impl<'gc> EditText<'gc> {
12431288
let text = &self.text()[selection.start()..selection.end()];
12441289
context.ui.set_clipboard_content(text.to_string());
12451290

1246-
self.replace_text(selection.start(), selection.end(), WStr::empty(), context);
1291+
self.replace_text(
1292+
selection.start(),
1293+
selection.end(),
1294+
WStr::empty(),
1295+
context,
1296+
);
12471297
if is_selectable {
12481298
self.set_selection(
12491299
Some(TextSelection::for_position(selection.start())),
@@ -1322,9 +1372,9 @@ impl<'gc> EditText<'gc> {
13221372
&WString::from_char(character),
13231373
context,
13241374
);
1325-
let new_start = selection.start() + character.len_utf8();
1375+
let new_pos = selection.start() + character.len_utf8();
13261376
self.set_selection(
1327-
Some(TextSelection::for_position(new_start)),
1377+
Some(TextSelection::for_position(new_pos)),
13281378
context.gc_context,
13291379
);
13301380
changed = true;
@@ -1345,61 +1395,6 @@ impl<'gc> EditText<'gc> {
13451395
}
13461396
}
13471397

1348-
/// Listens for keyboard text control commands.
1349-
///
1350-
/// TODO: Add explicit text control events (#4452).
1351-
pub fn handle_text_control_event(
1352-
self,
1353-
context: &mut UpdateContext<'_, 'gc>,
1354-
event: ClipEvent,
1355-
) -> ClipEventResult {
1356-
if let ClipEvent::KeyPress { key_code } = event {
1357-
let mut edit_text = self.0.write(context.gc_context);
1358-
let selection = edit_text.selection;
1359-
if let Some(mut selection) = selection {
1360-
let text = edit_text.text_spans.text();
1361-
let length = text.len();
1362-
match key_code {
1363-
ButtonKeyCode::Left => {
1364-
if (context.input.is_key_down(KeyCode::Shift) || selection.is_caret())
1365-
&& selection.to > 0
1366-
{
1367-
selection.to = string_utils::prev_char_boundary(text, selection.to);
1368-
if !context.input.is_key_down(KeyCode::Shift) {
1369-
selection.from = selection.to;
1370-
}
1371-
} else if !context.input.is_key_down(KeyCode::Shift) {
1372-
selection.to = selection.start();
1373-
selection.from = selection.to;
1374-
}
1375-
selection.clamp(length);
1376-
edit_text.selection = Some(selection);
1377-
return ClipEventResult::Handled;
1378-
}
1379-
ButtonKeyCode::Right => {
1380-
if (context.input.is_key_down(KeyCode::Shift) || selection.is_caret())
1381-
&& selection.to < length
1382-
{
1383-
selection.to = string_utils::next_char_boundary(text, selection.to);
1384-
if !context.input.is_key_down(KeyCode::Shift) {
1385-
selection.from = selection.to;
1386-
}
1387-
} else if !context.input.is_key_down(KeyCode::Shift) {
1388-
selection.to = selection.end();
1389-
selection.from = selection.to;
1390-
}
1391-
selection.clamp(length);
1392-
edit_text.selection = Some(selection);
1393-
return ClipEventResult::Handled;
1394-
}
1395-
_ => (),
1396-
}
1397-
}
1398-
}
1399-
1400-
ClipEventResult::NotHandled
1401-
}
1402-
14031398
fn initialize_as_broadcaster(&self, activation: &mut Avm1Activation<'_, 'gc>) {
14041399
if let Avm1Value::Object(object) = self.object() {
14051400
activation.context.avm1.broadcaster_functions().initialize(
@@ -2043,7 +2038,7 @@ impl TextSelection {
20432038
self.from.min(self.to)
20442039
}
20452040

2046-
/// The "end" part of the range is the smallest (closest to 0) part of this selection range.
2041+
/// The "end" part of the range is the largest (farthest from 0) part of this selection range.
20472042
pub fn end(&self) -> usize {
20482043
self.from.max(self.to)
20492044
}

core/src/events.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ pub enum PlayerEvent {
3333
codepoint: char,
3434
},
3535
TextControl {
36-
code: TextControlCode
36+
code: TextControlCode,
3737
},
3838
}
3939

@@ -337,6 +337,10 @@ impl<'gc> ClipEvent<'gc> {
337337
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
338338
pub enum TextControlCode {
339339
// TODO: Extend this
340+
MoveLeft,
341+
MoveRight,
342+
SelectLeft,
343+
SelectRight,
340344
SelectAll,
341345
Copy,
342346
Paste,

core/src/player.rs

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -991,16 +991,6 @@ impl Player {
991991
if state == ClipEventResult::Handled {
992992
key_press_handled = true;
993993
break;
994-
} else if let Some(text) =
995-
context.focus_tracker.get().and_then(|o| o.as_edit_text())
996-
{
997-
// Text fields listen for arrow key presses, etc.
998-
if text.handle_text_control_event(context, button_event)
999-
== ClipEventResult::Handled
1000-
{
1001-
key_press_handled = true;
1002-
break;
1003-
}
1004994
}
1005995
}
1006996
}

desktop/src/main.rs

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,11 +22,11 @@ use isahc::{config::RedirectPolicy, prelude::*, HttpClient};
2222
use rfd::FileDialog;
2323
use ruffle_core::backend::audio::AudioBackend;
2424
use ruffle_core::backend::navigator::OpenURLMode;
25+
use ruffle_core::events::{KeyCode, TextControlCode};
2526
use ruffle_core::{
26-
config::Letterbox, tag_utils::SwfMovie, LoadBehavior, Player, PlayerBuilder,
27-
PlayerEvent, StageDisplayState, StageScaleMode, StaticCallstack, ViewportDimensions,
27+
config::Letterbox, tag_utils::SwfMovie, LoadBehavior, Player, PlayerBuilder, PlayerEvent,
28+
StageDisplayState, StageScaleMode, StaticCallstack, ViewportDimensions,
2829
};
29-
use ruffle_core::events::{KeyCode, TextControlCode};
3030
use ruffle_render::backend::RenderBackend;
3131
use ruffle_render::quality::StageQuality;
3232
use ruffle_render_wgpu::backend::WgpuRenderBackend;
@@ -589,7 +589,9 @@ impl App {
589589
let key_char = winit_key_to_char(key, modifiers.shift());
590590
let event = match input.state {
591591
ElementState::Pressed => {
592-
if let Some(control_code) = winit_to_ruffle_text_control(key, modifiers) {
592+
if let Some(control_code) =
593+
winit_to_ruffle_text_control(key, modifiers)
594+
{
593595
PlayerEvent::TextControl { code: control_code }
594596
} else {
595597
PlayerEvent::KeyDown { key_code, key_char }
@@ -917,6 +919,7 @@ fn winit_to_ruffle_text_control(
917919
key: VirtualKeyCode,
918920
modifiers: ModifiersState,
919921
) -> Option<TextControlCode> {
922+
let shift = modifiers.contains(ModifiersState::SHIFT);
920923
let ctrl_cmd = modifiers.contains(ModifiersState::CTRL)
921924
|| (modifiers.contains(ModifiersState::LOGO) && cfg!(target_os = "macos"));
922925
if ctrl_cmd {
@@ -931,6 +934,20 @@ fn winit_to_ruffle_text_control(
931934
match key {
932935
VirtualKeyCode::Back => Some(TextControlCode::Backspace),
933936
VirtualKeyCode::Delete => Some(TextControlCode::Delete),
937+
VirtualKeyCode::Left => {
938+
if shift {
939+
Some(TextControlCode::SelectLeft)
940+
} else {
941+
Some(TextControlCode::MoveLeft)
942+
}
943+
}
944+
VirtualKeyCode::Right => {
945+
if shift {
946+
Some(TextControlCode::SelectRight)
947+
} else {
948+
Some(TextControlCode::MoveRight)
949+
}
950+
}
934951
_ => None,
935952
}
936953
}

desktop/src/ui.rs

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -63,9 +63,7 @@ impl UiBackend for DesktopUiBackend {
6363
}
6464

6565
fn clipboard_content(&mut self) -> String {
66-
self.clipboard
67-
.get_text()
68-
.unwrap_or_else(|_| "".to_string())
66+
self.clipboard.get_text().unwrap_or_else(|_| "".to_string())
6967
}
7068

7169
fn set_clipboard_content(&mut self, content: String) {

web/src/lib.rs

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -843,9 +843,13 @@ impl Ruffle {
843843
let is_ctrl_cmd = js_event.ctrl_key() || js_event.meta_key();
844844
core.handle_event(PlayerEvent::KeyDown { key_code, key_char });
845845

846-
if let Some(control_code) = web_to_text_control(&js_event.key(), is_ctrl_cmd) {
846+
if let Some(control_code) = web_to_text_control(
847+
&js_event.key(),
848+
is_ctrl_cmd,
849+
js_event.shift_key(),
850+
) {
847851
core.handle_event(PlayerEvent::TextControl { code: control_code })
848-
}else if let Some(codepoint) = key_char {
852+
} else if let Some(codepoint) = key_char {
849853
core.handle_event(PlayerEvent::TextInput { codepoint });
850854
}
851855
});
@@ -1744,7 +1748,7 @@ fn web_key_to_codepoint(key: &str) -> Option<char> {
17441748
}
17451749
}
17461750

1747-
pub fn web_to_text_control(key: &str, ctrl_key: bool) -> Option<TextControlCode> {
1751+
pub fn web_to_text_control(key: &str, ctrl_key: bool, shift_key: bool) -> Option<TextControlCode> {
17481752
let mut chars = key.chars();
17491753
let (c1, c2) = (chars.next(), chars.next());
17501754
if c2.is_none() {
@@ -1765,7 +1769,21 @@ pub fn web_to_text_control(key: &str, ctrl_key: bool) -> Option<TextControlCode>
17651769
match key {
17661770
"Delete" => Some(TextControlCode::Delete),
17671771
"Backspace" => Some(TextControlCode::Backspace),
1772+
"ArrowLeft" => {
1773+
if shift_key {
1774+
Some(TextControlCode::SelectLeft)
1775+
} else {
1776+
Some(TextControlCode::MoveLeft)
1777+
}
1778+
}
1779+
"ArrowRight" => {
1780+
if shift_key {
1781+
Some(TextControlCode::SelectRight)
1782+
} else {
1783+
Some(TextControlCode::MoveRight)
1784+
}
1785+
}
17681786
_ => None,
17691787
}
17701788
}
1771-
}
1789+
}

0 commit comments

Comments
 (0)