キーボードマップ

草案コミュニティグループレポート,

このバージョン:
https://wicg.github.io/keyboard-map/
課題追跡:
GitHub
編集者:
(Google)
解説:
Keyboard Map 解説ドキュメント

概要

この仕様は、Webサイトが指定されたcode 値から、 ユーザーにキーを特定させるために表示できる有効なkey 値への変換を提供するAPIを定義します。 code からkey への変換は、 ユーザーが現在選択しているキーボードレイアウトに基づきます。 このAPIは、キーボードをボタン群として扱い、それらボタンについてユーザーに説明したいWebアプリケーションでの利用を想定しています。

この文書のステータス

この仕様は Web Platform Incubator Community Group により公開されました。 これはW3C標準でもW3C標準化トラックにもありません。 W3Cコミュニティ貢献者ライセンス契約(CLA)のもとで、限定的なオプトアウトがあり、その他の条件も適用されますのでご注意ください。 W3Cコミュニティおよびビジネスグループについて詳しくはご覧ください。

本書はエディタードラフトであり、最初のパブリックワーキングドラフトとして提案されています。

1. はじめに

KeyboardEvent では、code 属性が押されたキーの物理的な位置を表す値を持ちます。この値は現在のロケール(例: "en-US")、レイアウト(例: "dvorak")、モディファイア状態(例: "Shift + Control")を無視するため、キーボードを汎用的なボタンとして扱いたいアプリ(ゲームなど)には理想的です。code 属性のコンセプトは各物理キーに対するプラットフォーム非依存のスキャンコードを提供することです。

一方、key 属性は、ロケール、レイアウト、モディファイアキーを考慮したキー押下で生成される値を保持します。ほぼ全てのUnicode文字が `key` 属性に適合しますが、特殊な名前付き値も多くあります(KeyboardEvent key属性値 参照)。 よって、key の値は数千種類になります。

ほとんどのユーザーは自分のロケール・レイアウトに対応する物理キーボードを持つため、key の値はキーキャップに印字された字形と対応して良い代理になります。ユーザーが異なるレイアウトを選択している場合には一致しませんが、その場合ユーザー自身もキーキャップと出力文字の不一致を把握しています。

本書のAPIは、この基本的なcode からkey へのマッピングの取得を簡単にします。

2. キーボード マップAPI

キーボードマップAPIは、Keyboard インターフェースを拡張し、現在のキーボードレイアウトに関連する属性やメソッドを追加します。

keyboard 属性はNavigator オブジェクト上に存在し、詳細はKeyboard-Lockで規定されています。

2.2. KeyboardLayoutMap インターフェース

KeyboardLayoutMap

現行エンジン1つのみ。

FirefoxNoneSafariNoneChrome69+
Opera55+Edge79+
Edge (Legacy)NoneIENone
Firefox for AndroidNoneiOS SafariNoneChrome for Android69+Android WebView69+Samsung Internet10.0+Opera Mobile48+
[Exposed=Window]
interface KeyboardLayoutMap {
  readonly maplike<DOMString, DOMString>;
};

KeyboardLayoutMap は、code 値からkey 値へのマッピングを提供する読み取り専用コレクションです。

2.3. Keyboard インターフェース

Keyboard

現行エンジン1つのみ。

FirefoxNoneSafariNoneChrome68+
Opera55+Edge79+
Edge (Legacy)NoneIENone
Firefox for AndroidNoneiOS SafariNoneChrome for Android68+Android WebView68+Samsung Internet10.0+Opera Mobile48+
partial interface Keyboard {
  Promise<KeyboardLayoutMap> getLayoutMap();

  attribute EventHandler onlayoutchange;
};

注: 基本のKeyboard インターフェースは[Keyboard-Lock]で定義されています。

2.3.1. getLayoutMap()

Keyboard/getLayoutMap

現行エンジン1つのみ。

FirefoxNoneSafariNoneChrome69+
Opera56+Edge79+
Edge (Legacy)NoneIENone
Firefox for AndroidNoneiOS SafariNoneChrome for Android69+Android WebView69+Samsung Internet10.0+Opera Mobile48+

getLayoutMap()が呼ばれると、ユーザーエージェントは次を実行します:

  1. p を新しいPromise とする。

  2. もし this関連するグローバルオブジェクト関連付けられたドキュメント使用することを許可されていない ポリシー制御機能 名称 "keyboard-map"

    1. pを"SecurityError" DOMExceptionで却下

    2. p を返す

  3. 以下のステップを並列で実行:

    1. map を新たな空のKeyboardLayoutMapとする。

    2. Writing System Keys テーブルの "KeyboardEvent code" 列 の各codeについて:

      1. layout を、最も優先度が高いASCII対応キーボードレイアウトまたは対応レイアウトが無い場合は最優先レイアウトとする。

      2. codelayoutで有効なキーでなければ続行

      3. key を、layout で修飾なしでcodeのキーを押した時に生成されるkey値とする。

      4. もしkeyデッドキーであれば

        1. keyデッドキーと対応する独立した文字(「デッドキーの単独等価」テーブル参照)をセット

      5. <code, key>からマップエントリeを作成

      6. emapに追加

    3. pをmapで解決

  4. p を返す。

ユーザーエージェントはlayout変更時にキャッシュを破棄・更新する限りmapをキャッシュし、キャッシュ値を返してもよい。

ゲームでどのキーを押すか指示を表示する例:
navigator.keyboard.getLayoutMap().then(function(map) {
  var keyUp = map.get("KeyW");
  showUserDialog("Press " + keyUp + " to move up.");
});
"US International" キーボードのように、シングルクォート (') キーがデッドキーとして機能し、次の文字にアキュートアクセントを追加する場合の例。 この場合、キーボードマップにはQuote(このキーのcode)と "'"(U+0027のシングルクォート文字)のマッピングが含まれます。

2.4. デッドキーおよび結合文字

キーボードマップAPIの目的はユーザーのキーボード上のキーに対する人間が判読できる説明を提供することなので、デッドキーや結合文字は、そのまま使える独立した形に変換する必要があります。

以下の表は、一般的なデッドキーや結合文字を独立した文字にどのようにマッピングするかを定義します。

表1: デッドキーの独立等価文字
デッドキー名 Unicode結合 独立文字 Unicode独立
Grave U+0300 "`" U+0060
Acute U+0301 "'" U+0027
Circumflex U+0302 "^" U+005e
Tilde U+0303 "~" U+007e
Diaeresis U+0308 "¨" U+00a8

2.5. ASCII対応キーボードレイアウト

ASCII対応キーボードレイアウトとは、次の条件を満たすものです。

共通書記体系キーとは、Figure 13[UIEvents-Code]仕様)で青色で示されている、全キーボードレイアウトに共通するキーです。

3. キーボードイベント

3.1. layoutchangeイベント

ユーザーエージェントがキーボードレイアウトの変更を検知した場合、必ずlayoutchangeイベントを発火しなければなりません。レイアウト変更のタイミングは基盤プラットフォームによって異なりますが、多くの場合はユーザーが新しいレイアウトを選択した時や、特定レイアウトが設定されたアプリケーションへ切り替える時など、直接・間接的トリガーによって発動します。

以下に注意してください:

ユーザーエージェントが前面アプリケーションでない間にキーボードレイアウトが変更された場合、フォーカスを再取得したタイミングで必ずlayoutchangeイベントを発火しなければなりません。

このイベントをハンドリングするなら:
navigator.keyboard.addEventListener("layoutchange", function() {
  // ユーザーのキーボードマップ設定を更新
  updateGameControlSettingsPage();
});

3.1.1. layoutchangeイベントを発火

"layoutchange"イベントを発火するには、イベントを発火し、イベント名layoutchange、ユーザーエージェントのkeyboard 属性(Navigator オブジェクト上)で発火します。

4. 統合

4.1. パーミッションポリシー

この仕様は、getLayoutMap()メソッドがKeyboard インターフェースで公開されるかどうかを制御する機能を定義します。

この機能のフィーチャー名は "keyboard-map" です。

この機能のデフォルト許可リストは "self" です。

5. モバイル端末での考慮事項

このAPIはキーボード中心のAPIであり、モバイル端末には物理キーボードが一般的でないため、通常はモバイル端末で利用不可またはサポートされません。

ただし物理キーボードの接続を許可するモバイル端末ではAPIに対応する場合もあります。その場合、プラットフォームに適した書記体系キーのサブセットを返すことがあります。

物理キーボードレイアウトの設定をユーザーに強いる(デフォルト値を持たない)プラットフォームの場合、エントリなしのレイアウトマップを返すことでこのAPIをサポートしても構いません。

6. セキュリティに関する考慮事項

このAPIは静的なデータのみを返し、システム状態を変更しないため、特別なセキュリティ上の懸念はありません。

7. プライバシーに関する考慮事項

現在の端末状態情報を返すすべてのAPIと同様、このAPIを利用してユーザーの「フィンガープリント情報」が広がるリスクがあります。

アクティブレイアウトではなく最優先ASCII対応レイアウト情報を返すことで、多くのユーザーが同じ値になりやすく、フィンガープリント用途での価値は低減します。

以下のような場合、このレイアウト情報は個人特定に使われる可能性があります:

このAPIがなくても、ページ上でユーザーにキー入力をさせてKeyboardEvent を解析すれば同様のフィンガープリント攻撃は技術的には可能ですが、より困難です。

7.1. プライバシー対策

第一の防御策として、このAPIが利用可能なのはセキュアコンテキスト内かつ、現在のトップレベルブラウジングコンテキストのみ、またはポリシー制御機能で許可された場合のみです。

このマッピング情報によるプライバシー影響を懸念するユーザーエージェントは、追加の対策も検討できます:

7.2. プライバシーモード

ユーザーエージェントが「シークレット」や「プライバシーモード」を提供する場合も、このAPIの挙動は通常と同じであるべきです。 なぜなら、ユーザーのプライバシーを保証できる普遍的な中立値が存在しないためです。

このモード時に返す値の選択肢をユーザーに委ねても構いませんが、居住地域外へ移動する時は値の更新が必要なことなど、ユーザーが誤った安全感を抱かないよう注意が必要です。

8. 謝辞

本提案の策定につながる議論をしてくださった皆さまに感謝いたします。

Hadley Beeman (W3C TAG), Joe Downing (Google), Masayuki Nakano (Mozilla), Julien Wajsberg (Mozilla)

9. 用語集

スキャンコード

各キーを一意に識別するためにキーボードハードウェアが割り当てる値。 詳細は https://en.wikipedia.org/wiki/Scancode を参照。

適合性

ドキュメントの規則

適合要件は、記述的な主張とRFC 2119の用語の組み合わせで表現されます。 本書の規範的な部分で使われる “MUST”, “MUST NOT”, “REQUIRED”, “SHALL”, “SHALL NOT”, “SHOULD”, “SHOULD NOT”, “RECOMMENDED”, “MAY”, “OPTIONAL” の語は RFC 2119の定義通り解釈します。 ただし、可読性を考慮し、 本仕様ではこれらの単語が全て大文字で表記されるとは限りません。

本仕様書の全ての記述は、明示的に非規範的(non-normative)、例(example)、注記(note)とされたセクションを除き規範的です。 [RFC2119]

本仕様の例は「for example」で始める、または class="example" のように規範文から切り分けて記載します。

これは参考例です。

参考注記は「Note」で始まり、また class="note" により規範文と区別されます。

Note、これは参考注記です。

適合するアルゴリズム

アルゴリズム中で命令形で書かれた要件(例:"strip any leading space characters" や "return false and abort these steps")は、アルゴリズムの冒頭で用いられた主要語 ("must", "should", "may" など) の意味に従って解釈されます。

アルゴリズムや特定の手順として表現された適合要件は、その最終結果が等しければ、どのように実装しても構いません。 特に、本仕様のアルゴリズムは理解しやすさを重視しており、 性能最優先の意図はありません。 実装者は最適化を推奨します。

索引

この仕様で定義された用語

参照で定義された用語

参考文献

規格文献

[DOM]
Anne van Kesteren. DOM Standard. Living Standard. URL: https://dom.spec.whatwg.org/
[HTML]
Anne van Kesteren; et al. HTML Standard. Living Standard. URL: https://html.spec.whatwg.org/multipage/
[Keyboard-Lock]
Keyboard Lock. cg-draft. URL: https://wicg.github.io/keyboard-lock/
[PERMISSIONS-POLICY-1]
Ian Clelland. Permissions Policy. 16 July 2020. WD. URL: https://www.w3.org/TR/permissions-policy-1/
[RFC2119]
S. Bradner. Key words for use in RFCs to Indicate Requirement Levels. March 1997. Best Current Practice. URL: https://datatracker.ietf.org/doc/html/rfc2119
[UIEVENTS]
Gary Kacmarcik; Travis Leithead. UI Events. 1 June 2022. WD. URL: https://www.w3.org/TR/uievents/
[UIEvents-Code]
Gary Kacmarcik; Travis Leithead. UI Events KeyboardEvent code Values. 1 June 2017. CR. URL: https://www.w3.org/TR/uievents-code/
[UIEVENTS-KEY]
Gary Kacmarcik; Travis Leithead. UI Events KeyboardEvent key Values. 1 June 2017. CR. URL: https://www.w3.org/TR/uievents-key/
[WEBIDL]
Edgar Chen; Timothy Gu. Web IDL Standard. Living Standard. URL: https://webidl.spec.whatwg.org/

IDL索引

[Exposed=Window]
interface KeyboardLayoutMap {
  readonly maplike<DOMString, DOMString>;
};

partial interface Keyboard {
  Promise<KeyboardLayoutMap> getLayoutMap();

  attribute EventHandler onlayoutchange;
};