text-input: re-sync on enter and flag secure fields as Password
LTK drives the on-screen keyboard through zwp_text_input_v3: focusing a text widget enables text-input so the compositor's input-method (squeekboard) brings the keyboard up. Two gaps are fixed here. Handle the `enter` event by re-emitting enable + content type + commit. The compositor sends `enter` when it (re)focuses the text input — notably when an input-method connects after the field has already enabled text-input (a startup race). LTK previously ignored `enter`, so that activation was lost and the keyboard never appeared; it now re-declares its state and the OSK comes up. Declare the content type from the field's `secure` flag: secure fields are flagged `ContentPurpose::Password` with `ContentHint::SensitiveData | HiddenText` (so the IME/OSK skips prediction, autocorrect and storing the value), everything else stays `Normal`/`None`. The content type is also refreshed when focus moves between two text fields (e.g. username → password) without re-creating the text-input object, and a new `AppData::text_input_secure` lets the `enter` re-emit path preserve the current field's type. Correct the docs: `TextEdit::secure()` and SECURITY.md claimed secure "skips text-input-v3 registration". It does not — the field still activates text-input so the OSK works on it; the protection is the Password / sensitive flagging, and the value still reaches a trusted compositor/IME.
This commit is contained in:
@@ -84,6 +84,7 @@ impl<A: App> AppData<A>
|
||||
{
|
||||
let was_text_input;
|
||||
let is_text_input;
|
||||
let secure;
|
||||
{
|
||||
let ss = self.surface_mut( focus );
|
||||
|
||||
@@ -91,6 +92,10 @@ impl<A: App> AppData<A>
|
||||
.and_then( |i| find_handlers( &ss.widget_rects, i ) )
|
||||
.map( |h| h.is_text_input() )
|
||||
.unwrap_or( false );
|
||||
secure = idx
|
||||
.and_then( |i| find_handlers( &ss.widget_rects, i ) )
|
||||
.map( |h| matches!( h, WidgetHandlers::TextEdit { secure: true, .. } ) )
|
||||
.unwrap_or( false );
|
||||
was_text_input = ss.focused_idx
|
||||
.and_then( |i| find_handlers( &ss.widget_rects, i ) )
|
||||
.map( |h| h.is_text_input() )
|
||||
@@ -141,17 +146,24 @@ impl<A: App> AppData<A>
|
||||
}
|
||||
}
|
||||
|
||||
eprintln!( "ltk: set_focus idx={:?} is_text_input={} was_text_input={}", idx, is_text_input, was_text_input );
|
||||
if was_text_input && !is_text_input
|
||||
{
|
||||
self.deactivate_text_input();
|
||||
self.app.on_text_input_focused( false );
|
||||
self.dirty_caches();
|
||||
}
|
||||
if is_text_input && !was_text_input
|
||||
else if is_text_input && !was_text_input
|
||||
{
|
||||
self.activate_text_input( qh );
|
||||
self.activate_text_input( qh, secure );
|
||||
self.app.on_text_input_focused( true );
|
||||
self.dirty_caches();
|
||||
}
|
||||
else if is_text_input
|
||||
{
|
||||
// Focus moved between text fields: refresh the content type so a
|
||||
// password field is flagged even without re-activating.
|
||||
self.activate_text_input( qh, secure );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user