Eingabekompatibilität

Auf ChromeOS-Geräten interagieren viele Nutzer mit Apps über eine Tastatur, Maus, ein Trackpad, einen Stift oder ein Gamepad. Diese Eingabegeräte werden zwar auch auf Android-Smartphones verwendet, sind aber nicht so verbreitet und werden von Entwicklern oft übersehen.

Entwickler, die möchten, dass ihre App auf ChromeOS-Geräten und anderen Android-Geräten mit großem Bildschirm gut mit Eingaben funktioniert, sollten sich die folgenden Optimierungen ansehen:

  • Fügen Sie grundlegende Tastaturunterstützung hinzu und testen Sie sie, z. B. die Tastaturnavigation mit den Pfeil- und Tabulatortasten, die Eingabetaste zum Bestätigen der Texteingabe und die Leertaste zum Abspielen/Pausieren in Media-Apps.
  • Fügen Sie gegebenenfalls Standardtastenkombinationen hinzu, z. B. ctrl+z für „Rückgängig“ und ctrl+s für „Speichern“.
  • Testen Sie grundlegende Mausinteraktionen wie das Rechtsklicken für das Kontextmenü, das Ändern von Symbolen beim Bewegen des Mauszeigers darauf und das Scrollen mit dem Mausrad oder Touchpad in benutzerdefinierten Ansichten.
  • Testen Sie appspezifische Eingabegeräte wie Stifte für Zeichen-Apps, Gamecontroller für Spiele und MIDI-Controller für Musik-Apps.
  • Erwägen Sie die Unterstützung erweiterter Eingabemethoden, die Ihre App auf Desktop-Geräten hervorheben könnten: Touchpad als Crossfader für DJ-Apps, Mauszeigerfang für Spiele und umfangreiche Tastenkombinationen für Power-User.

Tastatur

Die Art und Weise, wie Ihre App auf Tastatureingaben reagiert, trägt zu einer guten Desktop-Erfahrung bei. Es gibt drei Arten der Tastatureingabe: Navigation, Tastenanschläge und Tastenkürzel.

Die Tastaturnavigation wird selten in Apps implementiert, die für die Touchbedienung optimiert sind. Nutzer erwarten sie jedoch, wenn sie eine App mit einer Tastatur verwenden. Sie kann auch für Nutzer mit Beeinträchtigungen auf Smartphones und Desktopgeräten unerlässlich sein.

Für viele Apps ist die Navigation mit Pfeiltasten und Tabulatortaste ausreichend und wird größtenteils automatisch vom Android-Framework übernommen. Beispielsweise ist eine Ansicht eines Button standardmäßig fokussierbar und die Tastaturnavigation sollte im Allgemeinen ohne zusätzlichen Code funktionieren. Damit die Tastaturnavigation für Ansichten möglich ist, die standardmäßig nicht fokussierbar sind, müssen Entwickler sie als fokussierbar kennzeichnen. Dies kann programmatisch oder in XML erfolgen. Weitere Informationen finden Sie in der Dokumentation unter Fokusverwaltung.

yourView.isFocusable = true

Alternativ können Sie das Attribut focusable in Ihrer Layoutdatei festlegen:

android:focusable="true"

Sobald der Fokus aktiviert ist, erstellt das Android-Framework eine Navigationszuordnung für alle fokussierbaren Ansichten basierend auf ihrer Position. Das funktioniert in der Regel wie erwartet und es sind keine weiteren Maßnahmen erforderlich. Wenn die Standardzuordnung für die Anforderungen einer App nicht korrekt ist, kann sie so überschrieben werden:

// 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

Es empfiehlt sich, vor jedem Release nur über die Tastatur auf alle Funktionen Ihrer App zuzugreifen. Auf die häufigsten Aktionen sollte ohne Maus- oder Toucheingabe zugegriffen werden können.

Hinweis:Die Tastaturunterstützung kann für Nutzer mit Beeinträchtigungen unerlässlich sein.

Tastenanschläge

Bei der Texteingabe, die von einer virtuellen Bildschirmtastatur (IME) wie einer EditText verarbeitet wird, sollten sich Apps unter ChromeOS wie erwartet verhalten, ohne dass der Entwickler zusätzliche Maßnahmen ergreifen muss. Bei Tasteneingaben, die vom Framework nicht vorhergesehen werden können, müssen Apps das Verhalten selbst verarbeiten. Das gilt insbesondere für Apps mit benutzerdefinierten Ansichten.

Beispiele sind Chat-Apps, in denen Nachrichten mit der Eingabetaste gesendet werden, Media-Apps, in denen die Wiedergabe mit der Leertaste gestartet oder beendet wird, und Spiele, in denen die Bewegung mit den Tasten „w“, „a“, „s“ und „d“ gesteuert wird.

Die meisten Apps überschreiben das onKeyUp-Ereignis und fügen das erwartete Verhalten für jeden empfangenen Tastencode hinzu, wie unten beschrieben.

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)
    }
}

Durch die Verwendung von onKeyUp wird verhindert, dass Apps mehrere Ereignisse empfangen, wenn eine Taste gedrückt oder langsam losgelassen wird. Bei Spielen und Apps, bei denen Nutzer Tasten auf der Tastatur gedrückt halten müssen, kann nach dem onKeyDown-Ereignis gesucht werden.

Je nach den Anforderungen einer App kann das Überschreiben von onKeyUp für die gesamte Aktivität das erforderliche Verhalten bieten. Bei Bedarf kann stattdessen ein onKeyListener zu einer bestimmten Ansicht hinzugefügt werden. Eine App kann beispielsweise nur in einem bestimmten EditText-Feld und nicht in der Activity auf die Eingabetaste reagieren, um die Sende-Funktion nur dann zu implementieren, wenn der Nutzer in ein Chatfeld schreibt.

Wenn Sie Tastaturunterstützung hinzufügen, folgen Sie der Android-Dokumentation zur Tastaturbehandlung.

Tastenkombinationen

Gängige Tastenkombinationen, die auf ctrl, alt und shift basieren, werden in Desktopumgebungen erwartet. Wenn eine App sie nicht implementiert, kann die Nutzung für Nutzer frustrierend und fehlerhaft sein. Auch fortgeschrittene Nutzer schätzen Tastenkombinationen für häufig verwendete app-spezifische Aufgaben. Kurzbefehle erleichtern die Verwendung einer App und heben sie von Apps ohne Kurzbefehle ab.

Einige gängige Tastenkombinationen sind „Speichern“ (ctrl+s), „Rückgängig“ (ctrl+z) und „Wiederholen“ (ctrl+shift+z). Eine Liste mit weiteren Tastenkombinationen finden Sie unter VLC Media Player-Tastenkombinationen.

Verknüpfungen können mit dispatchKeyShortcutEvent implementiert werden. Dadurch werden alle Meta-Schlüsselkombinationen (alt, ctrl und shift) für einen bestimmten Tastencode abgefangen. Wenn Sie nach einem bestimmten Metaschlüssel suchen möchten, verwenden Sie KeyEvent.isCtrlPressed(), KeyEvent.isShiftPressed(), KeyEvent.isAltPressed() oder KeyEvent.hasModifiers().

Wenn Sie den Tastenkombinationscode von anderen Tasteneingaben (z. B. onKeyUp oder onKeyDown) trennen, kann die Codeverwaltung einfacher sein. Außerdem wird die Standardakzeptanz von Meta-Tasten beibehalten, ohne dass Sie Meta-Tastenprüfungen in jedem Fall manuell implementieren müssen. Wenn Sie alle Meta-Tastenkombinationen zulassen, kann das auch für Nutzer, die an unterschiedliche Tastaturlayouts und Betriebssysteme gewöhnt sind, praktischer sein.

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)
    }
  }
}

Sie können auch Verknüpfungen in onKeyUp implementieren, indem Sie auf dieselbe Weise nach KeyEvent.isCtrlPressed(), KeyEvent.isShiftPressed() oder KeyEvent.isAltPressed() suchen. Das kann einfacher zu verwalten sein, wenn das Meta-Verhalten eher eine Änderung des App-Verhaltens als eine Verknüpfung ist. Beispiel: „w“ bedeutet „nach vorne gehen“ und „Umschalt+w“ bedeutet „nach vorne laufen“.

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)
  }
}

Unterstützung von Maus und Touchpad

ChromeOS verarbeitet die meisten Maus- und Trackpad-Ereignisse automatisch, sodass sie sich wie Touch-Ereignisse auf einem Android-Smartphone verhalten. Dazu gehört auch das Scrollen mit zwei Fingern auf dem Touchpad oder mit dem Mausrad. Die meisten Apps müssen in der Regel nur drei desktoporientierte Ereignisse verarbeiten: Rechtsklick, Hover und Drag-and-Drop.

Rechtsklicken

Alle Aktionen, die dazu führen, dass in einer App ein Kontextmenü angezeigt wird, z. B. langes Drücken auf ein Listenelement, sollten auch auf Rechtsklickereignisse reagieren. Um Rechtsklickereignisse zu verarbeiten, sollten Apps ein View.OnContextClickListener registrieren. Weitere Informationen zum Erstellen eines Kontextmenüs finden Sie in der Android-Dokumentation zu Kontextmenüs.

yourView.setOnContextClickListener { view ->
  showContextMenu()
  true
}

Hinweis:Alle Ansichten, die mit Activity.registerForContextMenu() für ein Kontextmenü registriert wurden, sollten automatisch sowohl mit Langdrücken als auch mit Rechtsklicken funktionieren, ohne dass ein Kontextklick-Listener registriert werden muss.

Mauszeiger hierher bewegen

Entwickler können Hover-Ereignisse nutzen, um das Layout ihrer Apps zu optimieren und die Bedienung zu vereinfachen. Das gilt insbesondere für benutzerdefinierte Ansichten. Die beiden häufigsten Beispiele hierfür sind:

  • Nutzer darauf hinweisen, dass ein Element interaktiv ist, z. B. durch Ändern des Mauszeigersymbols, wenn es anklickbar oder bearbeitbar ist
  • Visuelles Feedback für Elemente in einer großen Liste oder einem großen Raster hinzufügen, wenn der Mauszeiger darauf bewegt wird
// 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.
}

Drag-and-drop

In einer Umgebung mit mehreren Fenstern erwarten Nutzer, dass sie Elemente per Drag-and-drop zwischen Apps verschieben können. Das gilt sowohl für ChromeOS-Geräte als auch für Tablets, Smartphones und faltbare Geräte im Splitscreen-Modus.

Entwickler sollten überlegen, ob Nutzer wahrscheinlich Elemente in ihre App ziehen. Einige gängige Beispiele: Fotoeditoren sollten Fotos empfangen, Audioplayer sollten Audiodateien empfangen und Zeichenprogramme sollten Fotos empfangen.

Wenn Sie Drag-and-Drop-Unterstützung hinzufügen möchten, folgen Sie der Android-Dokumentation zu Drag-and-Drop und lesen Sie diesen ChromeOS-Blogpost.

Besondere Überlegungen für ChromeOS

  • Wenn Sie Dateien aus der ChromeOS-Dateimanager-App verarbeiten möchten, suchen Sie nach dem MIME-Typ application/x-arc-uri-list
  • Denken Sie daran, die Berechtigung mit requestDragAndDropPermissions anzufordern, um auf Elemente zuzugreifen, die von außerhalb der App hineingezogen wurden.
  • Ein Element muss das Flag View.DRAG_FLAG_GLOBAL haben, damit es in andere Anwendungen gezogen werden kann.

Unterstützung der Mehrfachauswahl

Wenn Ihre App Listen oder Tabellen enthält, sollten Sie überlegen, ob Ihre Nutzer von der Unterstützung der Mehrfachauswahl profitieren würden. Eine hochwertige Mehrfachauswahl mit Maus und Trackpad umfasst oft Funktionen wie die Auswahl von Bereichen. Die Implementierung dieser Funktion kann schwierig sein. Sie können jedoch die RecyclerView-Auswahlbibliothek verwenden.

Beispiel für die Auswahl mehrerer Bänder mit Maus und Zeiger.

Erweiterte Unterstützung für Zeiger

Apps, die Maus- und Touchpad-Eingaben auf erweiterte Weise verarbeiten, sollten der Android-Dokumentation für View.onGenericMotionEvent() folgen und MotionEvent.getSource() verwenden, um zwischen SOURCE_MOUSE und SOURCE_TOUCHSCREEN zu unterscheiden.

Sehen Sie sich die MotionEvent an, um das erforderliche Verhalten zu implementieren:

  • Durch Bewegung werden ACTION_HOVER_MOVE Ereignisse generiert
  • Schaltflächen generieren ACTION_BUTTON_PRESS- und ACTION_BUTTON_RELEASE-Ereignisse. Mit getButtonState() können Sie auch den aktuellen Status aller Maus- und Trackpad-Tasten prüfen.
  • Beim Scrollen mit dem Mausrad werden ACTION_SCROLL-Ereignisse generiert

Eingabestift

Viele Chromebooks werden mit einem Eingabestift geliefert. Android-Apps behandeln die Eingabe über den Stift als Touchscreen-Eingabe. Einige Geräte haben möglicherweise auch ein USB- oder Bluetooth-Zeichentablet, z. B. das Wacom Intuos. Android-Apps können Bluetooth-Eingaben empfangen, funktionieren aber nicht mit USB-Eingaben.

Ein Eingabestift-Ereignis wird als Touchscreen-Ereignis mit View.onTouchEvent() oder View.onGenericMotionEvent() gemeldet und enthält ein MotionEvent.getSource() vom Typ SOURCE_STYLUS. MotionEvent enthält auch zusätzliche Daten:

Historische Punkte

Android fasst Eingabeereignisse in Batches zusammen und stellt sie einmal pro Frame bereit. Ein Stift kann Ereignisse mit einer viel höheren Frequenz als das Display melden. Beim Erstellen von Zeichen-Apps ist es wichtig, mit den getHistorical-APIs nach Ereignissen zu suchen, die möglicherweise in der jüngsten Vergangenheit aufgetreten sind:

  • MotionEvent.getHistoricalX()
  • MotionEvent.getHistoricalY()
  • MotionEvent.getHistoricalPressure()
  • MotionEvent.getHistoricalAxisValue()

Handballenabweisung

ChromeOS versucht zu erkennen, wenn die Handfläche eines Nutzers auf dem Touchscreen aufliegt. Das ist jedoch nicht immer möglich. Manchmal wird ein Touch-Ereignis an die App gemeldet, bevor das Betriebssystem es als Handfläche erkennt. In diesem Fall werden Berührungen durch das Melden eines ACTION_CANCEL-Ereignisses abgebrochen.

Dieses Ereignis informiert die App darüber, dass bestimmte Berührungen ungültig sind und alle durch diese Berührungen ausgelösten Interaktionen rückgängig gemacht werden sollten. Eine Zeichen-App kann beispielsweise neue Linien vorübergehend zeichnen, sobald sie empfangen werden, um die Latenz zu minimieren. Sie werden aber erst dann dauerhaft auf der Zeichenfläche gespeichert, wenn die Touch-Serie sauber beendet wurde. Wenn Touch-Ereignisse in der Zwischenzeit abgebrochen werden, können die temporären Linien gelöscht werden.

Hinweis:Eine Möglichkeit, unerwünschte Handflächen- und Fingerereignisse in Zeichen- und Schreib-Apps zu reduzieren, besteht darin, eine UI-Einstellung anzubieten, mit der das Zeichnen per Fingerberührung deaktiviert wird. In diesem Modus werden dann nur Eingabestift-Ereignisse zum Zeichnen verwendet.

Notizen-Apps

ChromeOS hat eine spezielle Absicht, die registrierte Notizen-Apps für Nutzer sichtbar macht. Wenn Sie eine App als Notiz-App registrieren möchten, fügen Sie dem Android-Manifest Folgendes hinzu:

<intent-filter>
    <action android:name="org.chromium.arc.intent.action.CREATE_NOTE" />
    <category android:name="android.intent.category.DEFAULT" />
  </intent-filter>

Wenn eine App registriert ist, kann der Nutzer sie als Standard-App für Notizen auswählen. Wenn eine neue Notiz angefordert wird, sollte die App eine leere Notiz erstellen, die für die Stifteingabe bereit ist. Wenn der Nutzer ein Bild (z. B. einen Screenshot oder ein heruntergeladenes Bild) mit Anmerkungen versehen möchte, wird die App mit ClipData gestartet, das ein oder mehrere Elemente mit content://-URIs enthält. Die App sollte eine Notiz erstellen, in der das erste angehängte Bild als Hintergrundbild verwendet wird, und in einen Modus wechseln, in dem der Nutzer mit einem Stylus auf dem Bild zeichnen kann.

Notiz-Intents ohne Eingabestift testen

So testen Sie, ob eine App ohne aktiven Stylus korrekt auf Notiz-Intents reagiert:

  1. In den Entwicklermodus wechseln und das Gerät beschreibbar machen
  2. Drücke ctrl + alt + f2, um ein Terminal zu öffnen.
  3. Führen Sie den Befehl sudo vi /etc/chrome_dev.conf aus.
  4. Drücken Sie i, um die Datei zu bearbeiten, und fügen Sie --ash-enable-palette in einer neuen Zeile am Ende der Datei hinzu.
  5. Speichern Sie, indem Sie Esc drücken und dann :, w, q eingeben und Enter drücken.
  6. Drücke ctrl + alt + f1, um zur regulären ChromeOS-Benutzeroberfläche zurückzukehren.

Im Ablagefach sollte jetzt ein Stiftmenü angezeigt werden:

  • Tippen Sie in der Ablage auf die Stift-Schaltfläche und wählen Sie Neue Notiz aus. Dadurch sollte eine leere Zeichennotiz geöffnet werden.
  • Erstelle einen Screenshot. Wählen Sie im Ablagefach Stift-Schaltfläche > Bildschirm aufnehmen aus oder laden Sie ein Bild herunter. In der Benachrichtigung sollte die Option „Bild annotieren“ angezeigt werden. Dadurch sollte die App mit dem Bild gestartet werden, das annotiert werden soll.

Controller

Chromebooks unterstützen bis zu vier Gamecontroller. Entwickler sollten die standardmäßigen Android-Game Controller APIs verwenden, um sie zu verarbeiten.

Schaltflächen werden gemäß einer gemeinsamen Zuordnung gemeinsamen Werten zugeordnet. Leider folgen nicht alle Hersteller von Gamecontrollern denselben Zuordnungskonventionen. Sie können die Nutzerfreundlichkeit erheblich verbessern, wenn Sie Nutzern die Möglichkeit geben, verschiedene beliebte Controller-Belegungen auszuwählen.

Eingabeübersetzungsmodus

In ChromeOS ist standardmäßig ein Modus für die Eingabeübersetzung aktiviert. Bei den meisten Android-Apps sorgt dieser Modus dafür, dass die Apps in einer Desktopumgebung wie erwartet funktionieren. Beispiele hierfür sind das automatische Aktivieren des Scrollens mit zwei Fingern auf dem Touchpad, das Scrollen mit dem Mausrad und das Zuordnen von Rohkoordinaten des Displays zu Fensterkoordinaten. Im Allgemeinen müssen App-Entwickler keines dieser Verhaltensweisen selbst implementieren.

Wenn eine App benutzerdefiniertes Eingabeverhalten implementiert, z. B. eine benutzerdefinierte Zwei-Finger-Touchpad-Geste zum Verkleinern, oder diese Eingabeübersetzungen nicht die von der App erwarteten Eingabeereignisse liefern, können Sie den Eingabeübersetzungsmodus deaktivieren, indem Sie dem Android-Manifest das folgende Tag hinzufügen:

<uses-feature android:name="android.hardware.type.pc"
              android:required="false" />