Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

キーバインドで必須と任意の修飾キーを設定できるようにし、Option + Enterを .enterとして扱うようにする #173

Merged
merged 6 commits into from
Jun 16, 2024

Conversation

mtgto
Copy link
Owner

@mtgto mtgto commented Jun 12, 2024

#172 で問題となった、Option + Enterがv0.23.0からIMEで拾われるようになってしまったことへの対処として、KeyBinding.Inputに「必須の修飾キーの集合」と「押していてもよい任意の修飾キーの集合」を設定するようにします。

2024-06-15: 既存のキーバインドは、矢印キーはShiftあり、エンターはOptionありとしていますがマージする前にもう少し考えます。

Copy link
Contributor

@y-yu y-yu left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ちょっとアドホックな気もしますが、とはいえIntelliJが不便な状況になっちゃてるので直るならマージでよさそう 🙆‍♀️

macSKK/KeyBindingSet.swift Show resolved Hide resolved
if keyBind.0.key == input.key {
switch input.key {
case .character(let c):
if KeyBinding.Key.characters.contains(c) && keyBind.0.modifierFlags == input.modifierFlags {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

KeyBinding.Key.characters.contains(c)はこれinput.keyのコンストラクト時 👇 にもチェックしています。

init(event: NSEvent) {
if let character = event.charactersIgnoringModifiers?.lowercased().first, Key.characters.contains(character) {
key = .character(character)

よって.characterのケースに進入した以上はもうこのチェックは不要ということで

Suggested change
if KeyBinding.Key.characters.contains(c) && keyBind.0.modifierFlags == input.modifierFlags {
keyBind.0.modifierFlags == input.modifierFlags {

☝️ こうしても大丈夫なような 🤔

return keyBind.1
}
case .code(let code):
if input.modifierFlags.contains(keyBind.0.modifierFlags) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ほほー、input.key側が.codeかどうかによってmodifierFlagsを完全一致にするかcontainsにするかどうか的なロジックですか 👀
これは 👇 こういうちゃんとした(?)modifierFlagsの取り扱いをするまでの一旦の凌ぎみたいな感じということかな 🤔

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

直感でいけるかな? とおおまかに分けたんですが、さすがに自信がないので見直します。
このPR内でv0.22.xまでのKeyBinding入力前と同じような挙動になるように修正しようかなと思っています。

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

「ちゃんとしたmodifierFlagsの取り扱い」をするのもそう大変ではなかったので、大きく舵切ってこのPRでやることにしました。 f9f259d
将来ユーザーがキーバインドをカスタマイズするときには必須modifierFlagsにユーザーが入力したもの、optionalFlagsはデフォルトは空でユーザーがカスタマイズ可能にするつもりです (EnterをOption押しててもありにする、みたいなカスタマイズ)。

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

自分もこれ実は裏でやろうとしてたんですが、なかなかoptionalFlagsをどう持つかとかがあまりうまくいかず、いったんOption + Enterだけ局所的にどうにかする方向でいいか 🤔 と思ってましたが、全体的にこのPRでやってよくなっていると思います 👍

@mtgto mtgto changed the title Option + Enterを .enterとして扱う キーバインドで必須と任意の修飾キーを設定できるようにし、Option + Enterを .enterとして扱うようにする Jun 15, 2024
Copy link
Contributor

@y-yu y-yu left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

些細な指摘もしたけどトータルでよさそう! 👍

case .code:
hasher.combine(modifierFlags.subtracting(.shift).rawValue)
}
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(メモ)
この.shiftを特別扱いするhashを消すの、個人的にはすごく賛成です 👍
ディクショナリーのキーなどに暗黙的に用いられるであろう関数において.shiftに関する特別処理が記述されているというのは後々なにか問題の種になる可能性があると思ったので、optionalModifierFlags導入とKeyBindingSet.dict廃止によりこのhashが消えることは将来にわたってとてもいい判断になると確信しています。

} else {
return lhs.key == rhs.key && lhs.modifierFlags == rhs.modifierFlags
}
return lhs.key == rhs.key && lhs.modifierFlags == rhs.modifierFlags && lhs.optionalModifierFlags == rhs.optionalModifierFlags
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(メモ)
同様にこの==.shiftに関する特別処理が消えて相当自明になったと思うのでこの実装を支持します 👍

Comment on lines +159 to +165
if let character = event.charactersIgnoringModifiers?.lowercased().first, Key.characters.contains(character) {
if key != .character(character) {
return false
}
} else if key != .code(event.keyCode) {
return false
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

めちゃくちゃ微粒子レベルの指摘にはなりますが、else ifでやっている比較のほうがなんか単純な比較だけなので、先にそっちをやったほうが、そっちでもうreturn falseとなったら Key.characters.containsをやらなくてよくなって超微妙に効率がよかったりますかね?

Suggested change
if let character = event.charactersIgnoringModifiers?.lowercased().first, Key.characters.contains(character) {
if key != .character(character) {
return false
}
} else if key != .code(event.keyCode) {
return false
}
if key != .code(event.keyCode) {
return false
} else if let character = event.charactersIgnoringModifiers?.lowercased().first, Key.characters.contains(character) {
if key != .character(character) {
return false
}
}

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

このaccept、最大で登録されているキーバインドの回数だけ呼ばれるのでそれも含めて富豪的な書き方になってますね。
ちゃんとやるならNSEventを引数にするのを止めて、ここでやってるちょっとした前処理を初期化で済ませた別の構造体に入れておくかなあとか思います。

struct CurrentInput {
  let key: Key
  let modifierFlags: NSEvent.ModifierFlags

  init(event: NSEvent) {
     if let character = event.charactersIgnoringModifiers?.lowercased().first, Key.characters.contains(character) {
       self.key = .character(character)
     }
     ...
  }
}

みたいな。

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

なるほど、そうですね 👍
もともとはNSEventからKeyBinding.Inputをインスタンシーエションしていて、KeyBindingに用いるInputというデータ構造と入力のmodifierFlagsやキーコードなどを整理しておくデータ構造は別であったほうがいいと思ってました。
今回のPRの変更では、やや副作用かもしれませんがKeyBinding.InputNSEventからインスタンシーエションされるパスが消滅しKeyBinding.Inputが真にKeyBinding用のデータ構造になったと思います。いったんこのPRの段階では今の状態でも十分とは思いますが、将来的にはCurrentInputのようなデータ構造がKeyBinding.Inputとは別に定義されるのはとてもいいと思いました 👍

} else if key != .code(event.keyCode) {
return false
}
return modifierFlags.isSubset(of: event.modifierFlags) && modifierFlags.union(optionalModifierFlags).isSuperset(of: event.modifierFlags)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

なるほど、たしかにisSubsetisSupersetでこう表現できるのか。(メモ)

Copy link
Contributor

@y-yu y-yu left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

よさそう。

@mtgto mtgto merged commit 5c29a36 into main Jun 16, 2024
2 checks passed
@mtgto mtgto deleted the option-enter branch June 16, 2024 02:42
@mtgto
Copy link
Owner Author

mtgto commented Jun 16, 2024

レビューありがとうございました。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants