Input compatibility

On ChromeOS devices, many users interact with apps using a keyboard, mouse,
trackpad, stylus, or gamepad. While these input devices are also used on Android
phones, they are not as common and are often overlooked by developers.

Developers who want their app to work well with input on ChromeOS, and other
large screen Android capable devices, should look at the
following optimizations:

The way your app responds to keyboard input contributes to a good desktop
experience. There are three kinds of keyboard input: Navigation,
Keystrokes, and Shortcuts.

Mục lục bài viết

Keyboard navigation is rarely implemented in touch-centric apps, but users
expect it when they are using an app and have their hands on a keyboard.
It can also be essential for users with accessibility needs on both phones
and desktop devices.

For many apps, simple arrow key and tab navigation is all that is needed and is
mostly handled automatically by the Android framework. For example, a view of
a Button is focusable by default, and keyboard navigation should generally
work without any additional code. In order to enable keyboard navigation for
views that are not focusable by default, developers should mark them as
focusable. This can be done programmatically or in XML, as shown below. See the
Focus Handling⁠
documentation for more information.

Kotlin

yourView

.

isFocusable

=

true

Alternatively you can set the focusable attribute in your layout file:

XML

android:focusable="true"

Once focus is enabled, the Android framework will create a navigational mapping
for all focusable views based on their position. This usually works as expected
and no further work is needed. When the default mapping is not correct for an
app’s needs, it can be overridden as follows:

Kotlin

 
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 yourView

.

nextFocusForwardId

=

R

.

id

.

next_view

It is good practice to try to access every piece of your app’s functionality
before each release using the keyboard only. It should be easy to access the
most common actions without mouse of touch input.

Remember, keyboard support might be essential for users with accessibility needs.

Keystrokes

For text input that would be handled by an on-screen virtual keyboard
(IME⁠) such as an EditText,
apps should behave as expected on ChromeOS with no additional work from the
developer. For keystrokes that cannot be anticipated by the framework, apps
will need to handle the behavior themselves. This is especially true for apps
with custom views.

Some examples are chat apps that use the enter key to send a message,
media apps that start/stop playback with the space key, and games that control
movement with the w,a,s, and d keys.

Most apps override the
onKeyUp⁠
event and add the expected behavior for each received keycode, as shown below.

Kotlin

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

)

}

}

Using onKeyUp prevents apps from receiving multiple events if a key is held
down or released slowly. Games and apps that expect users to hold down keyboard
keys can look for the
onKeyDown⁠
event.

Depending on an app’s needs, overriding onKeyUp for the entire Activity
usually provides the needed behavior. If desired, an
onKeyListener⁠ can be added to a
specific view instead. For example an app may only listen for the Enter key in
specific EditText, and not the Activity, in order to implement send
functionality only when the user is typing in a chat box.

When you add keyboard support, follow the Android
Keyboard handling documentation⁠.

Shortcuts

Common Ctrl, Alt, and Shift-based shortcuts are expected in desktop
environments. If an app does not implement them, the experience can feel
frustrating and broken to users. Advanced users also
appreciate shortcuts for frequently used app-specific tasks. Shortcuts make an
app easier to use and differentiate it from apps that don’t have shortcuts.

Some common shortcuts include save (Ctrl+S), undo (Ctrl+Z), and
redo (Ctrl+Shift+Z). For an example of some more advanced shortcuts, see the
list of
VLC Media Player shortcut keys⁠.

Shortcuts can be implemented using
dispatchKeyShortcutEvent⁠.
This intercepts all meta-key combinations (Alt, Ctrl, and Shift) for a given
keycode. To check for a specific meta-key, use
KeyEvent.isCtrlPressed()⁠,
KeyEvent.isShiftPressed()⁠,
KeyEvent.isAltPressed()⁠,
or KeyEvent.hasModifiers()⁠.

Separating shortcut code from other keystroke handling (such as onKeyUp or
onKeyDown) can make code maintenance easier and maintains the default acceptance
of meta-keys without having to manually implement meta-key checks in every case.
Allowing all meta-key combinations can also be more convenient for users who
are accustomed to different keyboard layouts and operating systems.

Kotlin

override

fun

dispatchKeyShortcutEvent

(

event

:

KeyEvent

)

:

Boolean

{

return

when

(

event

.

keyCode

)

{

KeyEvent

.

KEYCODE_O

->

{

openFile

(

)

true

}

KeyEvent

.

KEYCODE_Z

->

{

if

(

event

.

isCtrlPressed

)

{

if

(

event

.

isShiftPressed

)

{

redoLastAction

(

)

true

}

else

{

undoLastAction

(

)

true

}

}

}

else

->

{

return

super

.

dispatchKeyShortcutEvent

(

event

)

}

}

}

You can also implement shortcuts in onKeyUp by checking for
KeyEvent.isCtrlPressed()⁠,
KeyEvent.isShiftPressed()⁠,
or KeyEvent.isAltPressed()⁠
in the same manner as above. This can be easier to maintain if the meta-behavior
is more of a modification to an app behavior than a shortcut. For example, when
W means “walk forward” and Shift+W means “run forward”.

Kotlin

override

fun

onKeyUp

(

keyCode

:

Int

,

event

:

KeyEvent

)

:

Boolean

{

return

when

(

keyCode

)

{

KeyEvent

.

KEYCODE_W

->

{

if

(

event

.

isShiftPressed

)

{

if

(

event

.

isCtrlPressed

)

{

flyForward

(

)

true

}

else

{

runForward

(

)

true

}

}

else

{

walkForward

(

)

}

}

else

->

super

.

onKeyUp

(

keyCode

,

event

)

}

}