![[chappy-log.webp|cover-picture]]
## Window Hints 方向移動の候補選択改善
上下左右の方向移動で、「見た目上その方向にあるウィンドウ」をより自然に選べるようにするため、候補判定とスコアリングを改善しました。
今回のポイントは以下です。
- 候補ウィンドウの方向側エッジが、現在ウィンドウの方向側エッジを越えている場合だけ上下左右の候補にする
- 主軸の重なりが小さい候補は「移動方向へ離れた候補」として扱い、副軸の重なり不足では除外しない
- 主軸の重なりが大きい候補は、副軸の重なり率が一定以上ある場合だけ候補にする
- サンプリング上の可視率が高い候補を、かなり隠れている近傍候補より優先する
- 大きな背面候補の内側に前面候補がある場合、内包された前面候補を優先する
```lua
navigation = {
direction = {
scoring = {
preferredVisibleRatio = 0.4,
maxPrimaryOverlapRatioForDetached = 0.2,
minOrthogonalOverlapRatio = 0.5,
cardinalOverlapTieThresholdPx = 720,
},
},
}
```
### preferredVisibleRatio
preferredVisibleRatio = 0.4
上下左右の移動で、サンプリング上の可視率がこの値以上の候補を、より隠れている候補より優先します。
この可視率は、単純なウィンドウ全体の可視率ではなく、現在ウィンドウから見て移動方向側にあるサンプル点だけを対象にします。たとえば right なら、現在ウィンドウの右端より右側にあるサンプル点だけを見ます。
A から right
```
+-----+ +------+
| A | ---> | R | よく見えている
+-----+ +------+
+-------------+
| C | かなり隠れている
+-------------+
```
この場合、R の可視率が 0.6 以上なら、C より R を優先します。
すべての候補が 0.6 未満の場合でも、候補から完全除外はせず、その中でより見えている候補を選びます。
0 にすると、この可視率優先を無効化できます。
可視率がしきい値以上の候補同士では、従来どおり副軸の重なり量、主軸距離、前面順などのスコアで比較します。
### maxPrimaryOverlapRatioForDetached
maxPrimaryOverlapRatioForDetached = 0.2
移動方向の主軸で、現在ウィンドウと候補ウィンドウがどれくらい重なっているかを判定します。
right/left では X 方向、up/down では Y 方向が主軸です。
C から right
```
+--------------------+
| A |
+--------------------+ +------+
+----------+ | R |
| C | -------------------> +------+
+----------+
```
R は C と X 方向にほとんど重なっていないため、「右に離れた候補」として扱います。
この主軸重なり率が 0.2 以下なら、副軸の重なりが小さくても候補に残ります。
### minOrthogonalOverlapRatio
minOrthogonalOverlapRatio = 0.5
主軸で大きく重なっている候補に対して、移動方向と垂直な軸の重なり率を要求します。
right/left では Y 方向、up/down では X 方向が副軸です。
C から right
```
+--------------------+
| A |
+--------------------+
+----------+
| C |
+----------+
```
A は C の右端を越えていても、X 方向には大きく重なっています。
この場合は「右に離れた候補」ではなく「上/背面寄りの候補」とみなし、Y 方向の重なり率が 0.5 以上ないと候補から除外します。
### 方向側エッジ判定
上下左右の候補は、候補ウィンドウの方向側エッジが現在ウィンドウの方向側エッジを越えている必要があります。
right なら、候補の右端が現在ウィンドウの右端より右にある場合だけ候補にします。
```
+----------------------+
| C |
| +----------+ | 中心が少し右でも、右端が C の右端を越えない
| | A | | => right 候補にしない
| +----------+ |
+----------------------+
```
これにより、現在ウィンドウより小さい背面・前面ウィンドウの中心が少しズレているだけで、上下左右の移動先になってしまうケースを避けます。
### 内包された前面候補の優先
移動方向に大きな背面候補があり、その中に小さな前面候補がある場合は、小さな前面候補を優先します。
C から right
```
+------+
| C | ----------->
+------+
+--------------------+
| B | 大きな背面候補
| +----------+ |
| | F | | 内包された前面候補
| +----------+ |
+--------------------+
```
この場合、F が B に内包されていると判定できるなら F を優先します。数 px 程度のはみ出しは許容します。
### まとめ
right/left:
1. 候補の方向側エッジが、現在ウィンドウの方向側エッジを越えている必要がある
2. X方向の重なり率が 0.2 以下なら「離れた候補」として残す
3. X方向の重なり率が 0.2 を超えるなら、Y方向の重なり率が 0.5 以上必要
4. 候補同士では、内包された前面候補を優先
5. 可視率 0.6 以上の候補を、大きく隠れた候補より優先
6. 可視率で決まらなければ、副軸重なり量、主軸距離、前面順、副軸ずれ、直前アクティブウィンドウ、ウィンドウIDの順で決める
up/down:
X と Y を入れ替えて同じルール
斜め方向は今回の主な対象外で、従来どおり2軸のエッジ距離合計、前面順、中心距離、直前アクティブウィンドウの順で決定します。
この変更により、少し中心がズレているだけの背面ウィンドウへ移動してしまうケースを避けつつ、実際に右・左・上・下へ離れているウィンドウや、背面候補の内側に見えている前面ウィンドウへ自然に移動できます。