Search code examples
androidunicodeandroid-custom-viewkeycodecontrol-characters

Differentiating text keycode from control keycode in Android KeyEvent


There are 284 KeyEvent key codes. Some of them represent Unicode characters (like KEYCODE_A and KEYCODE_1), while others represent control characters (like KEYCODE_DEL).

I am making a custom view that handles keyboard input. It gets most of its input from an Input Connection, but sometimes keyboards send key codes (normall associated with hard keyboard input). I need to handle that, too. Do I need to exhaustively handle every control key code and then convert the rest to text (with (char) event.getUnicodeChar()) or is there a built in way to differentiate the text codes from the control codes?


Solution

  • The KeyEvent.getUnicodeChar() documentation says

    Returns 0 if the key is not one that is used to type Unicode characters.

    Thus it is easy to differentiate text codes from control codes like this:

    if (keyEvent.getUnicodeChar() != 0) {
        // unicode text
        char unicodeChar = (char) keyEvent.getUnicodeChar();
    } else {
        // control char
    }
    

    Here is a list that helped me reach this conclution:

    // keyCode, Unicode, char, keyCode name
    
    0   0   ��  KEYCODE_UNKNOWN
    1   0   ��  KEYCODE_SOFT_LEFT
    2   0   ��  KEYCODE_SOFT_RIGHT
    3   0   ��  KEYCODE_HOME
    4   0   ��  KEYCODE_BACK
    5   0   ��  KEYCODE_CALL
    6   0   ��  KEYCODE_ENDCALL
    7   48  0   KEYCODE_0
    8   49  1   KEYCODE_1
    9   50  2   KEYCODE_2
    10  51  3   KEYCODE_3
    11  52  4   KEYCODE_4
    12  53  5   KEYCODE_5
    13  54  6   KEYCODE_6
    14  55  7   KEYCODE_7
    15  56  8   KEYCODE_8
    16  57  9   KEYCODE_9
    17  42  *   KEYCODE_STAR
    18  35  #   KEYCODE_POUND
    19  0   ��  KEYCODE_DPAD_UP
    20  0   ��  KEYCODE_DPAD_DOWN
    21  0   ��  KEYCODE_DPAD_LEFT
    22  0   ��  KEYCODE_DPAD_RIGHT
    23  0   ��  KEYCODE_DPAD_CENTER
    24  0   ��  KEYCODE_VOLUME_UP
    25  0   ��  KEYCODE_VOLUME_DOWN
    26  0   ��  KEYCODE_POWER
    27  0   ��  KEYCODE_CAMERA
    28  0   ��  KEYCODE_CLEAR
    29  97  a   KEYCODE_A
    30  98  b   KEYCODE_B
    31  99  c   KEYCODE_C
    32  100 d   KEYCODE_D
    33  101 e   KEYCODE_E
    34  102 f   KEYCODE_F
    35  103 g   KEYCODE_G
    36  104 h   KEYCODE_H
    37  105 i   KEYCODE_I
    38  106 j   KEYCODE_J
    39  107 k   KEYCODE_K
    40  108 l   KEYCODE_L
    41  109 m   KEYCODE_M
    42  110 n   KEYCODE_N
    43  111 o   KEYCODE_O
    44  112 p   KEYCODE_P
    45  113 q   KEYCODE_Q
    46  114 r   KEYCODE_R
    47  115 s   KEYCODE_S
    48  116 t   KEYCODE_T
    49  117 u   KEYCODE_U
    50  118 v   KEYCODE_V
    51  119 w   KEYCODE_W
    52  120 x   KEYCODE_X
    53  121 y   KEYCODE_Y
    54  122 z   KEYCODE_Z
    55  44  ,   KEYCODE_COMMA
    56  46  .   KEYCODE_PERIOD
    57  0   ��  KEYCODE_ALT_LEFT
    58  0   ��  KEYCODE_ALT_RIGHT
    59  0   ��  KEYCODE_SHIFT_LEFT
    60  0   ��  KEYCODE_SHIFT_RIGHT
    61  9       KEYCODE_TAB
    62  32      KEYCODE_SPACE
    63  0   ��  KEYCODE_SYM
    64  0   ��  KEYCODE_EXPLORER
    65  0   ��  KEYCODE_ENVELOPE
    66  10      KEYCODE_ENTER
    67  0   ��  KEYCODE_DEL
    68  96  `   KEYCODE_GRAVE
    69  45  -   KEYCODE_MINUS
    70  61  =   KEYCODE_EQUALS
    71  91  [   KEYCODE_LEFT_BRACKET
    72  93  ]   KEYCODE_RIGHT_BRACKET
    73  92  \   KEYCODE_BACKSLASH
    74  59  ;   KEYCODE_SEMICOLON
    75  39  '   KEYCODE_APOSTROPHE
    76  47  /   KEYCODE_SLASH
    77  64  @   KEYCODE_AT
    78  0   ��  KEYCODE_NUM
    79  0   ��  KEYCODE_HEADSETHOOK
    80  0   ��  KEYCODE_FOCUS
    81  43  +   KEYCODE_PLUS
    82  0   ��  KEYCODE_MENU
    83  0   ��  KEYCODE_NOTIFICATION
    84  0   ��  KEYCODE_SEARCH
    85  0   ��  KEYCODE_MEDIA_PLAY_PAUSE
    86  0   ��  KEYCODE_MEDIA_STOP
    87  0   ��  KEYCODE_MEDIA_NEXT
    88  0   ��  KEYCODE_MEDIA_PREVIOUS
    89  0   ��  KEYCODE_MEDIA_REWIND
    90  0   ��  KEYCODE_MEDIA_FAST_FORWARD
    91  0   ��  KEYCODE_MUTE
    92  0   ��  KEYCODE_PAGE_UP
    93  0   ��  KEYCODE_PAGE_DOWN
    94  0   ��  KEYCODE_PICTSYMBOLS
    95  0   ��  KEYCODE_SWITCH_CHARSET
    96  0   ��  KEYCODE_BUTTON_A
    97  0   ��  KEYCODE_BUTTON_B
    98  0   ��  KEYCODE_BUTTON_C
    99  0   ��  KEYCODE_BUTTON_X
    100 0   ��  KEYCODE_BUTTON_Y
    101 0   ��  KEYCODE_BUTTON_Z
    102 0   ��  KEYCODE_BUTTON_L1
    103 0   ��  KEYCODE_BUTTON_R1
    104 0   ��  KEYCODE_BUTTON_L2
    105 0   ��  KEYCODE_BUTTON_R2
    106 0   ��  KEYCODE_BUTTON_THUMBL
    107 0   ��  KEYCODE_BUTTON_THUMBR
    108 0   ��  KEYCODE_BUTTON_START
    109 0   ��  KEYCODE_BUTTON_SELECT
    110 0   ��  KEYCODE_BUTTON_MODE
    111 0   ��  KEYCODE_ESCAPE
    112 0   ��  KEYCODE_FORWARD_DEL
    113 0   ��  KEYCODE_CTRL_LEFT
    114 0   ��  KEYCODE_CTRL_RIGHT
    115 0   ��  KEYCODE_CAPS_LOCK
    116 0   ��  KEYCODE_SCROLL_LOCK
    117 0   ��  KEYCODE_META_LEFT
    118 0   ��  KEYCODE_META_RIGHT
    119 0   ��  KEYCODE_FUNCTION
    120 0   ��  KEYCODE_SYSRQ
    121 0   ��  KEYCODE_BREAK
    122 0   ��  KEYCODE_MOVE_HOME
    123 0   ��  KEYCODE_MOVE_END
    124 0   ��  KEYCODE_INSERT
    125 0   ��  KEYCODE_FORWARD
    126 0   ��  KEYCODE_MEDIA_PLAY
    127 0   ��  KEYCODE_MEDIA_PAUSE
    128 0   ��  KEYCODE_MEDIA_CLOSE
    129 0   ��  KEYCODE_MEDIA_EJECT
    130 0   ��  KEYCODE_MEDIA_RECORD
    131 0   ��  KEYCODE_F1
    132 0   ��  KEYCODE_F2
    133 0   ��  KEYCODE_F3
    134 0   ��  KEYCODE_F4
    135 0   ��  KEYCODE_F5
    136 0   ��  KEYCODE_F6
    137 0   ��  KEYCODE_F7
    138 0   ��  KEYCODE_F8
    139 0   ��  KEYCODE_F9
    140 0   ��  KEYCODE_F10
    141 0   ��  KEYCODE_F11
    142 0   ��  KEYCODE_F12
    143 0   ��  KEYCODE_NUM_LOCK
    144 0   ��  KEYCODE_NUMPAD_0
    145 0   ��  KEYCODE_NUMPAD_1
    146 0   ��  KEYCODE_NUMPAD_2
    147 0   ��  KEYCODE_NUMPAD_3
    148 0   ��  KEYCODE_NUMPAD_4
    149 0   ��  KEYCODE_NUMPAD_5
    150 0   ��  KEYCODE_NUMPAD_6
    151 0   ��  KEYCODE_NUMPAD_7
    152 0   ��  KEYCODE_NUMPAD_8
    153 0   ��  KEYCODE_NUMPAD_9
    154 47  /   KEYCODE_NUMPAD_DIVIDE
    155 42  *   KEYCODE_NUMPAD_MULTIPLY
    156 45  -   KEYCODE_NUMPAD_SUBTRACT
    157 43  +   KEYCODE_NUMPAD_ADD
    158 0   ��  KEYCODE_NUMPAD_DOT
    159 44  ,   KEYCODE_NUMPAD_COMMA
    160 10      KEYCODE_NUMPAD_ENTER
    161 61  =   KEYCODE_NUMPAD_EQUALS
    162 40  (   KEYCODE_NUMPAD_LEFT_PAREN
    163 41  )   KEYCODE_NUMPAD_RIGHT_PAREN
    164 0   ��  KEYCODE_VOLUME_MUTE
    165 0   ��  KEYCODE_INFO
    166 0   ��  KEYCODE_CHANNEL_UP
    167 0   ��  KEYCODE_CHANNEL_DOWN
    168 0   ��  KEYCODE_ZOOM_IN
    169 0   ��  KEYCODE_ZOOM_OUT
    170 0   ��  KEYCODE_TV
    171 0   ��  KEYCODE_WINDOW
    172 0   ��  KEYCODE_GUIDE
    173 0   ��  KEYCODE_DVR
    174 0   ��  KEYCODE_BOOKMARK
    175 0   ��  KEYCODE_CAPTIONS
    176 0   ��  KEYCODE_SETTINGS
    177 0   ��  KEYCODE_TV_POWER
    178 0   ��  KEYCODE_TV_INPUT
    179 0   ��  KEYCODE_STB_POWER
    180 0   ��  KEYCODE_STB_INPUT
    181 0   ��  KEYCODE_AVR_POWER
    182 0   ��  KEYCODE_AVR_INPUT
    183 0   ��  KEYCODE_PROG_RED
    184 0   ��  KEYCODE_PROG_GREEN
    185 0   ��  KEYCODE_PROG_YELLOW
    186 0   ��  KEYCODE_PROG_BLUE
    187 0   ��  KEYCODE_APP_SWITCH
    188 0   ��  KEYCODE_BUTTON_1
    189 0   ��  KEYCODE_BUTTON_2
    190 0   ��  KEYCODE_BUTTON_3
    191 0   ��  KEYCODE_BUTTON_4
    192 0   ��  KEYCODE_BUTTON_5
    193 0   ��  KEYCODE_BUTTON_6
    194 0   ��  KEYCODE_BUTTON_7
    195 0   ��  KEYCODE_BUTTON_8
    196 0   ��  KEYCODE_BUTTON_9
    197 0   ��  KEYCODE_BUTTON_10
    198 0   ��  KEYCODE_BUTTON_11
    199 0   ��  KEYCODE_BUTTON_12
    200 0   ��  KEYCODE_BUTTON_13
    201 0   ��  KEYCODE_BUTTON_14
    202 0   ��  KEYCODE_BUTTON_15
    203 0   ��  KEYCODE_BUTTON_16
    204 0   ��  KEYCODE_LANGUAGE_SWITCH
    205 0   ��  KEYCODE_MANNER_MODE
    206 0   ��  KEYCODE_3D_MODE
    207 0   ��  KEYCODE_CONTACTS
    208 0   ��  KEYCODE_CALENDAR
    209 0   ��  KEYCODE_MUSIC
    210 0   ��  KEYCODE_CALCULATOR
    211 0   ��  KEYCODE_ZENKAKU_HANKAKU
    212 0   ��  KEYCODE_EISU
    213 0   ��  KEYCODE_MUHENKAN
    214 0   ��  KEYCODE_HENKAN
    215 0   ��  KEYCODE_KATAKANA_HIRAGANA
    216 0   ��  KEYCODE_YEN
    217 0   ��  KEYCODE_RO
    218 0   ��  KEYCODE_KANA
    219 0   ��  KEYCODE_ASSIST
    220 0   ��  KEYCODE_BRIGHTNESS_DOWN
    221 0   ��  KEYCODE_BRIGHTNESS_UP
    222 0   ��  KEYCODE_MEDIA_AUDIO_TRACK
    223 0   ��  KEYCODE_SLEEP
    224 0   ��  KEYCODE_WAKEUP
    225 0   ��  KEYCODE_PAIRING
    226 0   ��  KEYCODE_MEDIA_TOP_MENU
    227 0   ��  KEYCODE_11
    228 0   ��  KEYCODE_12
    229 0   ��  KEYCODE_LAST_CHANNEL
    230 0   ��  KEYCODE_TV_DATA_SERVICE
    231 0   ��  KEYCODE_VOICE_ASSIST
    232 0   ��  KEYCODE_TV_RADIO_SERVICE
    233 0   ��  KEYCODE_TV_TELETEXT
    234 0   ��  KEYCODE_TV_NUMBER_ENTRY
    235 0   ��  KEYCODE_TV_TERRESTRIAL_ANALOG
    236 0   ��  KEYCODE_TV_TERRESTRIAL_DIGITAL
    237 0   ��  KEYCODE_TV_SATELLITE
    238 0   ��  KEYCODE_TV_SATELLITE_BS
    239 0   ��  KEYCODE_TV_SATELLITE_CS
    240 0   ��  KEYCODE_TV_SATELLITE_SERVICE
    241 0   ��  KEYCODE_TV_NETWORK
    242 0   ��  KEYCODE_TV_ANTENNA_CABLE
    243 0   ��  KEYCODE_TV_INPUT_HDMI_1
    244 0   ��  KEYCODE_TV_INPUT_HDMI_2
    245 0   ��  KEYCODE_TV_INPUT_HDMI_3
    246 0   ��  KEYCODE_TV_INPUT_HDMI_4
    247 0   ��  KEYCODE_TV_INPUT_COMPOSITE_1
    248 0   ��  KEYCODE_TV_INPUT_COMPOSITE_2
    249 0   ��  KEYCODE_TV_INPUT_COMPONENT_1
    250 0   ��  KEYCODE_TV_INPUT_COMPONENT_2
    251 0   ��  KEYCODE_TV_INPUT_VGA_1
    252 0   ��  KEYCODE_TV_AUDIO_DESCRIPTION
    253 0   ��  KEYCODE_TV_AUDIO_DESCRIPTION_MIX_UP
    254 0   ��  KEYCODE_TV_AUDIO_DESCRIPTION_MIX_DOWN
    255 0   ��  KEYCODE_TV_ZOOM_MODE
    256 0   ��  KEYCODE_TV_CONTENTS_MENU
    257 0   ��  KEYCODE_TV_MEDIA_CONTEXT_MENU
    258 0   ��  KEYCODE_TV_TIMER_PROGRAMMING
    259 0   ��  KEYCODE_HELP
    260 0   ��  KEYCODE_NAVIGATE_PREVIOUS
    261 0   ��  KEYCODE_NAVIGATE_NEXT
    262 0   ��  KEYCODE_NAVIGATE_IN
    263 0   ��  KEYCODE_NAVIGATE_OUT
    264 0   ��  KEYCODE_STEM_PRIMARY
    265 0   ��  KEYCODE_STEM_1
    266 0   ��  KEYCODE_STEM_2
    267 0   ��  KEYCODE_STEM_3
    268 0   ��  KEYCODE_DPAD_UP_LEFT
    269 0   ��  KEYCODE_DPAD_DOWN_LEFT
    270 0   ��  KEYCODE_DPAD_UP_RIGHT
    271 0   ��  KEYCODE_DPAD_DOWN_RIGHT
    272 0   ��  KEYCODE_MEDIA_SKIP_FORWARD
    273 0   ��  KEYCODE_MEDIA_SKIP_BACKWARD
    274 0   ��  KEYCODE_MEDIA_STEP_FORWARD
    275 0   ��  KEYCODE_MEDIA_STEP_BACKWARD
    276 0   ��  KEYCODE_SOFT_SLEEP
    277 0   ��  KEYCODE_CUT
    278 0   ��  KEYCODE_COPY
    279 0   ��  KEYCODE_PASTE
    280 0   ��  KEYCODE_SYSTEM_NAVIGATION_UP
    281 0   ��  KEYCODE_SYSTEM_NAVIGATION_DOWN
    282 0   ��  KEYCODE_SYSTEM_NAVIGATION_LEFT
    283 0   ��  KEYCODE_SYSTEM_NAVIGATION_RIGHT
    

    Dead keys

    Note that it might also be necessary to take dead keys into account. The docs say

    The system recognizes the following Unicode characters as combining diacritical dead key characters.

    • '\u0300': Grave accent.
    • '\u0301': Acute accent.
    • '\u0302': Circumflex accent.
    • '\u0303': Tilde accent.
    • '\u0308': Umlaut accent.

    When a dead key is typed followed by another character, the dead key and the following characters are composed. For example, when the user types a grave accent dead key followed by the letter 'a', the result is 'à'.

    To get the dead key a combination of KeyEvent.getDeadChar(), COMBINING_ACCENT, and COMBINING_ACCENT_MASK are used. The following method is used in many open source projects to send hard key events on to the InputConnection.

    /**
     * This translates incoming hard key events in to edit operations on an
     * InputConnection.  It is only needed when using the
     * PROCESS_HARD_KEYS option.
     */
    private boolean translateKeyDown(int keyCode, KeyEvent event) {
        mMetaState = MetaKeyKeyListener.handleKeyDown(mMetaState,
                keyCode, event);
        int c = event.getUnicodeChar(MetaKeyKeyListener.getMetaState(mMetaState));
        mMetaState = MetaKeyKeyListener.adjustMetaAfterKeypress(mMetaState);
        InputConnection ic = getCurrentInputConnection();
        if (c == 0 || ic == null) {
            return false;
        }
    
        boolean dead = false;
    
        if ((c & KeyCharacterMap.COMBINING_ACCENT) != 0) {
            dead = true;
            c = c & KeyCharacterMap.COMBINING_ACCENT_MASK;
        }
    
        if (mComposing.length() > 0) {
            char accent = mComposing.charAt(mComposing.length() -1 );
            int composed = KeyEvent.getDeadChar(accent, c);
    
            if (composed != 0) {
                c = composed;
                mComposing.setLength(mComposing.length()-1);
            }
        }
    
        onKey(c, null);
    
        return true;
    }
    

    Another way?

    @pskink mentions TextKeyListener, BaseKeyListener and KeyListener. These may very well be a better way to go. However, I was unable to find adequate explanation and examples of how to use them.