KaleidoscopeのQukeysプラグインの設定

## まとめ

Qukeysの設定は少々ハードルが高いですが、とても柔軟に設定できます。

個人的には、

```
Qukeys.setMaxIntervalForTapRepeat(0);
```

を設定することで、誤発動がグッと減りました。

## はじめに

[Keyboardio](https://shop.keyboard.io) は、とてもユニークなキーボードをつくっています。かれらの [Atreus](https://shop.keyboard.io/products/keyboardio-atreus)は超コンパクトな44キーのキーボード。

![e621c03fa31981a655060e363e02de16_original.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/184128/e225926b-5d4a-1a7b-3ade-15caf6e6d019.jpeg)


[Kalaidoscope](https://github.com/keyboardio/Kaleidoscope) を用いると、とても柔軟にカスタマイズできる、ということを、[Keyboardio Kaleidscopeのはじめかた - Qiita](https://qiita.com/hann-solo/items/3d2486116a92b79e80e5) で書きました。

プラグイン形式でさまざまな設定ができます。なかでも便利そうなのがQukeysです。

:::note
Qukeysは、あるキーをタップしたときと、長押ししたときで動作を変える機能です。
:::

かなり便利なのですが、カスタマイズしようとするとなんだかムズい。のでした。

ドキュメントの原文が（わたしにはわりと）難しかったので、意訳気味に訳し、図を加えてみました。

### 想定読者

- Atreus、Model 100などの、Keyboardioのキーボードのユーザ
- ErgoDox EZ、OLKB Planckなど、Kaleidoscope対応キーボードのユーザ
- Qukeys機能を使いたいが、設定のパラメータがピンとこない人

### 図について

原文には図がありません。図がないとわたしはイメージが湧かなかったので、図示を試みました。

```plantuml
@startuml
<style>
root {
  Padding 20
  Margin 20
}
footer {
  FontSize 32
}
</style>
scale 0.4
center footer ▲ `A` と刻印されているキーを、プレス→ホールド→リリース（タップ） すると\n`a` が出力された、を意味する図。
title <img:https://cdn-ak.f.st-hatena.com/images/fotolife/m/masatora_bd5/20240130/20240130220408.png>
@enduml
```

:::note
- 図示にあたって、qukeyは `A` で、長押ししたときに `ctrl` にしたいとします。
- qukeyの次に押すキーは `F` とします。
:::

## 訳文（＋図）

原文はこちら：[Qukeys - Kaleidoscope  documentation](https://kaleidoscope.readthedocs.io/en/latest/plugins/Kaleidoscope-Qukeys.html)

### コンセプト

このKaleidoscopeプラグインを使うと、キーボードのキーを過負荷状態にする。タップすると1つのキーコードを出力し、押し続けると別のキーコード（多くの場合はshiftやaltなどの修飾キー）を出力する。この名前は「qubit」にかけており、qukeyは「quantum key（量子キー）」を意味する。

```plantuml
@startuml
<style>
root {
  Padding 20
  Margin 20
}
footer {
  FontSize 32
}
</style>
scale 0.4
center footer ▲ `A` を短く押すと `a` が出力される。`A` を長押しすると、`ctrl` が出力される。
title <img:https://cdn-ak.f.st-hatena.com/images/fotolife/m/masatora_bd5/20240130/20240130221855.png>
@enduml
```


キーをプレスしたとき、qukeyは未決定状態の重ね合わせにある。どの状態になるかは、次のイベントによって決まる。qukeyがこの不確定な状態にあるあいだ、qukeyのプレスと、次のキーのプレスは、qukeyの最終状態が決まるまで遅延される。

qukeyの状態（プライマリかオルタネイト）の決定要因は、多くの場合はキーリリースである。qukeyが次のキーを押す前にリリースされた場合、プライマリ値（おそらくキーに刻印されている文字）を出力する。しかし、もし次のキーが先にリリースされた場合、オルタネイト値（通常は修飾キー）を出力する。

```plantuml
@startuml
<style>
root {
  Padding 20
  Margin 20
}
footer {
  FontSize 32
}
</style>
scale 0.4
center footer ▲ `A` を先にリリースし、`F` を押すと、`af` を出力。`F` を先にリリースすると、`ctrl+f` を出力。
title <img:https://cdn-ak.f.st-hatena.com/images/fotolife/m/masatora_bd5/20240128/20240128000553.png>
@enduml
```

qukeyは、従来のキーカスタマイズ手法ではうまくできなかった、「ホーム行のキーに2つの役割をさせる」ができるよう設計してある。一部のタイピスト（修飾キーを後続キーより先にリリースするクセがついている人）は、qukeyが完全に機能しない可能性がある。しかしホーム行でqukeyを使ってよい結果を報告している人もいる。



### 設定

#### .setHoldTimeout(timeout)

キーを押し続けたとき、どれだけの時間（ミリ秒単位）経過後にqukeyがオルタネイト値を出力するかを設定。注意：これはqukeyの状態決定の主要因ではない。次のキーを押す前に、この時間を待つ必要はない。このタイムアウト時間のおもな用途は、qukeyの次に押すのがキーでないとき、オルタネイト値を出力できるようにすること（例：shift + クリック）。

デフォルトは250ミリ秒。

```plantuml
@startuml
<style>
root {
  Padding 20
  Margin 20
}
footer {
  FontSize 32
}
</style>
scale 0.4
center footer ▲ xxxミリ秒を超えると `ctrl` が発動するが……
title <img:https://cdn-ak.f.st-hatena.com/images/fotolife/m/masatora_bd5/20240128/20240128001905.png>
@enduml
```

```plantuml
@startuml
<style>
root {
  Padding 20
  Margin 20
}
footer {
  FontSize 32
}
</style>
scale 0.4
center footer ▲ 発動までxxxミリ秒待つ必要はなく、\n次のキーをタップすれば、`ctrl` が発動する。
title <img:https://cdn-ak.f.st-hatena.com/images/fotolife/m/masatora_bd5/20240128/20240128002032.png>
@enduml
```


#### .setMaxIntervalForTapRepeat(timeout)

タップリピートが効く時間（ミリ秒単位）を設定。qukeyをこの時間内に「押す→リリース→押す&押し続ける」とすると、このキーを押し続けたと扱い、プライマリ値をリピート出力し続ける。この方法でのみ、プライマリ値をリピート出力できる（キーを押し続けるとオルタネイト値を出力するため）。

```plantuml
@startuml
<style>
root {
  Padding 20
  Margin 20
}
footer {
  FontSize 32
}
</style>
scale 0.4
center footer ▲ XXXミリ秒以内に連打&ホールドで、`aaaaa...` を出力。
title <img:https://cdn-ak.f.st-hatena.com/images/fotolife/m/masatora_bd5/20240128/20240128002800.png>
@enduml
```

もしこの時間内に「押す→リリース→押す→リリース」（2回タップ）した場合、プライマリ値のダブルタップを出力する。


```plantuml
@startuml
<style>
root {
  Padding 20
  Margin 20
}
footer {
  FontSize 32
}
</style>
scale 0.4
center footer ▲ XXXミリ秒以内に連打&リリースなら、`aa` を出力。
title <img:https://cdn-ak.f.st-hatena.com/images/fotolife/m/masatora_bd5/20240128/20240128002841.png>
@enduml
```

タップリピートをオフにするには、値を0にする。最大値は255。250以上に設定すると、Qukeysプラグインがタップリピートかダブルタップか判断する前に、ホストでキーリピートが発生する可能性があるため（ほとんどのシステムでキーリピートの遅延が500ミリ秒）。

デフォルトは200ミリ秒。


#### .setOverlapThreshold(percentage)

qukeyから次のキーへロールオーバー（qukeyを先にリリース）することを許容するためのもの。先にキーをリリースしても、qukeyのオルタネイト値を出力するためのしきい値を設定する。

パラメータは1から100（75は75％）。後続キーのプレス時間のうち、qukeyのプレスと重なるパーセントのこと。qukeyのリリース直後に後続キーをリリースすれば、重なりパーセントは大きくなり、qukeyはオルタネイト値（おそらく修飾キー）を出力する。逆に、qukeyのリリース後も後続キーを長くプレスする場合、qukeyはプライマリ値（キー刻印値）を出力する。



```plantuml
@startuml
<style>
root {
  Padding 20
  Margin 20
}
footer {
  FontSize 32
}
</style>
scale 0.4
center footer ▲ `A` のすぐあとに `F` をリリースすると、`ctrl+f` を出力する。
title <img:https://cdn-ak.f.st-hatena.com/images/fotolife/m/masatora_bd5/20240128/20240128004543.png>
@enduml
```


```plantuml
@startuml
<style>
root {
  Padding 20
  Margin 20
}
footer {
  FontSize 32
}
</style>
scale 0.4
center footer ▲ `A` のリリースから時間が経って `F` をリリースすると、\n`af` を出力する。
title <img:https://cdn-ak.f.st-hatena.com/images/fotolife/m/masatora_bd5/20240128/20240128004550.png>
@enduml
```

100％に設定すると、猶予期間はオフになる。2つのキーを同時にリリースすると、プライマリかオルタネイト、どちらの値も確実に得ることができない。オルタネイト値を出力するには「後続キーのリリース→qukeyのリリース」の順にする必要がある。

パーセントを低い値（例：30）に設定すると、猶予期間は長くなる。オルタネイト値がほしいのにプライマリ値が出力される場合、しきい値（%）を減らすとよい。逆に、プライマリ値がほしいのにオルタネイト値が出力される場合、しきい値（%）を増やすとよい。両方のケースが発生しているなら、タイピング習慣を変えること。

デフォルトは80％。


#### .setMinimumHoldTime(min_hold_time)

qukeyがオルタネイト値を出力する前にプレスし続けるべき最小時間（ミリ秒単位）を設定。ホーム行のqukeyを利用していて、上記のOverlapThresholdを100％にしてもなお意図しないオルタネイト値を出力してしまう場合に使用。ただし、この設定をすると、Qukeysで修飾キーを出力するとき、タイピングを遅くする必要がある可能性あり。

デフォルトは50ミリ秒。


#### .setMinimumPriorInterval(min_interval)

qukeyの先行キーのプレスと、qukeyのプレスのあいだに経過する必要がある最小時間（ミリ秒単位）を設定。これは、速くタイピングする際に意図しないオルタネイト値の出力を防ぐための別の対策。

デフォルトは75ミリ秒。

### おわりに

Kaleidoscopeの強力なカスタマイズ機能、Qukeysについて調べました。快適なタイピング体験のお役に立てますように。

### 参考

#### inoファイル

ご参考までわたしのinoファイル： [Atreus.ino · GitHub](https://gist.github.com/hnsol/edaf16fe5d4d679d980561923e048cad)


#### 原文

原文が変わるかもしれないので念のため。


Concept

This Kaleidoscope plugin allows you to overload keys on your keyboard so that they produce one keycode (i.e. symbol) when tapped, and a different keycode – most likely a modifier (e.g. shift or alt) – when held. The name is a play on the term qubit; a qukey is a “quantum key”. When it is first pressed it is in a superposition of states until some event determines which state it ends up in. While a qukey is in this indeterminate state, its key press event and any subsequent key presses are delayed until something determines the qukey’s ultimate state.

Most likely, what determines the qukey’s state (primary or alternate) is the release of a key; if the qukey is released before a subsequent key, it will take on its primary value (most likely a printable character), but if the subsequent key is released first, it will take on its alternate value (usually a modifier).

Qukeys is designed to make it practical to use these overloaded keys on the home row, where similar designs have historically been problematic. For some typists (particularly those who are accustomed to rolling over from modifiers to modified keys, rather than deliberately holding the modifier until the subsequent key has been released), this may still not work perfectly with Qukeys, but some people have reported good results with home-row qukeys.



Configuration

.setHoldTimeout(timeout)

Sets the time (in milliseconds) after which a qukey held on its own will take on its alternate state. Note: this is not the primary determining factor for a qukey’s state. It is not necessary to wait this long before pressing a key that should be modified by the qukey’s alternate value. The primary function of this timeout is so that a qukey can be used as a modifier for an separate pointing device (i.e. shift + click).

Defaults to 250.

.setMaxIntervalForTapRepeat(timeout)

Sets the time (in milliseconds) that limits the tap-repeat window. If the same qukey is pressed, released, and pressed again within this timeframe, then held, Qukeys will turn it into a single press and hold event, using the primary key value (which cannot otherwise be held). If the second press is also a tap, and the two release events occur within the same timeframe, it will instead be treated as a double tap (of the primary key value).

To effectively shut off the tap-repeat feature, set this value to 0. The maximum value is 255; anything higher than 250 could result in key repeat being triggered on the host before Qukeys determines whether it’s a tap-repeat or a double-tap sequence, because most systems delay the key repeat by 500 ms.

Defaults to 200.

.setOverlapThreshold(percentage)

This sets a variable that allows the user to roll over from a qukey to a subsequent key (i.e. the qukey is released first), and still get the qukey’s alternate (modifier) state.

The percentage parameter should be between 1 and 100 (75 means 75%), and represents the fraction of the subsequent key press’s duration that overlaps with the qukey’s press. If the subsequent key is released soon enough after the qukey is released, the percentage overlap will be high, and the qukey will take on its alternate (modifier) value. If, on the other hand, the subsequent key is held longer after the qukey is released, the qukey will take on its primary (non-modifier) value.

Setting percentage to 100% turns off the grace period, so you can’t reliably get either output if you release the two keys simultaneously. That means the subsequent key must be released before the qukey for the release-order condition to trigger making the qukey take on its alternate state.

Setting percentage to a low value (e.g. 30) will result in a longer grace period. If you’re getting primary values when you intended modifiers, try decreasing this setting. If, on the other hand, you start getting modifiers when you intend primary values, try increasing this setting. If you’re getting both, the only solution is to change your typing habits, unfortunately.

Defaults to 80.

.setMinimumHoldTime(min_hold_time)

Sets the minimum amount of time (in milliseconds) a qukey must be held before it is allowed to resolve to its alternate Key value. Use this if you find that you’re getting unintended alternate values (i.e. modifiers) while typing on home-row qukeys, despite setting the overlap threshold (see above) to 100%. It may mean that you’ll need to slow down when using Qukeys to get modifiers, however.

Defaults to 50 (milliseconds).

.setMinimumPriorInterval(min_interval)

Sets the minimum amount of time (in milliseconds) that must pass between the press event of a prior (non-modifier) key and the press of a qukey required to make that qukey eligible to take on it’s alternate state. This is another measure that can be taken to prevent unintended modifiers while typing fast.

Defaults to 75 (milliseconds).