| /* Copyright (C) 2007-2008 The Android Open Source Project |
| ** |
| ** This software is licensed under the terms of the GNU General Public |
| ** License version 2, as published by the Free Software Foundation, and |
| ** may be copied, distributed, and modified under those terms. |
| ** |
| ** This program is distributed in the hope that it will be useful, |
| ** but WITHOUT ANY WARRANTY; without even the implied warranty of |
| ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| ** GNU General Public License for more details. |
| */ |
| #include "android/skin/keyboard.h" |
| |
| #include "android/skin/charmap.h" |
| #include "android/skin/keycode.h" |
| #include "android/skin/keycode-buffer.h" |
| #include "android/utils/debug.h" |
| #include "android/utils/bufprint.h" |
| #include "android/utils/system.h" |
| #include "android/utils/utf8_utils.h" |
| |
| #include <stdio.h> |
| |
| #define DEBUG 1 |
| |
| #if DEBUG |
| # define D(...) VERBOSE_PRINT(keys,__VA_ARGS__) |
| #else |
| # define D(...) ((void)0) |
| #endif |
| |
| struct SkinKeyboard { |
| const SkinCharmap* charmap; |
| |
| SkinRotation rotation; |
| |
| SkinKeycodeBuffer keycodes[1]; |
| }; |
| |
| #define DEFAULT_ANDROID_CHARMAP "qwerty2" |
| |
| static bool skin_key_code_is_arrow(int code) { |
| return code == kKeyCodeDpadLeft || |
| code == kKeyCodeDpadRight || |
| code == kKeyCodeDpadUp || |
| code == kKeyCodeDpadDown; |
| } |
| |
| static SkinKeyCode |
| skin_keyboard_key_to_code(SkinKeyboard* keyboard, |
| int code, |
| int mod, |
| int down) |
| { |
| D("key code=%d mod=%d str=%s", |
| code, |
| mod, |
| skin_key_pair_to_string(code, mod)); |
| |
| /* first, handle the arrow keys directly */ |
| if (skin_key_code_is_arrow(code)) { |
| code = skin_keycode_rotate(code, -keyboard->rotation); |
| D("handling arrow (code=%d mod=%d)", code, mod); |
| int doCapL, doCapR, doAltL, doAltR; |
| |
| doCapL = mod & kKeyModLShift; |
| doCapR = mod & kKeyModRShift; |
| doAltL = mod & kKeyModLAlt; |
| doAltR = mod & kKeyModRAlt; |
| |
| if (down) { |
| if (doAltL) skin_keyboard_add_key_event(keyboard, kKeyCodeAltLeft, 1); |
| if (doAltR) skin_keyboard_add_key_event(keyboard, kKeyCodeAltRight, 1); |
| if (doCapL) skin_keyboard_add_key_event(keyboard, kKeyCodeCapLeft, 1); |
| if (doCapR) skin_keyboard_add_key_event(keyboard, kKeyCodeCapRight, 1); |
| } |
| skin_keyboard_add_key_event(keyboard, code, down); |
| |
| if (!down) { |
| if (doAltR) skin_keyboard_add_key_event(keyboard, kKeyCodeAltRight, 0); |
| if (doAltL) skin_keyboard_add_key_event(keyboard, kKeyCodeAltLeft, 0); |
| if (doCapR) skin_keyboard_add_key_event(keyboard, kKeyCodeCapRight, 0); |
| if (doCapL) skin_keyboard_add_key_event(keyboard, kKeyCodeCapLeft, 0); |
| } |
| code = 0; |
| return code; |
| } |
| |
| /* special case for keypad keys, ignore them here if numlock is on */ |
| if ((mod & kKeyModNumLock) != 0) { |
| switch ((int)code) { |
| case KEY_KP0: |
| case KEY_KP1: |
| case KEY_KP2: |
| case KEY_KP3: |
| case KEY_KP4: |
| case KEY_KP5: |
| case KEY_KP6: |
| case KEY_KP7: |
| case KEY_KP8: |
| case KEY_KP9: |
| case KEY_KPPLUS: |
| case KEY_KPMINUS: |
| case KEY_KPASTERISK: |
| case KEY_KPSLASH: |
| case KEY_KPEQUAL: |
| case KEY_KPDOT: |
| case KEY_KPENTER: |
| return 0; |
| default: |
| ; |
| } |
| } |
| |
| D("could not handle (code=%d, mod=%d, str=%s)", code, mod, |
| skin_key_pair_to_string(code,mod)); |
| return -1; |
| } |
| |
| void |
| skin_keyboard_process_event(SkinKeyboard* kb, SkinEvent* ev, int down) |
| { |
| if (ev->type == kEventTextInput) { |
| // TODO(digit): For each Unicode value in the input text. |
| const uint8_t* text = ev->u.text.text; |
| const uint8_t* end = text + sizeof(ev->u.text.text); |
| while (text < end && *text) { |
| uint32_t codepoint = 0; |
| int len = android_utf8_decode(text, end - text, &codepoint); |
| if (len < 0) { |
| break; |
| } |
| skin_keyboard_process_unicode_event(kb, codepoint, 1); |
| skin_keyboard_process_unicode_event(kb, codepoint, 0); |
| text += len; |
| } |
| skin_keyboard_flush(kb); |
| } else if (ev->type == kEventKeyDown || ev->type == kEventKeyUp) { |
| int keycode = ev->u.key.keycode; |
| int mod = ev->u.key.mod; |
| |
| /* first, try the keyboard-mode-independent keys */ |
| int code = skin_keyboard_key_to_code(kb, keycode, mod, down); |
| if (code == 0) { |
| return; |
| } |
| if ((int)code > 0) { |
| skin_keyboard_add_key_event(kb, code, down); |
| skin_keyboard_flush(kb); |
| return; |
| } |
| |
| code = keycode; |
| |
| if (code == kKeyCodeAltLeft || code == kKeyCodeAltRight || |
| code == kKeyCodeCapLeft || code == kKeyCodeCapRight || |
| code == kKeyCodeSym) { |
| return; |
| } |
| |
| if (code == KEY_APPSWITCH || code == KEY_PLAYPAUSE || |
| code == KEY_BACK || code == KEY_POWER || |
| code == KEY_BACKSPACE || code == KEY_SOFT1 || |
| code == KEY_CENTER || code == KEY_REWIND || |
| code == KEY_ENTER || code == KEY_VOLUMEDOWN || |
| code == KEY_FASTFORWARD || code == KEY_VOLUMEUP || |
| code == KEY_HOME ) |
| { |
| skin_keyboard_add_key_event(kb, code, down); |
| skin_keyboard_flush(kb); |
| return; |
| } |
| D("ignoring keycode %d", keycode); |
| } |
| } |
| |
| void |
| skin_keyboard_set_rotation( SkinKeyboard* keyboard, |
| SkinRotation rotation ) |
| { |
| keyboard->rotation = (rotation & 3); |
| } |
| |
| void |
| skin_keyboard_add_key_event( SkinKeyboard* kb, |
| unsigned code, |
| unsigned down ) |
| { |
| skin_keycode_buffer_add(kb->keycodes, code, down); |
| } |
| |
| |
| void |
| skin_keyboard_flush( SkinKeyboard* kb ) |
| { |
| skin_keycode_buffer_flush(kb->keycodes); |
| } |
| |
| |
| int |
| skin_keyboard_process_unicode_event( SkinKeyboard* kb, unsigned int unicode, int down ) |
| { |
| return skin_charmap_reverse_map_unicode(kb->charmap, unicode, down, |
| kb->keycodes); |
| } |
| |
| static SkinKeyboard* skin_keyboard_create_from_charmap_name( |
| const char* charmap_name, |
| SkinRotation dpad_rotation, |
| SkinKeyCodeFlushFunc keycode_flush) { |
| SkinKeyboard* kb; |
| |
| ANEW0(kb); |
| |
| kb->charmap = skin_charmap_get_by_name(charmap_name); |
| if (!kb->charmap) { |
| // Charmap name was not found. Default to "qwerty2" */ |
| kb->charmap = skin_charmap_get_by_name(DEFAULT_ANDROID_CHARMAP); |
| fprintf(stderr, "### warning, skin requires unknown '%s' charmap, reverting to '%s'\n", |
| charmap_name, kb->charmap->name ); |
| } |
| skin_keycode_buffer_init(kb->keycodes, keycode_flush); |
| skin_keyboard_set_rotation(kb, dpad_rotation); |
| return kb; |
| } |
| |
| SkinKeyboard* skin_keyboard_create(const char* kcm_file_path, |
| SkinRotation dpad_rotation, |
| SkinKeyCodeFlushFunc keycode_flush) { |
| const char* charmap_name = DEFAULT_ANDROID_CHARMAP; |
| char cmap_buff[SKIN_CHARMAP_NAME_SIZE]; |
| |
| if (kcm_file_path != NULL) { |
| kcm_extract_charmap_name(kcm_file_path, cmap_buff, sizeof cmap_buff); |
| charmap_name = cmap_buff; |
| } |
| return skin_keyboard_create_from_charmap_name(charmap_name, dpad_rotation, |
| keycode_flush); |
| } |
| |
| void |
| skin_keyboard_free( SkinKeyboard* keyboard ) |
| { |
| if (keyboard) { |
| AFREE(keyboard); |
| } |
| } |