diff --git a/Cargo.lock b/Cargo.lock index 7e211cad5eb4..6960601f9bc1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4184,6 +4184,7 @@ dependencies = [ "downcast-rs", "egui", "egui_extras", + "either", "encoding_rs", "enum-map", "enumset", diff --git a/core/Cargo.toml b/core/Cargo.toml index d2f5668bcf4d..cc4cb764af3b 100644 --- a/core/Cargo.toml +++ b/core/Cargo.toml @@ -66,6 +66,7 @@ ttf-parser = "0.20" num-bigint = "0.4" unic-segment = "0.9.0" id3 = "1.13.1" +either = "1.10.0" [target.'cfg(not(target_family = "wasm"))'.dependencies.futures] version = "0.3.30" diff --git a/core/src/avm2/qname.rs b/core/src/avm2/qname.rs index f70aab3ca34a..59efb7a8a13f 100644 --- a/core/src/avm2/qname.rs +++ b/core/src/avm2/qname.rs @@ -1,8 +1,8 @@ use crate::avm2::script::TranslationUnit; use crate::avm2::{Activation, Error, Namespace}; use crate::context::UpdateContext; -use crate::either::Either; use crate::string::{AvmString, WStr, WString}; +use either::Either; use gc_arena::{Collect, Mutation}; use std::fmt::Debug; use swf::avm2::types::{Index, Multiname as AbcMultiname}; diff --git a/core/src/either.rs b/core/src/either.rs deleted file mode 100644 index 4f7167c9e310..000000000000 --- a/core/src/either.rs +++ /dev/null @@ -1,21 +0,0 @@ -use std::ops::Deref; - -pub enum Either { - Left(A), - Right(B), -} - -impl Deref for Either -where - A: Deref, - B: Deref, -{ - type Target = A::Target; - - fn deref(&self) -> &Self::Target { - match self { - Self::Left(a) => a, - Self::Right(b) => b, - } - } -} diff --git a/core/src/focus_tracker.rs b/core/src/focus_tracker.rs index 020108368fd0..50b5f0f793e3 100644 --- a/core/src/focus_tracker.rs +++ b/core/src/focus_tracker.rs @@ -4,6 +4,7 @@ use crate::context::UpdateContext; pub use crate::display_object::{ DisplayObject, TDisplayObject, TDisplayObjectContainer, TextSelection, }; +use either::Either; use gc_arena::lock::GcLock; use gc_arena::{Collect, Mutation}; @@ -67,7 +68,7 @@ impl<'gc> FocusTracker<'gc> { } } - pub fn cycle(&self, context: &mut UpdateContext<'_, 'gc>) { + pub fn cycle(&self, context: &mut UpdateContext<'_, 'gc>, reverse: bool) { let stage = context.stage; let mut tab_order = vec![]; stage.fill_tab_order(&mut tab_order, context); @@ -88,16 +89,23 @@ impl<'gc> FocusTracker<'gc> { tab_order.sort_by_key(|o| o.tab_index()); } + let mut tab_order = if reverse { + Either::Left(tab_order.iter().rev()) + } else { + Either::Right(tab_order.iter()) + } + .peekable(); + let first = tab_order.peek().copied(); + let next = if let Some(current_focus) = self.0.get() { // Find the next object which should take the focus. tab_order - .iter() .skip_while(|o| o.as_ptr() != current_focus.as_ptr()) .nth(1) - .or(tab_order.first()) + .or(first) } else { // If no focus is present, we start from the beginning. - tab_order.first() + first }; self.set(next.copied(), context); diff --git a/core/src/lib.rs b/core/src/lib.rs index fc43e80845b6..2a76613d5e66 100644 --- a/core/src/lib.rs +++ b/core/src/lib.rs @@ -29,7 +29,6 @@ pub mod context; pub mod context_menu; mod drawing; mod ecma_conversions; -pub(crate) mod either; pub mod events; pub mod focus_tracker; mod font; diff --git a/core/src/player.rs b/core/src/player.rs index ea1772b4f962..bd47e1005a0b 100644 --- a/core/src/player.rs +++ b/core/src/player.rs @@ -1186,8 +1186,9 @@ impl Player { } = event { self.mutate_with_update_context(|context| { + let reversed = context.input.is_key_down(KeyCode::Shift); let tracker = context.focus_tracker; - tracker.cycle(context); + tracker.cycle(context, reversed); }); } } diff --git a/tests/framework/src/runner.rs b/tests/framework/src/runner.rs index 953b1bf35745..30756907c246 100644 --- a/tests/framework/src/runner.rs +++ b/tests/framework/src/runner.rs @@ -230,6 +230,10 @@ impl TestRunner { key_code: KeyCode::from_u8(*key_code).expect("Invalid keycode in test"), key_char: None, }, + AutomatedEvent::KeyUp { key_code } => PlayerEvent::KeyUp { + key_code: KeyCode::from_u8(*key_code).expect("Invalid keycode in test"), + key_char: None, + }, AutomatedEvent::TextInput { codepoint } => PlayerEvent::TextInput { codepoint: *codepoint, }, diff --git a/tests/input-format/src/format.rs b/tests/input-format/src/format.rs index a60ac59bed44..71540c338832 100644 --- a/tests/input-format/src/format.rs +++ b/tests/input-format/src/format.rs @@ -65,6 +65,9 @@ pub enum AutomatedEvent { /// Press a key KeyDown { key_code: u8 }, + /// Release a key + KeyUp { key_code: u8 }, + /// Input a character code TextInput { codepoint: char }, diff --git a/tests/input-format/src/injector.rs b/tests/input-format/src/injector.rs index a0d326c15b33..28a120f5dd95 100644 --- a/tests/input-format/src/injector.rs +++ b/tests/input-format/src/injector.rs @@ -96,6 +96,7 @@ impl InputInjector { AutomatedEvent::Wait => break, AutomatedEvent::MouseMove { .. } | AutomatedEvent::KeyDown { .. } + | AutomatedEvent::KeyUp { .. } | AutomatedEvent::TextInput { .. } | AutomatedEvent::TextControl { .. } | AutomatedEvent::SetClipboardText { .. } => {} diff --git a/tests/tests/swfs/avm1/tab_ordering_reverse/input.json b/tests/tests/swfs/avm1/tab_ordering_reverse/input.json new file mode 100644 index 000000000000..3ca80b630b38 --- /dev/null +++ b/tests/tests/swfs/avm1/tab_ordering_reverse/input.json @@ -0,0 +1,24 @@ +[ + { "type": "KeyDown", "key_code": 9 }, + { "type": "KeyDown", "key_code": 9 }, + { "type": "KeyDown", "key_code": 16 }, + { "type": "KeyDown", "key_code": 9 }, + { "type": "KeyUp", "key_code": 16 }, + { "type": "KeyDown", "key_code": 9 }, + { "type": "KeyDown", "key_code": 16 }, + { "type": "KeyDown", "key_code": 9 }, + { "type": "KeyDown", "key_code": 9 }, + { "type": "KeyDown", "key_code": 9 }, + { "type": "KeyUp", "key_code": 16 }, + { "type": "KeyDown", "key_code": 9 }, + { "type": "KeyDown", "key_code": 9 }, + { "type": "KeyDown", "key_code": 17 }, + { "type": "KeyDown", "key_code": 9 }, + { "type": "KeyUp", "key_code": 17 }, + { "type": "KeyDown", "key_code": 16 }, + { "type": "KeyDown", "key_code": 17 }, + { "type": "KeyDown", "key_code": 9 }, + { "type": "KeyUp", "key_code": 17 }, + { "type": "KeyUp", "key_code": 16 }, + { "type": "KeyDown", "key_code": 9 } +] diff --git a/tests/tests/swfs/avm1/tab_ordering_reverse/output.txt b/tests/tests/swfs/avm1/tab_ordering_reverse/output.txt new file mode 100644 index 000000000000..1ee971e0ff60 --- /dev/null +++ b/tests/tests/swfs/avm1/tab_ordering_reverse/output.txt @@ -0,0 +1,51 @@ +Focus changed + old: null + new: _level0.text1 +Tab pressed +Focus changed + old: _level0.text1 + new: _level0.text2 +Tab pressed +Focus changed + old: _level0.text2 + new: _level0.text3 +Tab pressed +Focus changed + old: _level0.text3 + new: _level0.text2 +Tab pressed +Focus changed + old: _level0.text2 + new: _level0.text3 +Tab pressed +Focus changed + old: _level0.text3 + new: _level0.text2 +Tab pressed +Focus changed + old: _level0.text2 + new: _level0.text1 +Tab pressed +Focus changed + old: _level0.text1 + new: _level0.text4 +Tab pressed +Focus changed + old: _level0.text4 + new: _level0.text1 +Tab pressed +Focus changed + old: _level0.text1 + new: _level0.text2 +Tab pressed +Focus changed + old: _level0.text2 + new: _level0.text3 +Tab pressed +Focus changed + old: _level0.text3 + new: _level0.text2 +Tab pressed +Focus changed + old: _level0.text2 + new: _level0.text3 diff --git a/tests/tests/swfs/avm1/tab_ordering_reverse/test.as b/tests/tests/swfs/avm1/tab_ordering_reverse/test.as new file mode 100644 index 000000000000..9633923eb424 --- /dev/null +++ b/tests/tests/swfs/avm1/tab_ordering_reverse/test.as @@ -0,0 +1,11 @@ +var listener = new Object(); +listener.onSetFocus = function(oldFocus, newFocus) { + if (newFocus) { + trace("Focus changed"); + trace(" old: " + oldFocus); + trace(" new: " + newFocus); + } +}; +Selection.addListener(listener); + +Selection.setFocus(text1); diff --git a/tests/tests/swfs/avm1/tab_ordering_reverse/test.swf b/tests/tests/swfs/avm1/tab_ordering_reverse/test.swf new file mode 100644 index 000000000000..358e00590e04 Binary files /dev/null and b/tests/tests/swfs/avm1/tab_ordering_reverse/test.swf differ diff --git a/tests/tests/swfs/avm1/tab_ordering_reverse/test.toml b/tests/tests/swfs/avm1/tab_ordering_reverse/test.toml new file mode 100644 index 000000000000..cf6123969a1d --- /dev/null +++ b/tests/tests/swfs/avm1/tab_ordering_reverse/test.toml @@ -0,0 +1 @@ +num_ticks = 1