🖥️

【AppKit】NSSecureTextFieldのAuto Fillの挙動とバグ

2021/07/12に公開

概要

Projectでパスワード等セキュアな入力に使うNSSecureTextFieldを使った際、動きに翻弄されたので、調査し判明したことを内容として記載する

Auto Fillの表示条件

NSSecureTextFieldは、特定の配置において、パスワードのAuto Fillのpopupが表示され使える挙動をする。以下の画像が、正常な時の表示。

正常

⭕️ 正常縦並び ⭕️ 正常横並び
正常縦 正常横

画像のように、EditableなNSTextFieldの次にNSSecureTextFieldを配置することで、Auto Fillのpopupが表示されるように仕組まれている。

不適合

❌ NSSecureTextFiledを連続配置 ❌ NSSecureTextFiled単体配置
NSSecureTextFiledを連続配 NSSecureTextFiled単体配置
❌ NSSecureTextFiled後にNSTextField(縦) ❌ NSSecureTextFiled後にNSTextField(横)
NSSecureTextFiled後にNSTextField(縦) NSSecureTextFiled後にNSTextField(横)
❌ EditableでないNSTextFiled後に配置1 ❌ EditableでないNSTextFiled後に配置2
EditableでないNSTextFiled後に配置1 EditableでないNSTextFiled後に配置2

isFlippedによるAuto Fillのバグ

Macの座標は、左下が原点となっているため、人によっては扱いづらく、isFlipped = trueにして左上を原点としている人も少なからずいる。
ただその際、Macの各種Objectが正しく動くとは限らず、NSSecureTextFieldのAuto Fillのpopupもこれに該当する。

isFlipped = trueにしているviewの上に配置されたNSSecureTextFieldのAuto Fillのpopupは、以下の画像のようにNSSecureTextFieldと重なった状態で表示される。

isFlipped=true

回避策としては、NSSecureTextFiledをラップしたviewを作って配置してやるか、その画面だけStoryboardやXIBを使ったGUIで画面を作るのが無難なとこだろうか。

WrapSecureTextField
class WrapSecureTextField: NSView {

    override var isFlipped: Bool { false }

    var placeholderString: String? {
        get { textField.placeholderString }
        set { textField.placeholderString = newValue }
    }

    var stringValue: String {
        get { textField.stringValue }
        set { textField.stringValue = newValue }
    }

    private var textField: NSSecureTextField

    init(string: String) {
        textField = .init(string: string)
        super.init(frame: .zero)

        addSubview(textField)
    }

    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

    override func layout() {
        super.layout()

        textField.frame = bounds
    }
}

Discussion