From f636445a27b758dd1f8a132678eab2f6b213cc7d Mon Sep 17 00:00:00 2001 From: Kamil Jarosz Date: Sat, 4 May 2024 18:59:01 +0200 Subject: [PATCH 1/3] avm2: Do not highlight Stage on focus Stage is never highlightable, even if there's a focus on it. --- core/src/display_object/stage.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/core/src/display_object/stage.rs b/core/src/display_object/stage.rs index 843197511d31..1dad2d79f785 100644 --- a/core/src/display_object/stage.rs +++ b/core/src/display_object/stage.rs @@ -922,6 +922,11 @@ impl<'gc> TInteractiveObject<'gc> for Stage<'gc> { fn mouse_cursor(self, _context: &mut UpdateContext<'_, 'gc>) -> MouseCursor { MouseCursor::Arrow } + + fn is_highlight_enabled(&self, _context: &mut UpdateContext<'_, 'gc>) -> bool { + // Highlight is always disabled for stage. + false + } } pub struct ParseEnumError; From 2a5e7b31433af4d5359ef1ecc374df247f04d328 Mon Sep 17 00:00:00 2001 From: Kamil Jarosz Date: Sat, 4 May 2024 18:59:34 +0200 Subject: [PATCH 2/3] core: Call focus handlers on every object Before this patch, focus handlers were called from on_focus_changed, only for selected objects. It seems that they should be called for every object by default. --- core/src/display_object/avm1_button.rs | 5 ++--- core/src/display_object/avm2_button.rs | 5 ++--- core/src/display_object/edit_text.rs | 5 +---- core/src/display_object/movie_clip.rs | 3 +-- core/src/focus_tracker.rs | 2 ++ 5 files changed, 8 insertions(+), 12 deletions(-) diff --git a/core/src/display_object/avm1_button.rs b/core/src/display_object/avm1_button.rs index 095ed6a5e323..858e41ff5748 100644 --- a/core/src/display_object/avm1_button.rs +++ b/core/src/display_object/avm1_button.rs @@ -610,12 +610,11 @@ impl<'gc> TInteractiveObject<'gc> for Avm1Button<'gc> { fn on_focus_changed( &self, - context: &mut UpdateContext<'_, 'gc>, + _context: &mut UpdateContext<'_, 'gc>, focused: bool, - other: Option>, + _other: Option>, ) { self.0.has_focus.set(focused); - self.call_focus_handler(context, focused, other); } fn tab_enabled_avm1(&self, context: &mut UpdateContext<'_, 'gc>) -> bool { diff --git a/core/src/display_object/avm2_button.rs b/core/src/display_object/avm2_button.rs index 07c80bcc8249..5eaa450f6fb5 100644 --- a/core/src/display_object/avm2_button.rs +++ b/core/src/display_object/avm2_button.rs @@ -826,12 +826,11 @@ impl<'gc> TInteractiveObject<'gc> for Avm2Button<'gc> { fn on_focus_changed( &self, - context: &mut UpdateContext<'_, 'gc>, + _context: &mut UpdateContext<'_, 'gc>, focused: bool, - other: Option>, + _other: Option>, ) { self.0.has_focus.set(focused); - self.call_focus_handler(context, focused, other); } fn tab_enabled_avm2_default(&self, _context: &mut UpdateContext<'_, 'gc>) -> bool { diff --git a/core/src/display_object/edit_text.rs b/core/src/display_object/edit_text.rs index 3086dfb86260..357b5b74b423 100644 --- a/core/src/display_object/edit_text.rs +++ b/core/src/display_object/edit_text.rs @@ -2457,7 +2457,7 @@ impl<'gc> TInteractiveObject<'gc> for EditText<'gc> { &self, context: &mut UpdateContext<'_, 'gc>, focused: bool, - other: Option>, + _other: Option>, ) { let is_action_script_3 = self.movie().is_action_script_3(); let mut text = self.0.write(context.gc_context); @@ -2465,9 +2465,6 @@ impl<'gc> TInteractiveObject<'gc> for EditText<'gc> { if !focused && !is_action_script_3 { text.selection = None; } - drop(text); - - self.call_focus_handler(context, focused, other); } fn is_highlightable(&self, _context: &mut UpdateContext<'_, 'gc>) -> bool { diff --git a/core/src/display_object/movie_clip.rs b/core/src/display_object/movie_clip.rs index 2462863720d9..f1a09815ba48 100644 --- a/core/src/display_object/movie_clip.rs +++ b/core/src/display_object/movie_clip.rs @@ -3390,10 +3390,9 @@ impl<'gc> TInteractiveObject<'gc> for MovieClip<'gc> { &self, context: &mut UpdateContext<'_, 'gc>, focused: bool, - other: Option>, + _other: Option>, ) { self.0.write(context.gc_context).has_focus = focused; - self.call_focus_handler(context, focused, other); } fn tab_enabled_avm1(&self, context: &mut UpdateContext<'_, 'gc>) -> bool { diff --git a/core/src/focus_tracker.rs b/core/src/focus_tracker.rs index ac8714ea5e51..f492d941b746 100644 --- a/core/src/focus_tracker.rs +++ b/core/src/focus_tracker.rs @@ -99,9 +99,11 @@ impl<'gc> FocusTracker<'gc> { if let Some(old) = old { old.on_focus_changed(context, false, new); + old.call_focus_handler(context, false, new); } if let Some(new) = new { new.on_focus_changed(context, true, old); + new.call_focus_handler(context, true, old); } tracing::info!("Focus is now on {:?}", new); From d8595b57a60a6f7f3302b6de85c42a857bf0e5b2 Mon Sep 17 00:00:00 2001 From: Kamil Jarosz Date: Sat, 4 May 2024 18:59:52 +0200 Subject: [PATCH 3/3] tests: Add avm2/focus_stage test This test verifies the behavior of focus and focus highlight for the stage object. --- tests/tests/swfs/avm2/focus_stage/Test.as | 26 ++++++++++++++++++ .../swfs/avm2/focus_stage/output.expected.png | Bin 0 -> 143 bytes tests/tests/swfs/avm2/focus_stage/output.txt | 1 + tests/tests/swfs/avm2/focus_stage/test.swf | Bin 0 -> 1086 bytes tests/tests/swfs/avm2/focus_stage/test.toml | 6 ++++ 5 files changed, 33 insertions(+) create mode 100644 tests/tests/swfs/avm2/focus_stage/Test.as create mode 100644 tests/tests/swfs/avm2/focus_stage/output.expected.png create mode 100644 tests/tests/swfs/avm2/focus_stage/output.txt create mode 100644 tests/tests/swfs/avm2/focus_stage/test.swf create mode 100644 tests/tests/swfs/avm2/focus_stage/test.toml diff --git a/tests/tests/swfs/avm2/focus_stage/Test.as b/tests/tests/swfs/avm2/focus_stage/Test.as new file mode 100644 index 000000000000..a85b264619a6 --- /dev/null +++ b/tests/tests/swfs/avm2/focus_stage/Test.as @@ -0,0 +1,26 @@ +package { + +import flash.display.Sprite; +import flash.text.TextField; +import flash.display.Sprite; +import flash.display.Shape; +import flash.display.MovieClip; +import flash.events.FocusEvent; + +[SWF(width="50", height="50", backgroundColor="#000000")] +public class Test extends MovieClip { + public function Test() { + super(); + + var shape = new Shape(); + shape.graphics.beginFill(0xFFFF0000); + shape.graphics.drawRect(10, 10, 30, 30); + shape.graphics.endFill(); + this.stage.addChild(shape); + this.stage.addEventListener("focusIn", function (evt:FocusEvent):void { + trace("Focus changed to stage"); + }); + this.stage.focus = this.stage; + } +} +} diff --git a/tests/tests/swfs/avm2/focus_stage/output.expected.png b/tests/tests/swfs/avm2/focus_stage/output.expected.png new file mode 100644 index 0000000000000000000000000000000000000000..9a62fe8f53a399aeb93156ecaeb05626ff633be8 GIT binary patch literal 143 zcmeAS@N?(olHy`uVBq!ia0vp^Mj*_=1|;R|J2nETFi#i9kc@k8Z*JsdP~dSrC|~%0 zYANeMC!X)GOxPPmR;p<8N@WUhfWQgg&m|wO{?uR1%7g`csury;699n;b`y9FXE7%y T+Q%LN+Q8uH>gTe~DWM4fw3j2z literal 0 HcmV?d00001 diff --git a/tests/tests/swfs/avm2/focus_stage/output.txt b/tests/tests/swfs/avm2/focus_stage/output.txt new file mode 100644 index 000000000000..2df7f1f24a38 --- /dev/null +++ b/tests/tests/swfs/avm2/focus_stage/output.txt @@ -0,0 +1 @@ +Focus changed to stage diff --git a/tests/tests/swfs/avm2/focus_stage/test.swf b/tests/tests/swfs/avm2/focus_stage/test.swf new file mode 100644 index 0000000000000000000000000000000000000000..41b854e916d3acc3a2c0c488df33212b58f7e536 GIT binary patch literal 1086 zcmV-E1i|}5S5qmG1^@tf0fkh}bK67|-_?g@`P;GMByQTe#1LF!OL0P(xT$F-#+@*f zFfmLDGak=cT3I5BB&4;S92gk>0sbUT9Ju+yog3WZ&TxlaDIaw?AX_{8-uwOD*Y49R z@I8Qk1F#A~C%*;&_@VG81YqCSjn+x0TeouEafXPYJ=UQ1D?(`jS6({TNfvc0#r zr>IS(*{oAUJ-BoTx~MzB#%4Qo(7}P`TOP4or@|bfp*tqeHaD-m>e{VSZ|vKlOI=g2 zjnA<|0%g0gO&#f4%W(a3MB2#nY)eDTopMnROjkRbq6w}WHVVvr@cs8@g|P(yz$Vs0u%c;aeA&nrpTuO-La#G znTEtWAfstMM#TMJ(hZDJY~+l_XoTC?8GO|Xecr0V3J}5Vm*}#xyH#nb&D|(nrrcLp z=ifMqYYjczHpt}0Yo8z2zc}diPLEGIV3wsfVBzWH{^Iw+AxD+pBzU^U=qu#Te%qn9 z1c0yA?>axz-LHu+aX`Q?#rFgNm?ac*ph35c3;y`$>YyovS{_eGTA_#e^eK}YC=iK{ zG+gSs+Bm3aCao3g72;L`LQ57VuBE5KGj8AsyBLWO_zBy`n1`w=_DtmAbOh3^z_Zb1 zeB>j~w6q{hjYg^N>^{0aU8K81+|b-}<)F8tG*$J9G8|hrv7D6!AFY?}#KMQRGE*%ET!T!TV(2+wht(I6590Bhw+83OxN4BW!R#-8!BSJ5= zFAwp^a=Mmn$8{e~PiRmHJ33Q{VdvsV*AGq0)+K{=_Q=UmMd;)+Dx|4&J!1^aC$Vo}%l-f35yS~@Yg57n57t&vHxL!_OJd^R8Lh8jNWgTcrh5O<)_ff?x7upEoc|G>ny$9rzT@2DTG+<@M;H=i_fA}n#Gcqt`j zR=9X}6_#N+SI(E0%7t>Vyv(H`C&r|>oJgk9nQTeoM2V9mUY3NUoQ84<$}3P_g%Y^^LNJr%%z4#p9H~IG;e^9G! z)nP+XVPhL+vT{5e3dqAu2Lhfl1OTC&;AiR!IzAkiOct*o4~nma`Enm_#kvsI<|S(5 zL@t@0Qgv#ko<9Cvy@Cmlnx|(+V4lUWFMKM1pU&YthoKD(QGwkUCFUcknxMZ2)dyWk zsLhumT{jMD^TN!Knb=KGaFGgI_nyOUlB>};D^#R^l$x);05HvFo9Ae*AJ0^3O=8f` z89B9|H}YzK$yieR1*4$$i$+oHFB{8hKWk*e