/* Copyright 2012 bigbiff/Dees_Troy TeamWin This file is part of TWRP/TeamWin Recovery Project. TWRP is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. TWRP 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. You should have received a copy of the GNU General Public License along with TWRP. If not, see . */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "../data.hpp" #include extern "C" { #include "../twcommon.h" #include "../minuitwrp/minui.h" #include "gui.h" } #include "rapidxml.hpp" #include "objects.hpp" GUIKeyboard::GUIKeyboard(xml_node<>* node) : GUIObject(node) { int layoutindex, rowindex, keyindex, Xindex, Yindex, keyHeight = 0, keyWidth = 0; rowY = colX = -1; highlightRenderCount = hasHighlight = hasCapsHighlight = 0; char resource[10], layout[8], row[5], key[6], longpress[7]; xml_attribute<>* attr; xml_node<>* child; xml_node<>* keylayout; xml_node<>* keyrow; for (layoutindex=0; layoutindexfirst_node("action"); if (child) { mAction = new GUIAction(node); } memset(&mHighlightColor, 0, sizeof(COLOR)); child = node->first_node("highlight"); if (child) { attr = child->first_attribute("color"); if (attr) { hasHighlight = 1; std::string color = attr->value(); ConvertStrToColor(color, &mHighlightColor); } } memset(&mCapsHighlightColor, 0, sizeof(COLOR)); child = node->first_node("capshighlight"); if (child) { attr = child->first_attribute("color"); if (attr) { hasCapsHighlight = 1; std::string color = attr->value(); ConvertStrToColor(color, &mCapsHighlightColor); } } // Load the images for the different layouts child = node->first_node("layout"); if (child) { layoutindex = 1; strcpy(resource, "resource1"); attr = child->first_attribute(resource); while (attr && layoutindex < (MAX_KEYBOARD_LAYOUTS + 1)) { keyboardImg[layoutindex - 1] = LoadAttrImage(child, resource); layoutindex++; resource[8] = (char)(layoutindex + 48); attr = child->first_attribute(resource); } } // Check the first image to get height and width if (keyboardImg[0] && keyboardImg[0]->GetResource()) { KeyboardWidth = keyboardImg[0]->GetWidth(); KeyboardHeight = keyboardImg[0]->GetHeight(); } // Load all of the layout maps layoutindex = 1; strcpy(layout, "layout1"); keylayout = node->first_node(layout); while (keylayout) { if (layoutindex > MAX_KEYBOARD_LAYOUTS) { LOGERR("Too many layouts defined in keyboard.\n"); return; } child = keylayout->first_node("keysize"); if (child) { attr = child->first_attribute("height"); if (attr) keyHeight = scale_theme_y(atoi(attr->value())); else keyHeight = 0; attr = child->first_attribute("width"); if (attr) keyWidth = scale_theme_x(atoi(attr->value())); else keyWidth = 0; attr = child->first_attribute("capslock"); if (attr) caps_tracking[layoutindex - 1].capslock = atoi(attr->value()); else caps_tracking[layoutindex - 1].capslock = 1; attr = child->first_attribute("revert_layout"); if (attr) caps_tracking[layoutindex - 1].revert_layout = atoi(attr->value()); else caps_tracking[layoutindex - 1].revert_layout = -1; } rowindex = 1; Yindex = 0; strcpy(row, "row1"); keyrow = keylayout->first_node(row); while (keyrow) { if (rowindex > MAX_KEYBOARD_ROWS) { LOGERR("Too many rows defined in keyboard.\n"); return; } Yindex += keyHeight; row_heights[layoutindex - 1][rowindex - 1] = Yindex; keyindex = 1; Xindex = 0; strcpy(key, "key01"); attr = keyrow->first_attribute(key); while (attr) { if (keyindex > MAX_KEYBOARD_KEYS) { LOGERR("Too many keys defined in a keyboard row.\n"); return; } const char* keyinfo = attr->value(); if (strlen(keyinfo) == 0) { LOGERR("No key info on layout%i, row%i, key%dd.\n", layoutindex, rowindex, keyindex); return; } if (ParseKey(keyinfo, keyboard_keys[layoutindex - 1][rowindex - 1][keyindex - 1], Xindex, keyWidth, false)) LOGERR("Invalid key info on layout%i, row%i, key%02i.\n", layoutindex, rowindex, keyindex); // PROCESS LONG PRESS INFO IF EXISTS sprintf(longpress, "long%02i", keyindex); attr = keyrow->first_attribute(longpress); if (attr) { const char* keyinfo = attr->value(); if (strlen(keyinfo) == 0) { LOGERR("No long press info on layout%i, row%i, long%dd.\n", layoutindex, rowindex, keyindex); return; } if (ParseKey(keyinfo, keyboard_keys[layoutindex - 1][rowindex - 1][keyindex - 1], Xindex, keyWidth, true)) LOGERR("Invalid long press key info on layout%i, row%i, long%02i.\n", layoutindex, rowindex, keyindex); } keyindex++; sprintf(key, "key%02i", keyindex); attr = keyrow->first_attribute(key); } rowindex++; row[3] = (char)(rowindex + 48); keyrow = keylayout->first_node(row); } layoutindex++; layout[6] = (char)(layoutindex + 48); keylayout = node->first_node(layout); } int x, y, w, h; // Load the placement LoadPlacement(node->first_node("placement"), &x, &y, &w, &h); SetActionPos(x, y, KeyboardWidth, KeyboardHeight); SetRenderPos(x, y, w, h); return; } GUIKeyboard::~GUIKeyboard() { } int GUIKeyboard::ParseKey(const char* keyinfo, keyboard_key_class& key, int& Xindex, int keyWidth, bool longpress) { int keychar = 0; if (strlen(keyinfo) == 1) { // This is a single key, simple definition keychar = keyinfo[0]; } else { // This key has extra data: {keywidth}:{what_the_key_does} keyWidth = scale_theme_x(atoi(keyinfo)); const char* ptr = keyinfo; while (*ptr > 32 && *ptr != ':') ptr++; if (*ptr != ':') return -1; // no colon is an error ptr++; if (*ptr == 0) { // This is an empty area keychar = 0; } else if (strlen(ptr) == 1) { // This is the character that this key uses keychar = *ptr; } else if (*ptr == 'c') { // This is an ASCII character code: "c:{number}" keychar = atoi(ptr + 2); } else if (*ptr == 'l') { // This is a different layout: "layout{number}" keychar = KEYBOARD_LAYOUT; key.layout = atoi(ptr + 6); } else if (*ptr == 'a') { // This is an action: "action" keychar = KEYBOARD_ACTION; } else return -1; } if (longpress) { key.longpresskey = keychar; } else { key.key = keychar; Xindex += keyWidth; key.end_x = Xindex - 1; } return 0; } int GUIKeyboard::Render(void) { if (!isConditionTrue()) { mRendered = false; return 0; } int ret = 0; if (keyboardImg[currentLayout - 1] && keyboardImg[currentLayout - 1]->GetResource()) gr_blit(keyboardImg[currentLayout - 1]->GetResource(), 0, 0, KeyboardWidth, KeyboardHeight, mRenderX, mRenderY); // Draw highlight for capslock if (hasCapsHighlight && caps_tracking[currentLayout - 1].capslock == 0 && caps_tracking[currentLayout - 1].set_capslock) { int boxheight, boxwidth, x; gr_color(mCapsHighlightColor.red, mCapsHighlightColor.green, mCapsHighlightColor.blue, mCapsHighlightColor.alpha); for (int indexy=0; indexy 0) highlightRenderCount--; } else mRendered = true; return ret; } int GUIKeyboard::Update(void) { if (!isConditionTrue()) return (mRendered ? 2 : 0); if (!mRendered) return 2; return 0; } int GUIKeyboard::SetRenderPos(int x, int y, int w, int h) { mRenderX = x; mRenderY = y; if (w || h) { mRenderW = KeyboardWidth; mRenderH = KeyboardHeight; } if (mAction) mAction->SetActionPos(mRenderX, mRenderY, mRenderW, mRenderH); SetActionPos(mRenderX, mRenderY, mRenderW, mRenderH); return 0; } int GUIKeyboard::GetSelection(int x, int y) { if (x < mRenderX || x - mRenderX > (int)KeyboardWidth || y < mRenderY || y - mRenderY > (int)KeyboardHeight) return -1; return 0; } int GUIKeyboard::NotifyTouch(TOUCH_STATE state, int x, int y) { static int startSelection = -1, was_held = 0, startX = 0; static unsigned char initial_key = 0; int indexy, indexx, rely, relx, rowIndex = 0; rely = y - mRenderY; relx = x - mRenderX; if (!isConditionTrue()) return -1; switch (state) { case TOUCH_START: if (GetSelection(x, y) == 0) { startSelection = -1; was_held = 0; startX = x; // Find the correct row for (indexy=0; indexy rely) { rowIndex = indexy; rowY = indexy; indexy = MAX_KEYBOARD_ROWS; } } // Find the correct key (column) for (indexx=0; indexx relx) { // This is the key that was pressed! initial_key = keyboard_keys[currentLayout - 1][rowIndex][indexx].key; colX = indexx; indexx = MAX_KEYBOARD_KEYS; } } if (initial_key != 0) highlightRenderCount = -1; else highlightRenderCount = 0; mRendered = false; } else { if (highlightRenderCount != 0) mRendered = false; highlightRenderCount = 0; startSelection = 0; } break; case TOUCH_DRAG: break; case TOUCH_RELEASE: if (x < startX - (KeyboardWidth * 0.5)) { if (highlightRenderCount != 0) { highlightRenderCount = 0; mRendered = false; } PageManager::NotifyKeyboard(KEYBOARD_SWIPE_LEFT); return 0; } else if (x > startX + (KeyboardWidth * 0.5)) { if (highlightRenderCount != 0) { highlightRenderCount = 0; mRendered = false; } PageManager::NotifyKeyboard(KEYBOARD_SWIPE_RIGHT); return 0; } case TOUCH_HOLD: case TOUCH_REPEAT: if (startSelection == 0 || GetSelection(x, y) == -1) { if (highlightRenderCount != 0) { highlightRenderCount = 0; mRendered = false; } return 0; } else if (highlightRenderCount != 0) { if (state == TOUCH_RELEASE) highlightRenderCount = 2; else highlightRenderCount = -1; mRendered = false; } // Find the correct row for (indexy=0; indexy rely) { rowIndex = indexy; indexy = MAX_KEYBOARD_ROWS; } } // Find the correct key (column) for (indexx=0; indexx relx) { // This is the key that was pressed! if (key.key != initial_key) { // We dragged off of the starting key startSelection = 0; break; } else if (state == TOUCH_RELEASE && was_held == 0) { DataManager::Vibrate("tw_keyboard_vibrate"); if ((int)key.key < KEYBOARD_SPECIAL_KEYS && (int)key.key > 0) { // Regular key PageManager::NotifyKeyboard(key.key); if (caps_tracking[currentLayout - 1].capslock == 0 && !caps_tracking[currentLayout - 1].set_capslock) { // caps lock was not set, change layouts currentLayout = caps_tracking[currentLayout - 1].revert_layout; mRendered = false; } } else if ((int)key.key == KEYBOARD_LAYOUT) { // Switch layouts if (caps_tracking[currentLayout - 1].capslock == 0 && key.layout == caps_tracking[currentLayout - 1].revert_layout) { if (!caps_tracking[currentLayout - 1].set_capslock) { caps_tracking[currentLayout - 1].set_capslock = 1; // Set the caps lock } else { caps_tracking[currentLayout - 1].set_capslock = 0; // Unset the caps lock and change layouts currentLayout = key.layout; } } else { currentLayout = key.layout; } mRendered = false; } else if ((int)key.key == KEYBOARD_ACTION) { // Action highlightRenderCount = 0; if (mAction) { // Keyboard has its own action defined return (mAction ? mAction->NotifyTouch(state, x, y) : 1); } else { // Send action notification PageManager::NotifyKeyboard(key.key); } } } else if (state == TOUCH_HOLD) { was_held = 1; if ((int)key.key == KEYBOARD_BACKSPACE) { // Repeat backspace PageManager::NotifyKeyboard(key.key); } else if ((int)key.longpresskey < KEYBOARD_SPECIAL_KEYS && (int)key.longpresskey > 0) { // Long Press Key DataManager::Vibrate("tw_keyboard_vibrate"); PageManager::NotifyKeyboard(key.longpresskey); } } else if (state == TOUCH_REPEAT) { was_held = 1; if ((int)key.key == KEYBOARD_BACKSPACE) { // Repeat backspace PageManager::NotifyKeyboard(key.key); } } indexx = MAX_KEYBOARD_KEYS; } } break; } return 0; }