Umgang mit Eingabeänderungen

Chromebooks bieten Nutzern viele verschiedene Eingabeoptionen: Tastatur, Maus, Trackpads, Touchscreens, Stift, MIDI und Gamepad/Bluetooth-Controller. So kann dasselbe Gerät als DJ-Station, als Leinwand für Künstler oder als bevorzugte Plattform für AAA-Streaming-Spiele dienen.

Als Entwickler haben Sie so die Möglichkeit, vielseitige und spannende App-Erlebnisse für Ihre Nutzer zu schaffen, die die Eingabegeräte nutzen, die sie bereits zur Verfügung haben – von einer angeschlossenen Tastatur über einen Stylus bis hin zu einem Stadia-Controller. Bei all diesen Möglichkeiten müssen Sie jedoch auch an Ihre Benutzeroberfläche denken, damit die Nutzung Ihrer App reibungslos und logisch ist. Das gilt insbesondere, wenn Ihre App oder Ihr Spiel für Smartphones entwickelt wurde. Wenn Ihr Spiel beispielsweise einen Touch-Joystick auf dem Bildschirm für Smartphones hat, möchten Sie diesen wahrscheinlich ausblenden, wenn ein Nutzer mit der Tastatur spielt.

Auf dieser Seite finden Sie die wichtigsten Probleme, die Sie bei der Verwendung mehrerer Quellen für Eingaben berücksichtigen sollten, sowie Strategien zur Bewältigung dieser Probleme.

Unterstützte Eingabemethoden für Nutzer

Im Idealfall reagiert Ihre App nahtlos auf alle Eingaben, die der Nutzer verwendet. Oft ist das ganz einfach und Sie müssen dem Nutzer keine zusätzlichen Informationen geben. Eine Schaltfläche sollte beispielsweise funktionieren, wenn der Nutzer mit einer Maus, einem Trackpad, dem Touchscreen oder einem Stift darauf klickt. Sie müssen den Nutzer nicht darauf hinweisen, dass er diese verschiedenen Geräte verwenden kann, um die Schaltfläche zu aktivieren.

Es gibt jedoch Situationen, in denen die Eingabemethode die Nutzerfreundlichkeit verbessern kann. In solchen Fällen ist es sinnvoll, die Nutzer darüber zu informieren, dass Ihre App die Eingabemethode unterstützt. Beispiele:

  • Eine App zur Medienwiedergabe kann viele praktische Tastenkombinationen unterstützen, die der Nutzer möglicherweise nicht so einfach erraten kann.
  • Wenn Sie eine DJ-App erstellt haben, verwendet der Nutzer möglicherweise zuerst den Touchscreen und merkt nicht, dass Sie ihm erlaubt haben, über die Tastatur/das Trackpad auf einige Funktionen zuzugreifen. Außerdem wissen sie vielleicht nicht, dass du eine Reihe von MIDI-DJ-Controllern unterstützt. Wenn du sie darauf hinweist, dass sie sich die unterstützte Hardware ansehen sollen, können sie vielleicht ein authentischeres DJ-Erlebnis genießen.
  • Ihr Spiel lässt sich vielleicht hervorragend über Touchscreen und Tastatur/Maus steuern, aber Nutzer wissen möglicherweise nicht, dass es auch eine Reihe von Bluetooth-Gamecontrollern unterstützt. Wenn Sie eine dieser Funktionen einbinden, kann sich das positiv auf die Nutzerzufriedenheit und das Nutzer-Engagement auswirken.

Sie können Nutzern helfen, Eingabeoptionen zu entdecken, indem Sie ihnen zu einem geeigneten Zeitpunkt entsprechende Hinweise geben. Die Implementierung sieht für jede App anders aus. Einige Beispiele:

  • Pop-ups für Erstnutzung oder Tipps des Tages
  • Konfigurationsoptionen in den Einstellungsbereichen können Nutzern passiv signalisieren, dass Support verfügbar ist. Wenn in den Einstellungen eines Spiels beispielsweise ein Tab „Controller“ vorhanden ist, werden Controller unterstützt.
  • Kontextbezogene Nachrichten Wenn Sie beispielsweise eine physische Tastatur erkennen und feststellen, dass der Nutzer eine Aktion mit einer Maus oder einem Touchscreen auslöst, können Sie einen hilfreichen Hinweis mit einem Tastenkürzel anzeigen.
  • Listen mit Tastenkombinationen. Wenn eine physische Tastatur erkannt wird, sollte in der Benutzeroberfläche darauf hingewiesen werden, dass eine Liste der verfügbaren Tastenkombinationen aufgerufen werden kann. So wird zum einen darauf aufmerksam gemacht, dass die Tastatur unterstützt wird, und zum anderen können Nutzer die unterstützten Tastenkombinationen leicht aufrufen und sich merken.

UI-Labeling/-Layout für Eingabevariation

Im Idealfall sollte sich die visuelle Benutzeroberfläche nicht wesentlich ändern, wenn ein anderes Eingabegerät verwendet wird. Alle möglichen Eingaben sollten einfach funktionieren. Es gibt jedoch wichtige Ausnahmen. Zwei der wichtigsten sind die berührungsspezifische Benutzeroberfläche und die Aufforderungen auf dem Bildschirm.

Für Touch optimierte Benutzeroberfläche

Wenn Ihre App berührungsspezifische UI-Elemente enthält, z.B. einen Joystick auf dem Bildschirm in einem Spiel, sollten Sie überlegen, wie die Nutzerfreundlichkeit aussieht, wenn keine Berührung verwendet wird. Bei einigen mobilen Spielen wird ein erheblicher Teil des Bildschirms von der Steuerung belegt, die für die Touchbedienung erforderlich ist, aber nicht, wenn der Nutzer ein Gamepad oder eine Tastatur verwendet. Ihre App oder Ihr Spiel sollte eine Logik enthalten, um zu erkennen, welche Eingabemethode aktiv verwendet wird, und die Benutzeroberfläche entsprechend anpassen. Im Implementierungsabschnitt unten finden Sie einige Beispiele dafür.

Benutzeroberflächen eines Autorennspiels – eine mit Steuerelementen auf dem Bildschirm und eine mit Tastatur

Aufforderungen auf dem Bildschirm

Ihre App bietet Nutzern möglicherweise hilfreiche Aufforderungen auf dem Bildschirm. Achten Sie darauf, dass sie nicht von Eingabegeräten abhängig sind. Beispiel:

  • Wische zu…
  • Tippe irgendwohin, um das Fenster zu schließen
  • Zwei-Finger-Zoom
  • Drücke „X“, um…
  • Zum Aktivieren lange drücken

Bei einigen Apps kann die Formulierung so angepasst werden, dass sie unabhängig von der Eingabe ist. Das ist vorzuziehen, wenn es sinnvoll ist. In vielen Fällen ist jedoch die Spezifität wichtig und Sie müssen möglicherweise je nach verwendeter Eingabemethode unterschiedliche Meldungen anzeigen, insbesondere in Tutorial-Modi wie beim ersten Start der App.

Überlegungen zu mehreren Sprachen

Wenn Ihre App mehrere Sprachen unterstützt, sollten Sie sich Gedanken über die String-Architektur machen. Wenn Sie beispielsweise drei Eingabemodi und fünf Sprachen unterstützen, kann das 15 verschiedene Versionen jeder UI-Meldung bedeuten. Dadurch wird der Aufwand für das Hinzufügen neuer Funktionen erhöht und die Wahrscheinlichkeit von Rechtschreibfehlern steigt.

Eine Möglichkeit besteht darin, sich Benutzeroberflächenaktionen als separate Gruppe von Strings vorzustellen. Wenn Sie beispielsweise die Aktion „Schließen“ als eigene String-Variable mit eingabespezifischen Varianten wie „Zum Schließen irgendwo tippen“, „Zum Schließen die Esc-Taste drücken“, „Zum Schließen irgendwo klicken“ oder „Zum Schließen eine beliebige Taste drücken“ definieren, können alle Ihre UI-Meldungen, in denen dem Nutzer mitgeteilt werden muss, wie er etwas schließen kann, diese einzelne String-Variable „Schließen“ verwenden. Wenn sich die Eingabemethode ändert, müssen Sie nur den Wert dieser einen Variablen ändern.

Eingabe über Bildschirmtastatur / IME

Wenn ein Nutzer eine App ohne physische Tastatur verwendet, kann die Texteingabe über eine Bildschirmtastatur erfolgen. Achten Sie darauf, dass die erforderlichen UI-Elemente nicht verdeckt werden, wenn eine Bildschirmtastatur angezeigt wird. Weitere Informationen finden Sie in der Dokumentation zur Sichtbarkeit von Android-IME.

Implementierung

In den meisten Fällen sollten Apps oder Spiele unabhängig davon, was auf dem Bildschirm angezeigt wird, korrekt auf alle gültigen Eingaben reagieren. Wenn ein Nutzer 10 Minuten lang den Touchscreen verwendet, dann aber plötzlich zur Tastatur wechselt, sollte die Tastatureingabe funktionieren, unabhängig von visuellen Aufforderungen oder Steuerelementen auf dem Bildschirm. Mit anderen Worten: Die Funktionalität sollte Vorrang vor visuellen Elementen und Text haben.So wird sichergestellt, dass Ihre App oder Ihr Spiel auch dann verwendet werden kann, wenn in der Logik zur Erkennung von Eingaben ein Fehler auftritt oder eine unerwartete Situation eintritt.

Im nächsten Schritt wird die richtige Benutzeroberfläche für die aktuell verwendete Eingabemethode angezeigt. Wie kann man das genau erkennen? Was passiert, wenn Nutzer beim Verwenden Ihrer App zwischen verschiedenen Eingabemethoden wechseln? Was ist, wenn mehrere Methoden gleichzeitig verwendet werden?

Priorisierte Statusmaschine basierend auf empfangenen Ereignissen

Ein Ansatz besteht darin, den aktuellen „aktiven Eingabestatus“ zu verfolgen, der die Eingabeaufforderungen darstellt, die dem Nutzer derzeit auf dem Bildschirm angezeigt werden. Dazu werden die tatsächlichen Eingabeereignisse, die von der App empfangen werden, erfasst und der Übergang zwischen den Status mithilfe einer priorisierten Logik gesteuert.

Priorisieren

Warum sollten Eingabestatus priorisiert werden? Nutzer interagieren auf unterschiedliche Weise mit ihren Geräten und Ihre App sollte ihre Auswahl unterstützen. Wenn ein Nutzer beispielsweise gleichzeitig den Touchscreen und eine Bluetooth-Maus verwendet, sollte das unterstützt werden. Welche Eingabeaufforderungen und Steuerelemente sollten auf dem Bildschirm angezeigt werden? Maus oder Touchscreen?

Wenn Sie jede Gruppe von Prompts als „Eingabestatus“ definieren und dann priorisieren, können Sie eine einheitliche Entscheidung treffen.

Der Status wird durch empfangene Eingabeereignisse bestimmt.

Warum werden nur empfangene Eingabeereignisse berücksichtigt? Sie könnten Bluetooth-Verbindungen im Blick behalten, um festzustellen, ob ein Bluetooth-Controller angeschlossen wurde, oder USB-Verbindungen nach USB-Geräten durchsuchen. Diese Vorgehensweise wird aus zwei Hauptgründen nicht empfohlen.

Erstens sind die Informationen, die Sie anhand von API-Variablen über verbundene Geräte erraten können, nicht konsistent und die Anzahl der Bluetooth-/Hardware-/Stiftgeräte wächst ständig.

Der zweite Grund, empfangene Ereignisse anstelle des Verbindungsstatus zu verwenden, ist, dass Nutzer möglicherweise eine Maus, einen Bluetooth-Controller, einen MIDI-Controller usw. angeschlossen haben, aber nicht aktiv damit interagieren, um mit Ihrer App oder Ihrem Spiel zu interagieren.

Wenn Sie auf Eingabeereignisse reagieren, die Ihre App aktiv empfangen hat, reagieren Sie in Echtzeit auf die tatsächlichen Aktionen Ihrer Nutzer und versuchen nicht, ihre Absichten mit unvollständigen Informationen zu erraten.

Beispiel: Spiel mit Unterstützung für Touch, Tastatur/Maus und Controller

Stellen Sie sich vor, Sie haben ein Autorennen-Spiel für Touchscreen-Mobiltelefone entwickelt. Spieler können beschleunigen, abbremsen, nach rechts oder links abbiegen oder Nitro für einen Geschwindigkeitsschub verwenden.

Die aktuelle Touchscreen-Oberfläche besteht aus einem On-Screen-Joystick unten links auf dem Display für die Geschwindigkeits- und Richtungssteuerung und einer Taste unten rechts für Nitro. Der Nutzer kann auf der Strecke Nitro-Kanister sammeln. Wenn die Nitro-Anzeige unten auf dem Bildschirm voll ist, wird über der Schaltfläche die Meldung „Für Nitro drücken!“ angezeigt. Wenn es das erste Spiel des Nutzers ist oder eine Weile keine Eingabe erfolgt, wird über dem Joystick ein Tutorial-Text angezeigt, der dem Nutzer zeigt, wie er das Auto bewegen kann.

Sie möchten Unterstützung für Tastatur und Bluetooth-Controller hinzufügen. Wo fangen Sie an?

Autorennspiel mit Touch-Steuerung

Eingabestatus

Beginnen Sie damit, alle Eingabestatus zu ermitteln, in denen Ihr Spiel ausgeführt werden kann, und listen Sie dann alle Parameter auf, die Sie in den einzelnen Status ändern möchten.

                                                                                                                                                                        
BerührungTastatur/MausSpiele-Controller
       

Reagiert auf

     
       

Alle Eingaben

     
       

Alle Eingaben

     
       

Alle Eingaben

     
       

Steuerelemente auf dem Bildschirm

     
       

– Joystick auf dem Bildschirm
– Nitro-Schaltfläche

     
       

– Kein Joystick
– Kein Nitro-Button

     
       

– Kein Joystick
– Kein Nitro-Button

     
       

Text

     
       

Tippe hier, um den Nitroantrieb zu aktivieren.

     
       

Drücke „N“ für Nitro!

     
       

Drücke „A“ für Nitro!

     
       

Tutorial

     
       

Bild eines Joysticks für Geschwindigkeit/Richtung

     
       

Bild von Pfeiltasten und WASD für Geschwindigkeit/Richtung

     
       

Bild eines Gamepads für Geschwindigkeit/Richtung

     

Behalten Sie den Status „aktive Eingabe“ im Blick und aktualisieren Sie die Benutzeroberfläche entsprechend.

Hinweis: Ihr Spiel/Ihre App sollte unabhängig vom Status auf alle Eingabemethoden reagieren. Wenn ein Nutzer das Auto beispielsweise über den Touchscreen steuert, aber auf der Tastatur die Taste „N“ drückt, sollte die Nitro-Aktion ausgelöst werden.

Priorisierte Statusänderungen

Einige Nutzer verwenden möglicherweise gleichzeitig den Touchscreen und die Tastatureingabe. Einige Nutzer beginnen vielleicht auf dem Sofa im Tabletmodus mit Ihrem Spiel oder Ihrer App und wechseln dann zum Tastaturmodus am Tisch. Andere verbinden oder trennen möglicherweise Gamecontroller während des Spiels.

Im Idealfall sollten keine falschen UI-Elemente angezeigt werden, z. B. wenn der Nutzer aufgefordert wird, die Taste N zu drücken, obwohl er den Touchscreen verwendet. Wenn Nutzer gleichzeitig mehrere Eingabegeräte wie Touchscreen und Tastatur verwenden, soll die Benutzeroberfläche nicht ständig zwischen den beiden Zuständen hin- und herwechseln.

Eine Möglichkeit, dies zu beheben, besteht darin, Prioritäten für den Eingabetyp festzulegen und eine Verzögerung zwischen den Statusänderungen einzubauen. Im obigen Beispiel für das Autospiel sollte der Joystick auf dem Bildschirm immer sichtbar sein, wenn Touch-Ereignisse empfangen werden. Andernfalls könnte das Spiel für den Nutzer unbrauchbar erscheinen. Dadurch wird der Touchscreen zum Gerät mit der höchsten Priorität.

Wenn Tastatur- und Touchscreen-Ereignisse gleichzeitig empfangen wurden, sollte das Spiel im Touchscreen-Modus bleiben, aber trotzdem auf Tastatureingaben reagieren. Wenn nach 5 Sekunden keine Touchscreen-Eingabe erfolgt und weiterhin Tastaturereignisse empfangen werden, werden die Steuerelemente auf dem Bildschirm möglicherweise ausgeblendet und das Spiel wechselt in den Tastaturstatus.

Die Eingabe über den Controller würde einem ähnlichen Muster folgen: Der UI-Status des Controllers hätte eine niedrigere Priorität als Tastatur/Maus und Touch und würde nur angezeigt, wenn Eingaben über den Controller und nicht andere Eingabeformen empfangen werden. Das Spiel reagierte immer auf Controller-Eingaben.

Unten sehen Sie ein Zustandsdiagramm und eine Übergangstabelle für das Beispiel. Passen Sie die Idee an Ihre App oder Ihr Spiel an.

Priorisierte Zustandsmaschine – Touchscreen, Tastatur/Maus, Gamecontroller

                                                                                                                                        
1. Touchscreen#2 Tastatur#3 Gamepad
       

Zu Nr. 1 wechseln

     
       

     
       

– Eingabe per Berührung empfangen
– Sofort zum Status „Eingabe per Berührung“ wechseln

     
       

– Eingabe per Berührung empfangen
– Sofort zum Status „Eingabe per Berührung“ wechseln

     
       

Zu Nummer 2 wechseln

     
       

– 5 Sekunden lang keine Berührung
– Tastatureingabe empfangen
– Wechsel zum Status „Tastatureingabe“

     
       

     
       

– Tastatureingabe empfangen
(sofort zum Status „Tastatureingabe“ wechseln)

     
       

Weiter zu Nummer 3

     
       

– 5 Sekunden lang keine Berührung
– 5 Sekunden lang keine Tastatureingabe
– Gamepad-Eingabe empfangen
– Zum Gamepad-Eingabestatus wechseln

     
       

– 5 Sekunden lang keine Tastatureingabe
– Gamepad-Eingabe empfangen
– Zum Status „Gamepad-Eingabe“ wechseln

     
       

     

Hinweis:Durch die Priorisierung wird deutlich, welche Art von Eingabe dominant sein sollte. Der Eingabestatus wird sofort in der Priorität „nach oben“ verschoben:

3. Gamepad -> 2. Tastatur –> 1. Berührung

sobald ein Gerät mit höherer Priorität verwendet wird. Die Priorität wird jedoch erst nach einer Verzögerungszeit und nur dann langsam gesenkt, wenn das Gerät mit niedrigerer Priorität aktiv verwendet wird.

Eingabe-Ereignisse

Hier finden Sie Beispielcode, der zeigt, wie Sie Eingabeereignisse von verschiedenen Arten von Eingabegeräten mit den Standard-Android-APIs erkennen. Verwenden Sie diese Ereignisse, um den Statusautomaten wie oben beschrieben zu steuern. Sie sollten das allgemeine Konzept an die Arten von Eingabeereignissen anpassen, die Sie erwarten, und an Ihre App oder Ihr Spiel.

Tasten auf der Tastatur und dem Controller

// Drive the state machine based on the received input type
// onKeyDown drives the state machine, but does not trigger game actions
// Both keyboard and game controller events come through as key events
override fun onKeyDown(keyCode: Int, event: KeyEvent?): Boolean {
    if (event != null) {
        // Check input source
        val outputMessage = when (event.source) {
            SOURCE_KEYBOARD -> {
                MyStateMachine.KeyboardEventReceived()
                "Keyboard event"
            }
            SOURCE_GAMEPAD -> {
                MyStateMachine.ControllerEventReceived()
                "Game controller event"
            }
            else -> "Other key event: ${event.source}"
        }
        // Do something based on source type
        findViewById(R.id.text_message).text = outputMessage
    }
    // Pass event up to system
    return super.onKeyDown(keyCode, event)
}
// Trigger game events based on key release
// Both keyboard and game controller events come through as key events
override fun onKeyUp(keyCode: Int, event: KeyEvent?): Boolean {
   when(keyCode) {
       KeyEvent.KEYCODE_N -> {
           MyStateMachine.keyboardEventReceived()
           engageNitro()
           return true // event handled here, return true
       }
   }
   // If event not handled, pass up to system
   return super.onKeyUp(keyCode, event)
}

Hinweis:Für KeyEvents können Sie entweder onKeyDown() oder onKeyUp() verwenden. onKeyDown() wird zur Steuerung des Zustandsautomaten verwendet, während onKeyUp() zum Auslösen von Spielereignissen verwendet wird.

Wenn ein Nutzer eine Taste gedrückt hält, wird onKeyUp() nur einmal pro Tastendruck ausgelöst, während onKeyDown() mehrmals aufgerufen wird. Wenn Sie auf das Drücken nach unten reagieren möchten, sollten Sie Spielereignisse in onKeyDown() verarbeiten und eine Logik implementieren, um die wiederholten Ereignisse zu verarbeiten. Weitere Informationen finden Sie in der Dokumentation unter Tastaturaktionen verarbeiten.

Touch- und Eingabestift-Bedienung

// Touch and stylus events come through as touch events
override fun onTouchEvent(event: MotionEvent?): Boolean {
   if (event != null) {
       // Get tool type
       val pointerIndex = event.action and ACTION_POINTER_INDEX_MASK shr ACTION_POINTER_INDEX_SHIFT
       val toolType = event.getToolType(pointerIndex)

       // Check tool type
       val outputMessage = when (toolType) {
           TOOL_TYPE_FINGER -> {
               MyStateMachine.TouchEventReceived()
               "Touch event"
           }
           TOOL_TYPE_STYLUS -> {
                MyStateMachine.StylusEventReceived()
               "Stylus event"
           }
           else -> "Other touch event: ${toolType}"
       }

       // Do something based on tool type, return true if event handled
       findViewById(R.id.text_message).text = outputMessage
   }
   // If event not handled, pass up to system
   return super.onGenericMotionEvent(event)
}

Maus und Joystick

// Mouse and joystick events come through as generic events
override fun onGenericMotionEvent(event: MotionEvent?): Boolean {
   if (event != null) {
       // Check input source
       val outputMessage = when (event.source) {
           SOURCE_JOYSTICK -> {
                MyStateMachine.ControllerEventReceived()
               "Controller event"
           }
           SOURCE_MOUSE -> {
                MyStateMachine.MouseEventReceived()
               "Mouse event"
           }
           else -> "Other generic event: ${event.source}"
       }
       // Do something based on source type, return true if event handled
       findViewById(R.id.text_message).text = outputMessage
   }
   // If event not handled, pass up to system
   return super.onGenericMotionEvent(event)
}