ChromeOS デバイスでは、多くのユーザーがキーボード、マウス、トラックパッド、タッチペン、ゲームパッドを使用してアプリを操作します。これらの入力デバイスは Android スマートフォンでも使用されますが、一般的ではないためデベロッパーによって見過ごされがちです。
ChromeOS とその他の大画面 Android 対応デバイスでの入力に対してアプリが十分に機能するようにしたい場合は、次の最適化を考慮する必要があります。
- 基本的なキーボード サポートを追加してテストする(矢印キーと Tab キーによるキーボード ナビゲーション、Enter キーによるテキスト入力の確定、Space キーによるメディアアプリの再生と一時停止など)。
-
可能であれば標準のキーボード ショートカットを追加する(
ctrl+zで元に戻す、ctrl+sで保存するなど)。 - 基本的なマウス操作をテストする(右クリックしてコンテキスト メニューを表示する、ユーザーがカーソルを合わせたときにアイコンを変更する、マウスホイールまたはトラックパッドでカスタムビューをスクロールするなど)。
- アプリ固有の入力デバイスをテストする(描画アプリ用のタッチペン、ゲーム用のゲーム コントローラ、音楽アプリ用の MIDI コントローラなど)。
- パソコン環境でアプリの魅力を高める高度な入力サポートを検討する(DJ アプリ用のクロスフェーダーとしてのタッチパッド、ゲーム用のマウス キャプチャ、パワーユーザー向けの豊富なキーボード ショートカットなど)。
キーボード
キーボード入力に対してアプリがどのように応答するかは、パソコンのエクスペリエンスを高める鍵になります。キーボード入力には、ナビゲーション、キーストローク、ショートカットの 3 種類があります。
ナビゲーション
タップ中心のアプリにキーボード ナビゲーションが実装されることはまれですが、ユーザーはキーボードでアプリを使用しているときに、キーボード ナビゲーションを期待します。また、スマートフォンとパソコンの両方でユーザー補助機能を必要とするユーザーにとって、キーボードは不可欠です。
多くのアプリは矢印キーと Tab キーによるナビゲーションしか必要とせず、ほとんどの場合 Android フレームワークによって自動的に処理されます。たとえば、Button のビューはデフォルトでフォーカス可能であり、キーボード ナビゲーションは一般的に追加のコードなしで機能します。デフォルトではフォーカス可能でないビューのキーボード ナビゲーションを有効にするには、デベロッパーがビューをフォーカス可能としてマークする必要があります。これは、以下に示すように、プログラムまたは XML で実現できます。詳細については、フォーカス処理のドキュメントをご覧ください。
yourView.isFocusable = true
他に、レイアウト ファイルで focusable 属性を設定する方法もあります。
android:focusable="true"
フォーカスが有効になると、Android フレームワークはすべてのフォーカス可能なビューの位置に基づいて、それらのナビゲーション マッピングを作成します。通常、これは想定どおりに機能し、特別な作業は不要です。デフォルト マッピングがアプリのニーズに合わない場合は、次のようにしてオーバーライドできます。
// Arrow keys yourView.nextFocusLeftId = R.id.view_to_left yourView.nextFocusRightId = R.id.view_to_right yourView.nextFocusTopId = R.id.view_above yourView.nextFocusBottomId = R.id.view_below // Tab key yourView.nextFocusForwardId = R.id.next_view
アプリをリリースする前に、キーボードのみを使用してアプリの各機能をテストすることをおすすめします。一般的な操作は、マウス入力やタッチ入力なしで簡単に行えるようにする必要があります。
注: ユーザー補助機能を必要とするユーザーにとっては、キーボード サポートが不可欠であることに留意してください。
キーストローク
EditText のような画面上の仮想キーボード(IME)によって処理されるテキスト入力については、デベロッパーによる追加作業がなくてもアプリが ChromeOS 上で期待どおりに動作することが求められます。フレームワークが予測できないキーストロークについては、アプリが独自に動作を処理する必要があります。これは、特にカスタムビューを使用するアプリに当てはまります。
例としては、Enter キーを使用してメッセージを送信するチャットアプリ、Space キーで再生を開始および停止するメディアアプリ、W、A、S、D キーで移動を制御するゲームなどがあります。
ほとんどのアプリは、次に示すように、onKeyUp イベントをオーバーライドして、受け取ったキーコードごとに期待される動作を追加します。
override fun onKeyUp(keyCode: Int, event: KeyEvent): Boolean { return when (keyCode) { KeyEvent.KEYCODE_ENTER -> { sendChatMessage() true } KeyEvent.KEYCODE_SPACE -> { playOrPauseMedia() true } else -> super.onKeyUp(keyCode, event) } }
onKeyUp を使用すると、キーを押したり離したりする操作が遅い場合に、アプリが複数のイベントを受信することを回避できます。ユーザーがキーボードのキーを押す操作を想定しているゲームとアプリでは、onKeyDown イベントを探すことができます。
通常は、アプリのニーズに応じてアクティビティ全体で onKeyUp をオーバーライドすることで、必要な動作を実現できます。必要であれば、代わりに onKeyListener を特定のビューに追加することもできます。たとえば、ユーザーがチャット ボックスに入力しているときにのみアプリに送信機能を実装するには、Activity ではなく特定の EditText で Enter キーのみをリッスンします。
キーボード サポートを追加する場合は、Android のキーボード処理のドキュメントに沿って操作してください。
ショートカット
パソコン環境では、一般的な ctrl、alt、shift をベースとするショートカットが求められます。それらのショートカットがアプリに実装されていないと、ユーザーはフラストレーションを感じたり故障を疑ったりする可能性があります。また上級ユーザーにとっては、よく使うアプリ固有のタスクのショートカットが役立ちます。ショートカットを実装することで、アプリの使いやすさを高め、ショートカットを備えていないアプリとの差別化を図ることができます。
一般的なショートカットには、保存(ctrl+s)、元に戻す(ctrl+z)、やり直し(ctrl+shift+z)などがあります。より高度なショートカットの例については、VLC Media Player のショートカット キーの一覧をご覧ください。
ショートカットは dispatchKeyShortcutEvent を使用して実装できます。このメソッドは、特定のキーコードのすべてのメタキーの組み合わせ(alt、ctrl、shift)をインターセプトします。特定のメタキーをチェックするには、KeyEvent.isCtrlPressed()、KeyEvent.isShiftPressed()、KeyEvent.isAltPressed()、または KeyEvent.hasModifiers() を使用します。
ショートカット コードを他のキーストローク処理(onKeyUp や onKeyDown)から分離することで、コードのメンテナンスが容易になり、すべての場合に手動でメタキーのチェックを実装しなくても、メタキーのデフォルトの受容を管理できます。また、さまざまなキーボード レイアウトとオペレーティング システムに慣れたユーザーにとっては、あらゆるメタキーの組み合わせが可能であれば、使いやすさが向上します。
override fun dispatchKeyShortcutEvent(event: KeyEvent): Boolean { return when (event.keyCode) { KeyEvent.KEYCODE_O -> { openFile() // Ctrl+O, Shift+O, Alt+O true } KeyEvent.KEYCODE_Z-> { if (event.isCtrlPressed) { if (event.isShiftPressed) { redoLastAction() // Ctrl+Shift+Z pressed true } else { undoLastAction() // Ctrl+Z pressed true } } } else -> { return super.dispatchKeyShortcutEvent(event) } } }
同様に KeyEvent.isCtrlPressed()、KeyEvent.isShiftPressed()、KeyEvent.isAltPressed() をチェックして、onKeyUp でショートカットを実装することもできます。この方法では、メタキーの動作がショートカットというよりもアプリの動作の変形である場合に、メンテナンスが簡単になります。たとえば、w が「前に歩く」を意味し、shift+w が「前に走る」を意味する場合などです。
override fun onKeyUp(keyCode: Int, event: KeyEvent): Boolean { return when(keyCode) { KeyEvent.KEYCODE_W-> { if (event.isShiftPressed) { if (event.isCtrlPressed) { flyForward() // Ctrl+Shift+W pressed true } else { runForward() // Shift+W pressed true } } else { walkForward() // W pressed } } else -> super.onKeyUp(keyCode, event) } }
マウスとタッチパッドのサポート
ChromeOS では、ほとんどのマウスイベントとトラックパッド イベントは、Android スマートフォンのタッチイベントと同様に動作するように自動的に処理されます。2 本の指によるタッチパッド操作とマウスホイールによるスクロールもこれに該当します。一般的に、ほとんどのアプリで処理する必要があるパソコン中心のイベントは、右クリック、マウスオーバー、ドラッグ&ドロップの 3 つだけです。
右クリック
リストアイテムの長押しなど、アプリにコンテキスト メニューを表示させるためのすべてのアクションは、右クリック イベントにも反応する必要があります。アプリが右クリック イベントを処理するには、View.OnContextClickListener の登録が必要です。コンテキスト メニューの作成の詳細については、Android のコンテキスト メニューのドキュメントをご覧ください。
yourView.setOnContextClickListener { view -> showContextMenu() true }
注: Activity.registerForContextMenu() を使用してコンテキスト メニューに登録したビューは、コンテキスト クリック リスナーを登録しなくても、長押しと右クリックの両方で自動的に機能します。
カーソルを合わせる
デベロッパーは、マウスオーバー イベントを適切に処理することで、アプリのレイアウトが洗練されていて使いやすいとユーザーに感じさせることができます。これは、特にカスタムビューに当てはまります。最も一般的な例は次の 2 つです。
- マウスポインタ アイコンを変更することで、要素にインタラクティブな動作がある(たとえば、クリック可能または編集可能である)ことをユーザーに知らせる
- 大規模なリストまたはグリッド内のアイテムにユーザーがカーソルを合わせたとき、そのアイテムに視覚的なフィードバックを追加する
// Change the icon to a "hand" pointer on hover, // Highlight the view by changing the background. yourView.setOnHoverListener { view, _ -> addVisualHighlighting(true) view.pointerIcon = PointerIcon.getSystemIcon(applicationContext, PointerIcon.TYPE_HAND) false // listener did not consume the event. }
ドラッグ&ドロップ
マルチウィンドウ環境では、ユーザーはアプリ間でアイテムをドラッグ&ドロップできることを期待します。これは、ChromeOS デバイス、タブレット、スマートフォン、分割画面モードの折りたたみ式デバイスに当てはまります。
デベロッパーは、ユーザーがアプリにアイテムをドラッグする可能性があるかどうかを考慮する必要があります。よくある例としては、写真エディタによる写真の受け取り、オーディオ プレーヤーによる音声ファイルの受け取り、描画プログラムによる写真の受け取りなどがあります。
ドラッグ&ドロップのサポートを追加するには、Android のドラッグ&ドロップのドキュメントに従い、こちらの ChromeOS に関するブログ投稿を参照してください。
ChromeOS 向けの特別な考慮事項
-
ChromeOS ファイルアプリのファイルを処理するには、MIME タイプ
application/x-arc-uri-listを探します。 -
アプリ外からドラッグしたアイテムにアクセスするには、
requestDragAndDropPermissionsを使用して権限をリクエストします。 -
他のアプリにアイテムをドラッグするには、アイテムに
View.DRAG_FLAG_GLOBALフラグを設定する必要があります。
複数選択のサポート
アプリにリストやグリッドが含まれている場合は、ユーザーが複数選択をサポートすることでメリットを得られるかどうかを検討してください。マウスとトラックパッドによる高品質な複数選択エクスペリエンスには、帯域選択などの機能が含まれていることがよくあります。これを独自に実装するのは難しい場合がありますが、RecyclerView 選択ライブラリを使用できます。
高度なポインタのサポート
マウス入力とタッチパッド入力の高度な処理を行うアプリは、Android ドキュメントの View.onGenericMotionEvent() に関する説明に沿って、MotionEvent.getSource() を使用して SOURCE_MOUSE と SOURCE_TOUCHSCREEN を区別する必要があります。
MotionEvent を調べて、次のような必要な動作を実装します。
-
移動によって
ACTION_HOVER_MOVEイベントを生成する -
ボタンによって
ACTION_BUTTON_PRESSイベントとACTION_BUTTON_RELEASEイベントを生成する。getButtonState()を使用して、すべてのマウスまたはトラックパッド ボタンの現在の状態をチェックすることもできます。 -
マウスホイールのスクロールによって
ACTION_SCROLLイベントを生成する
タッチペン
多くの Chromebook にはタッチペンが付属しており、Android アプリはこれをタッチスクリーン入力として処理します。一部のデバイスは、Wacom Intuos のように USB または Bluetooth の描画テーブルを備えています。Android アプリは Bluetooth 入力を受け取れますが、USB 入力では動作しません。
タッチペン イベントは、View.onTouchEvent() または View.onGenericMotionEvent() を使用してタッチスクリーン イベントとしてレポートされ、SOURCE_STYLUS タイプの MotionEvent.getSource() を含みます。MotionEvent には他のデータも含まれます。
-
MotionEvent.getToolType()は、サーフェスと接触したツールに応じて、TOOL_TYPE_FINGER、TOOL_TYPE_STYLUS、またはTOOL_TYPE_ERASERを返します。 -
MotionEvent.getPressure()は、タッチペンに加えられた物理的な圧力を報告します(サポートされている場合)。 -
MotionEvent.getAxisValue()をMotionEvent.AXIS_TILT、MotionEvent.AXIS_ORIENTATIONと併用すると、タッチペンの物理的な傾きと向きを読み取ることができます(サポートされている場合)
履歴ポイント
Android は、入力イベントを一括でまとめてフレームごとに 1 回送信します。タッチペン入力では、ディスプレイよりもはるかに高い頻度でイベントがレポートされる可能性があります。描画アプリを作成する場合は、次の getHistorical API を使用して、最近発生した可能性があるイベントをチェックすることが重要です。
-
MotionEvent.getHistoricalX() -
MotionEvent.getHistoricalY() -
MotionEvent.getHistoricalPressure() -
MotionEvent.getHistoricalAxisValue()
パーム リジェクション
ChromeOS は、ユーザーの手のひらがタッチスクリーンに置かれた状態を認識しようと試みます。ただし、これは常に可能であるとは限りません。OS が手のひらとして認識する前に、タッチイベントがアプリに報告されることがあります。その場合は、ACTION_CANCEL イベントを報告することで、タッチをキャンセルできます。
このイベントは、特定のタップが無効であり、そのタップによって発生したすべての操作を元に戻す必要があることをアプリに伝えます。たとえば、描画アプリは、レイテンシを最小限に抑えるため、新しい線を受け取るとすぐにそれらを一時的に描画しますが、それらがキャンバスで永続的に確定されるのは、一連のタッチが明確に終了してからです。その間にタッチイベントがキャンセルされた場合、一時的に描画された線は消去できます。
注: 描画と書き込みを行うアプリで余分な手のひらイベントと指イベントを減らす方法としては、タップによる描画を無効にする UI 設定を提供し、このモードでは描画にタッチペン イベントのみを使用することが挙げられます。
メモ作成アプリ
ChromeOS には、登録されたメモ作成アプリをユーザーに表示するための特別なインテントがあります。アプリをメモ作成アプリとして登録するには、Android マニフェストに次の行を追加します。
<intent-filter> <action android:name="org.chromium.arc.intent.action.CREATE_NOTE" /> <category android:name="android.intent.category.DEFAULT" /> </intent-filter>
アプリが登録されると、ユーザーはそのアプリをデフォルトのメモ作成アプリとして選択できます。新しいメモがリクエストされた場合、アプリはタッチペン入力が可能な空のメモを作成する必要があります。ユーザーが画像(スクリーンショットやダウンロードした画像など)にアノテーションを付けようとした場合、アプリは content:// URI を持つアイテムを 1 つ以上含む ClipData とともに起動します。アプリは、最初の添付画像を背景画像として使用するメモを作成し、ユーザーがタッチペンで描画できるモードに移行する必要があります。
タッチペンなしでメモ作成インテントをテストする
アプリがメモ作成インテントに正しく応答するかどうかをアクティブなタッチペンがない状態でテストするには、次の方法でメモ作成オプションを表示します。
- デベロッパー モードに切り替えて、デバイスを書き込み可能にする
-
ctrl+alt+f2キーを押してターミナルを開きます。 -
sudo vi /etc/chrome_dev.confコマンドを実行します。 -
iを押して入力モードに切り替え、ファイルの末尾に新しい行として--ash-enable-paletteを追加する -
Escを押してから:、w、qと入力し、Enterを押して保存する -
ctrl+alt+f1キーを押して、通常の ChromeOS UI に戻る
これで、シェルフにタッチペン メニューが表示されるようになります。
- シェルフ内のタッチペン ボタンをタップし、[新しいメモ] を選択します。これにより、空白の描画メモが開きます。
- スクリーンショットを撮ります。シェルフから [タッチペン ボタン] > [画面をキャプチャ] を選択するか、または画像をダウンロードします。画像にアノテーションを付けるオプションが通知に表示されます。これにより、アノテーションを付けることができる画像を含むアプリが起動します。
ゲーム コントローラ
Chromebook は、最大 4 つのゲーム コントローラをサポートします。デベロッパーは、標準の Android ゲーム コントローラ API を使用してそれらを処理する必要があります。
ボタンは、一般的なマッピングに従って一般的な値にマッピングされます。残念ながら、すべてのゲーム コントローラ メーカーが同じマッピング規則に従っているわけではありません。各種の一般的なコントローラ マッピングをユーザーが選択できるようにすると、エクスペリエンスを大幅に向上させることができます。
入力変換モード
ChromeOS では、デフォルトで入力変換モードが有効になっています。ほとんどの Android アプリの場合、このモードはパソコン環境で想定されるとおりに動作します。たとえば、タッチパッドでの 2 本指スクロール、マウスホイールによるスクロール、未加工のディスプレイ座標のウィンドウ座標へのマッピングなどが自動的に有効になります。通常、アプリ デベロッパーはこうした動作を実装する必要はありません。
カスタムの入力動作をアプリに実装する(たとえば 2 本の指でタッチパッドをつまむカスタム操作を定義する)場合や、アプリが想定する入力イベントが入力変換によって提供されない場合は、Android マニフェストに次のタグを追加することにより、入力変換モードを無効にできます。
<uses-feature android:name="android.hardware.type.pc" android:required="false" />