1/*
2 * Copyright (C) 2013 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.terminal;
18
19import android.util.Log;
20import android.view.KeyCharacterMap;
21import android.view.KeyEvent;
22import android.view.View;
23
24public class TerminalKeys {
25    private static final String TAG = "TerminalKeys";
26    private static final boolean DEBUG = true;
27    // Taken from vterm_input.h
28    // TODO: Consider setting these via jni
29    public static final int VTERM_KEY_NONE      = 0;
30    public static final int VTERM_KEY_ENTER     = 1;
31    public static final int VTERM_KEY_TAB       = 2;
32    public static final int VTERM_KEY_BACKSPACE = 3;
33    public static final int VTERM_KEY_ESCAPE    = 4;
34    public static final int VTERM_KEY_UP        = 5;
35    public static final int VTERM_KEY_DOWN      = 6;
36    public static final int VTERM_KEY_LEFT      = 7;
37    public static final int VTERM_KEY_RIGHT     = 8;
38    public static final int VTERM_KEY_INS       = 9;
39    public static final int VTERM_KEY_DEL       = 10;
40    public static final int VTERM_KEY_HOME      = 11;
41    public static final int VTERM_KEY_END       = 12;
42    public static final int VTERM_KEY_PAGEUP    = 13;
43    public static final int VTERM_KEY_PAGEDOWN  = 14;
44
45    public static final int VTERM_KEY_FUNCTION_0   = 256;
46    public static final int VTERM_KEY_FUNCTION_MAX = VTERM_KEY_FUNCTION_0 + 255;
47
48    public static final int VTERM_KEY_KP_0 = 512;
49    public static final int VTERM_KEY_KP_1 = 513;
50    public static final int VTERM_KEY_KP_2 = 514;
51    public static final int VTERM_KEY_KP_3 = 515;
52    public static final int VTERM_KEY_KP_4 = 516;
53    public static final int VTERM_KEY_KP_5 = 517;
54    public static final int VTERM_KEY_KP_6 = 518;
55    public static final int VTERM_KEY_KP_7 = 519;
56    public static final int VTERM_KEY_KP_8 = 520;
57    public static final int VTERM_KEY_KP_9 = 521;
58    public static final int VTERM_KEY_KP_MULT = 522;
59    public static final int VTERM_KEY_KP_PLUS = 523;
60    public static final int VTERM_KEY_KP_COMMA = 524;
61    public static final int VTERM_KEY_KP_MINUS = 525;
62    public static final int VTERM_KEY_KP_PERIOD = 526;
63    public static final int VTERM_KEY_KP_DIVIDE = 527;
64    public static final int VTERM_KEY_KP_ENTER = 528;
65    public static final int VTERM_KEY_KP_EQUAL = 529;
66
67    public static final int VTERM_MOD_NONE = 0x00;
68    public static final int VTERM_MOD_SHIFT = 0x01;
69    public static final int VTERM_MOD_ALT = 0x02;
70    public static final int VTERM_MOD_CTRL = 0x04;
71
72    private Terminal mTerm;
73
74    public static int getModifiers(KeyEvent event) {
75        int mod = 0;
76        if (event.isCtrlPressed()) {
77            mod |= VTERM_MOD_CTRL;
78        }
79        if (event.isAltPressed()) {
80            mod |= VTERM_MOD_ALT;
81        }
82        if (event.isShiftPressed()) {
83            mod |= VTERM_MOD_SHIFT;
84        }
85        return mod;
86    }
87
88    public static int getKey(KeyEvent event) {
89        switch(event.getKeyCode()) {
90            case KeyEvent.KEYCODE_ENTER:
91                return VTERM_KEY_ENTER;
92            case KeyEvent.KEYCODE_TAB:
93                return VTERM_KEY_TAB;
94            case KeyEvent.KEYCODE_DEL:
95                return VTERM_KEY_BACKSPACE;
96            case KeyEvent.KEYCODE_ESCAPE:
97                return VTERM_KEY_ESCAPE;
98            case KeyEvent.KEYCODE_DPAD_UP:
99                return VTERM_KEY_UP;
100            case KeyEvent.KEYCODE_DPAD_DOWN:
101                return VTERM_KEY_DOWN;
102            case KeyEvent.KEYCODE_DPAD_LEFT:
103                return VTERM_KEY_LEFT;
104            case KeyEvent.KEYCODE_DPAD_RIGHT:
105                return VTERM_KEY_RIGHT;
106            case KeyEvent.KEYCODE_INSERT:
107                return VTERM_KEY_INS;
108            case KeyEvent.KEYCODE_FORWARD_DEL:
109                return VTERM_KEY_DEL;
110            case KeyEvent.KEYCODE_MOVE_HOME:
111                return VTERM_KEY_HOME;
112            case KeyEvent.KEYCODE_MOVE_END:
113                return VTERM_KEY_END;
114            case KeyEvent.KEYCODE_PAGE_UP:
115                return VTERM_KEY_PAGEUP;
116            case KeyEvent.KEYCODE_PAGE_DOWN:
117                return VTERM_KEY_PAGEDOWN;
118            default:
119                return 0;
120        }
121    }
122
123    public static String getKeyName(int key) {
124        switch(key) {
125            case VTERM_KEY_ENTER:
126                return "VTERM_KEY_ENTER";
127            case VTERM_KEY_TAB:
128                return "VTERM_KEY_TAB";
129            case VTERM_KEY_BACKSPACE:
130                return "VTERM_KEY_BACKSPACE";
131            case VTERM_KEY_ESCAPE:
132                return "VTERM_KEY_ESCAPE";
133            case VTERM_KEY_UP:
134                return "VTERM_KEY_UP";
135            case VTERM_KEY_DOWN:
136                return "VTERM_KEY_DOWN";
137            case VTERM_KEY_LEFT:
138                return "VTERM_KEY_LEFT";
139            case VTERM_KEY_RIGHT:
140                return "VTERM_KEY_RIGHT";
141            case VTERM_KEY_INS:
142                return "VTERM_KEY_INS";
143            case VTERM_KEY_DEL:
144                return "VTERM_KEY_DEL";
145            case VTERM_KEY_HOME:
146                return "VTERM_KEY_HOME";
147            case VTERM_KEY_END:
148                return "VTERM_KEY_END";
149            case VTERM_KEY_PAGEUP:
150                return "VTERM_KEY_PAGEUP";
151            case VTERM_KEY_PAGEDOWN:
152                return "VTERM_KEY_PAGEDOWN";
153            case VTERM_KEY_NONE:
154                return "VTERM_KEY_NONE";
155            default:
156                return "UNKNOWN KEY";
157        }
158    }
159
160    public int getCharacter(KeyEvent event) {
161        int c = event.getUnicodeChar();
162        // TODO: Actually support dead keys
163        if ((c & KeyCharacterMap.COMBINING_ACCENT) != 0) {
164            Log.w(TAG, "Received dead key, ignoring");
165            return 0;
166        }
167        return c;
168    }
169
170    public boolean onKey(View v, int keyCode, KeyEvent event) {
171        if (mTerm == null || event.getAction() == KeyEvent.ACTION_UP) return false;
172
173        int modifiers = getModifiers(event);
174
175        int c = getKey(event);
176        if (c != 0) {
177            if (DEBUG) {
178                Log.d(TAG, "dispatched key event: " +
179                        "mod=" + modifiers + ", " +
180                        "keys=" + getKeyName(c));
181            }
182            return mTerm.dispatchKey(modifiers, c);
183        }
184
185        c = getCharacter(event);
186        if (c != 0) {
187            if (DEBUG) {
188                Log.d(TAG, "dispatched key event: " +
189                        "mod=" + modifiers + ", " +
190                        "character='" + new String(Character.toChars(c)) + "'");
191            }
192            return mTerm.dispatchCharacter(modifiers, c);
193        }
194
195        return false;
196    }
197
198    public void setTerminal(Terminal term) {
199        mTerm = term;
200    }
201}
202