avm1: Fix some issues with `Selection.getFocus()` and `setFocus()`
This commit is contained in:
parent
7a6e6cf214
commit
5e165a0682
|
@ -2,7 +2,7 @@ use crate::avm1::activation::Activation;
|
|||
use crate::avm1::error::Error;
|
||||
use crate::avm1::globals::as_broadcaster::BroadcasterFunctions;
|
||||
use crate::avm1::property_decl::{define_properties_on, Declaration};
|
||||
use crate::avm1::{Object, ScriptObject, TObject, Value};
|
||||
use crate::avm1::{Object, ScriptObject, Value};
|
||||
use crate::display_object::{EditText, TDisplayObject, TextSelection};
|
||||
use gc_arena::MutationContext;
|
||||
|
||||
|
@ -108,10 +108,14 @@ pub fn get_focus<'gc>(
|
|||
_args: &[Value<'gc>],
|
||||
) -> Result<Value<'gc>, Error<'gc>> {
|
||||
let focus = activation.context.focus_tracker.get();
|
||||
match focus {
|
||||
Some(focus) => Ok(focus.object()),
|
||||
None => Ok(Value::Null),
|
||||
}
|
||||
Ok(match focus {
|
||||
Some(focus) => focus
|
||||
.object()
|
||||
.coerce_to_string(activation)
|
||||
.unwrap_or_default()
|
||||
.into(),
|
||||
None => Value::Null,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn set_focus<'gc>(
|
||||
|
@ -121,37 +125,22 @@ pub fn set_focus<'gc>(
|
|||
) -> Result<Value<'gc>, Error<'gc>> {
|
||||
let tracker = activation.context.focus_tracker;
|
||||
match args.get(0) {
|
||||
None => Ok(false.into()),
|
||||
Some(Value::Undefined | Value::Null) => {
|
||||
tracker.set(None, &mut activation.context);
|
||||
Ok(true.into())
|
||||
}
|
||||
Some(Value::Object(obj)) => {
|
||||
if let Some(display_object) = obj.as_display_object() {
|
||||
Some(focus) => {
|
||||
let start_clip = activation.target_clip_or_root();
|
||||
let object = activation.resolve_target_display_object(start_clip, *focus, false)?;
|
||||
if let Some(display_object) = object {
|
||||
if display_object.is_focusable() {
|
||||
tracker.set(Some(display_object), &mut activation.context);
|
||||
tracker.set(object, &mut activation.context);
|
||||
return Ok(true.into());
|
||||
}
|
||||
// [NA] Note: The documentation says true is success and false is failure,
|
||||
// but from testing this seems to be opposite.
|
||||
Ok(false.into())
|
||||
} else {
|
||||
Ok(true.into())
|
||||
}
|
||||
Ok(false.into())
|
||||
}
|
||||
Some(Value::MovieClip(_)) => {
|
||||
let obj = args.get(0).unwrap().coerce_to_object(activation);
|
||||
|
||||
if let Some(display_object) = obj.as_display_object() {
|
||||
if display_object.is_focusable() {
|
||||
tracker.set(Some(display_object), &mut activation.context);
|
||||
}
|
||||
// [NA] Note: The documentation says true is success and false is failure,
|
||||
// but from testing this seems to be opposite.
|
||||
Ok(false.into())
|
||||
} else {
|
||||
Ok(true.into())
|
||||
}
|
||||
}
|
||||
_ => Ok(false.into()),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
use crate::avm1::Avm1;
|
||||
use crate::avm1::Value;
|
||||
use crate::context::UpdateContext;
|
||||
pub use crate::display_object::{DisplayObject, TDisplayObject, TDisplayObjectContainer};
|
||||
pub use crate::display_object::{
|
||||
DisplayObject, TDisplayObject, TDisplayObjectContainer, TextSelection,
|
||||
};
|
||||
use gc_arena::{Collect, GcCell, MutationContext};
|
||||
|
||||
#[derive(Clone, Copy, Collect)]
|
||||
|
@ -22,44 +24,49 @@ impl<'gc> FocusTracker<'gc> {
|
|||
focused_element: Option<DisplayObject<'gc>>,
|
||||
context: &mut UpdateContext<'_, 'gc>,
|
||||
) {
|
||||
if let Some(text_field) = focused_element.and_then(|e| e.as_edit_text()) {
|
||||
if text_field.is_editable() {
|
||||
context.ui.open_virtual_keyboard();
|
||||
}
|
||||
}
|
||||
let old = std::mem::replace(&mut *self.0.write(context.gc_context), focused_element);
|
||||
|
||||
if old.is_none() && focused_element.is_none() {
|
||||
// We didn't have anything, we still don't, no change.
|
||||
return;
|
||||
}
|
||||
if old.is_some() == focused_element.is_some()
|
||||
&& old.unwrap().as_ptr() == focused_element.unwrap().as_ptr()
|
||||
if !(old.is_some() == focused_element.is_some()
|
||||
&& old.unwrap().as_ptr() == focused_element.unwrap().as_ptr())
|
||||
{
|
||||
// We're setting it to the same object as before, no change.
|
||||
return;
|
||||
if let Some(old) = old {
|
||||
old.on_focus_changed(context.gc_context, false);
|
||||
}
|
||||
if let Some(new) = focused_element {
|
||||
new.on_focus_changed(context.gc_context, true);
|
||||
}
|
||||
|
||||
tracing::info!("Focus is now on {:?}", focused_element);
|
||||
|
||||
if let Some(level0) = context.stage.root_clip() {
|
||||
Avm1::notify_system_listeners(
|
||||
level0,
|
||||
context,
|
||||
"Selection".into(),
|
||||
"onSetFocus".into(),
|
||||
&[
|
||||
old.map(|v| v.object()).unwrap_or(Value::Null),
|
||||
focused_element.map(|v| v.object()).unwrap_or(Value::Null),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(old) = old {
|
||||
old.on_focus_changed(context.gc_context, false);
|
||||
}
|
||||
if let Some(new) = focused_element {
|
||||
new.on_focus_changed(context.gc_context, true);
|
||||
}
|
||||
// This applies even if the focused element hasn't changed.
|
||||
if let Some(text_field) = focused_element.and_then(|e| e.as_edit_text()) {
|
||||
if text_field.is_editable() {
|
||||
let length = text_field.text_length();
|
||||
text_field.set_selection(
|
||||
Some(TextSelection::for_range(0, length)),
|
||||
context.gc_context,
|
||||
);
|
||||
|
||||
tracing::info!("Focus is now on {:?}", focused_element);
|
||||
|
||||
if let Some(level0) = context.stage.root_clip() {
|
||||
Avm1::notify_system_listeners(
|
||||
level0,
|
||||
context,
|
||||
"Selection".into(),
|
||||
"onSetFocus".into(),
|
||||
&[
|
||||
old.map(|v| v.object()).unwrap_or(Value::Null),
|
||||
focused_element.map(|v| v.object()).unwrap_or(Value::Null),
|
||||
],
|
||||
);
|
||||
context.ui.open_virtual_keyboard();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -26,7 +26,7 @@ _level0.a
|
|||
|
||||
|
||||
|
||||
false
|
||||
true
|
||||
|
||||
// Selection.setFocus(b)
|
||||
! - onSetFocus
|
||||
|
@ -50,7 +50,7 @@ _level0.b
|
|||
|
||||
|
||||
|
||||
false
|
||||
true
|
||||
|
||||
// Selection.setSelection(0)
|
||||
undefined
|
||||
|
@ -133,7 +133,7 @@ _level0.b
|
|||
|
||||
|
||||
// Selection.setFocus(b)
|
||||
false
|
||||
true
|
||||
|
||||
// b.focusEnabled = false;
|
||||
// Selection.getBeginIndex()
|
||||
|
@ -195,7 +195,7 @@ _level0.c
|
|||
|
||||
|
||||
|
||||
false
|
||||
true
|
||||
|
||||
// Selection.setFocus(d)
|
||||
false
|
||||
|
@ -246,7 +246,7 @@ _level0.button
|
|||
|
||||
|
||||
|
||||
false
|
||||
true
|
||||
|
||||
// Selection.setFocus(text_input
|
||||
! - onSetFocus
|
||||
|
@ -270,7 +270,7 @@ _level0.text_input
|
|||
|
||||
|
||||
|
||||
false
|
||||
true
|
||||
|
||||
// Selection.setFocus(text_selectable)
|
||||
! - onSetFocus
|
||||
|
@ -294,7 +294,7 @@ _level0.text_selectable
|
|||
|
||||
|
||||
|
||||
false
|
||||
true
|
||||
|
||||
// Selection.setSelection(0)
|
||||
undefined
|
||||
|
@ -414,7 +414,7 @@ _level0.text_non_selectable
|
|||
|
||||
|
||||
|
||||
false
|
||||
true
|
||||
|
||||
// Selection.setFocus(text_input)
|
||||
! - onSetFocus
|
||||
|
@ -438,7 +438,7 @@ _level0.text_input
|
|||
|
||||
|
||||
|
||||
false
|
||||
true
|
||||
|
||||
// Selection.setSelection(1, 3)
|
||||
// text_input.text
|
||||
|
|
Loading…
Reference in New Issue