blob: 306422f30fbb2f3951ef45a7d85fd745d0ef60ac [file] [log] [blame]
Dees Troy3be70a82013-10-22 14:25:12 +00001/*
2 Copyright 2012 bigbiff/Dees_Troy TeamWin
3 This file is part of TWRP/TeamWin Recovery Project.
4
5 TWRP is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation, either version 3 of the License, or
8 (at your option) any later version.
9
10 TWRP is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with TWRP. If not, see <http://www.gnu.org/licenses/>.
17*/
Dees_Troy51a0e822012-09-05 15:24:24 -040018
Dees_Troy51a0e822012-09-05 15:24:24 -040019#include <stdlib.h>
20#include <string.h>
Samer Diab (S.a.M.e.R_d)71e9b042014-01-07 20:18:47 +000021#include "../data.hpp"
Dees_Troy51a0e822012-09-05 15:24:24 -040022
23#include <string>
24
25extern "C" {
Dees_Troy2673cec2013-04-02 20:22:16 +000026#include "../twcommon.h"
Dees_Troy51a0e822012-09-05 15:24:24 -040027#include "../minuitwrp/minui.h"
Ethan Yonker63e414f2015-02-06 15:44:39 -060028#include "gui.h"
Dees_Troy51a0e822012-09-05 15:24:24 -040029}
30
31#include "rapidxml.hpp"
32#include "objects.hpp"
33
34GUIKeyboard::GUIKeyboard(xml_node<>* node)
Vojtech Bocekede51c52014-02-07 23:58:09 +010035 : GUIObject(node)
Dees_Troy51a0e822012-09-05 15:24:24 -040036{
37 int layoutindex, rowindex, keyindex, Xindex, Yindex, keyHeight = 0, keyWidth = 0;
Dees_Troy30b962e2012-10-19 20:48:59 -040038 rowY = colX = -1;
Ethan Yonker21ff02a2015-02-18 14:35:00 -060039 highlightRenderCount = 0;
40 hasHighlight = hasCapsHighlight = false;
Dees_Troy3a16cb52013-01-10 15:16:02 +000041 char resource[10], layout[8], row[5], key[6], longpress[7];
Dees_Troy51a0e822012-09-05 15:24:24 -040042 xml_attribute<>* attr;
43 xml_node<>* child;
44 xml_node<>* keylayout;
45 xml_node<>* keyrow;
46
47 for (layoutindex=0; layoutindex<MAX_KEYBOARD_LAYOUTS; layoutindex++)
48 keyboardImg[layoutindex] = NULL;
49
50 mRendered = false;
51 currentLayout = 1;
that1a7ba972015-02-01 19:48:19 +010052 KeyboardHeight = KeyboardWidth = 0;
Dees_Troy51a0e822012-09-05 15:24:24 -040053
54 if (!node) return;
55
Ethan Yonker21ff02a2015-02-18 14:35:00 -060056 mHighlightColor = LoadAttrColor(FindNode(node, "highlight"), "color", &hasHighlight);
57 mCapsHighlightColor = LoadAttrColor(FindNode(node, "capshighlight"), "color", &hasCapsHighlight);
Ethan Yonkerc3120d42014-02-17 07:55:00 -060058
Dees_Troy51a0e822012-09-05 15:24:24 -040059 // Load the images for the different layouts
Ethan Yonker21ff02a2015-02-18 14:35:00 -060060 child = FindNode(node, "layout");
Dees_Troy51a0e822012-09-05 15:24:24 -040061 if (child)
62 {
63 layoutindex = 1;
64 strcpy(resource, "resource1");
65 attr = child->first_attribute(resource);
66 while (attr && layoutindex < (MAX_KEYBOARD_LAYOUTS + 1)) {
thatf6ed8fc2015-02-14 20:23:16 +010067 keyboardImg[layoutindex - 1] = LoadAttrImage(child, resource);
Dees_Troy51a0e822012-09-05 15:24:24 -040068
69 layoutindex++;
70 resource[8] = (char)(layoutindex + 48);
71 attr = child->first_attribute(resource);
72 }
73 }
74
75 // Check the first image to get height and width
76 if (keyboardImg[0] && keyboardImg[0]->GetResource())
77 {
thatf6ed8fc2015-02-14 20:23:16 +010078 KeyboardWidth = keyboardImg[0]->GetWidth();
79 KeyboardHeight = keyboardImg[0]->GetHeight();
Dees_Troy51a0e822012-09-05 15:24:24 -040080 }
81
82 // Load all of the layout maps
83 layoutindex = 1;
84 strcpy(layout, "layout1");
Ethan Yonker21ff02a2015-02-18 14:35:00 -060085 keylayout = FindNode(node, layout);
Dees_Troy51a0e822012-09-05 15:24:24 -040086 while (keylayout)
87 {
88 if (layoutindex > MAX_KEYBOARD_LAYOUTS) {
Dees_Troy2673cec2013-04-02 20:22:16 +000089 LOGERR("Too many layouts defined in keyboard.\n");
Dees_Troy51a0e822012-09-05 15:24:24 -040090 return;
91 }
92
93 child = keylayout->first_node("keysize");
94 if (child) {
95 attr = child->first_attribute("height");
96 if (attr)
Ethan Yonker63e414f2015-02-06 15:44:39 -060097 keyHeight = scale_theme_y(atoi(attr->value()));
Dees_Troy51a0e822012-09-05 15:24:24 -040098 else
99 keyHeight = 0;
100 attr = child->first_attribute("width");
101 if (attr)
Ethan Yonker63e414f2015-02-06 15:44:39 -0600102 keyWidth = scale_theme_x(atoi(attr->value()));
Dees_Troy51a0e822012-09-05 15:24:24 -0400103 else
104 keyWidth = 0;
Ethan Yonkerc3120d42014-02-17 07:55:00 -0600105 attr = child->first_attribute("capslock");
106 if (attr)
107 caps_tracking[layoutindex - 1].capslock = atoi(attr->value());
108 else
109 caps_tracking[layoutindex - 1].capslock = 1;
110 attr = child->first_attribute("revert_layout");
111 if (attr)
112 caps_tracking[layoutindex - 1].revert_layout = atoi(attr->value());
113 else
114 caps_tracking[layoutindex - 1].revert_layout = -1;
Dees_Troy51a0e822012-09-05 15:24:24 -0400115 }
116
117 rowindex = 1;
118 Yindex = 0;
119 strcpy(row, "row1");
120 keyrow = keylayout->first_node(row);
121 while (keyrow)
122 {
123 if (rowindex > MAX_KEYBOARD_ROWS) {
Dees_Troy2673cec2013-04-02 20:22:16 +0000124 LOGERR("Too many rows defined in keyboard.\n");
Dees_Troy51a0e822012-09-05 15:24:24 -0400125 return;
126 }
127
128 Yindex += keyHeight;
129 row_heights[layoutindex - 1][rowindex - 1] = Yindex;
130
131 keyindex = 1;
132 Xindex = 0;
133 strcpy(key, "key01");
134 attr = keyrow->first_attribute(key);
135
136 while (attr) {
Dees_Troy51a0e822012-09-05 15:24:24 -0400137 if (keyindex > MAX_KEYBOARD_KEYS) {
Dees_Troy2673cec2013-04-02 20:22:16 +0000138 LOGERR("Too many keys defined in a keyboard row.\n");
Dees_Troy51a0e822012-09-05 15:24:24 -0400139 return;
140 }
141
that1a7ba972015-02-01 19:48:19 +0100142 const char* keyinfo = attr->value();
Dees_Troy51a0e822012-09-05 15:24:24 -0400143
144 if (strlen(keyinfo) == 0) {
Dees_Troy2673cec2013-04-02 20:22:16 +0000145 LOGERR("No key info on layout%i, row%i, key%dd.\n", layoutindex, rowindex, keyindex);
Dees_Troy51a0e822012-09-05 15:24:24 -0400146 return;
147 }
148
that1a7ba972015-02-01 19:48:19 +0100149 if (ParseKey(keyinfo, keyboard_keys[layoutindex - 1][rowindex - 1][keyindex - 1], Xindex, keyWidth, false))
150 LOGERR("Invalid key info on layout%i, row%i, key%02i.\n", layoutindex, rowindex, keyindex);
Dees_Troy51a0e822012-09-05 15:24:24 -0400151
Dees_Troy51a0e822012-09-05 15:24:24 -0400152
153 // PROCESS LONG PRESS INFO IF EXISTS
154 sprintf(longpress, "long%02i", keyindex);
155 attr = keyrow->first_attribute(longpress);
156 if (attr) {
that1a7ba972015-02-01 19:48:19 +0100157 const char* keyinfo = attr->value();
Dees_Troy51a0e822012-09-05 15:24:24 -0400158
159 if (strlen(keyinfo) == 0) {
Dees_Troy2673cec2013-04-02 20:22:16 +0000160 LOGERR("No long press info on layout%i, row%i, long%dd.\n", layoutindex, rowindex, keyindex);
Dees_Troy51a0e822012-09-05 15:24:24 -0400161 return;
162 }
163
that1a7ba972015-02-01 19:48:19 +0100164 if (ParseKey(keyinfo, keyboard_keys[layoutindex - 1][rowindex - 1][keyindex - 1], Xindex, keyWidth, true))
165 LOGERR("Invalid long press key info on layout%i, row%i, long%02i.\n", layoutindex, rowindex, keyindex);
Dees_Troy51a0e822012-09-05 15:24:24 -0400166 }
167 keyindex++;
168 sprintf(key, "key%02i", keyindex);
169 attr = keyrow->first_attribute(key);
170 }
171 rowindex++;
172 row[3] = (char)(rowindex + 48);
173 keyrow = keylayout->first_node(row);
174 }
175 layoutindex++;
176 layout[6] = (char)(layoutindex + 48);
Ethan Yonker21ff02a2015-02-18 14:35:00 -0600177 keylayout = FindNode(node, layout);
Dees_Troy51a0e822012-09-05 15:24:24 -0400178 }
179
thate79878b2015-03-14 23:07:23 +0100180 int x, y;
Dees_Troy51a0e822012-09-05 15:24:24 -0400181 // Load the placement
thate79878b2015-03-14 23:07:23 +0100182 LoadPlacement(FindNode(node, "placement"), &x, &y);
183 SetRenderPos(x, y, KeyboardWidth, KeyboardHeight);
Dees_Troy51a0e822012-09-05 15:24:24 -0400184 return;
185}
186
187GUIKeyboard::~GUIKeyboard()
188{
that1a7ba972015-02-01 19:48:19 +0100189}
Dees_Troy51a0e822012-09-05 15:24:24 -0400190
thate79878b2015-03-14 23:07:23 +0100191int GUIKeyboard::ParseKey(const char* keyinfo, Key& key, int& Xindex, int keyWidth, bool longpress)
that1a7ba972015-02-01 19:48:19 +0100192{
193 int keychar = 0;
194 if (strlen(keyinfo) == 1) {
195 // This is a single key, simple definition
196 keychar = keyinfo[0];
197 } else {
198 // This key has extra data: {keywidth}:{what_the_key_does}
Ethan Yonker63e414f2015-02-06 15:44:39 -0600199 keyWidth = scale_theme_x(atoi(keyinfo));
that1a7ba972015-02-01 19:48:19 +0100200
201 const char* ptr = keyinfo;
202 while (*ptr > 32 && *ptr != ':')
203 ptr++;
204 if (*ptr != ':')
205 return -1; // no colon is an error
206 ptr++;
207
208 if (*ptr == 0) { // This is an empty area
209 keychar = 0;
210 } else if (strlen(ptr) == 1) { // This is the character that this key uses
211 keychar = *ptr;
212 } else if (*ptr == 'c') { // This is an ASCII character code: "c:{number}"
213 keychar = atoi(ptr + 2);
214 } else if (*ptr == 'l') { // This is a different layout: "layout{number}"
215 keychar = KEYBOARD_LAYOUT;
216 key.layout = atoi(ptr + 6);
217 } else if (*ptr == 'a') { // This is an action: "action"
218 keychar = KEYBOARD_ACTION;
219 } else
220 return -1;
221 }
222
223 if (longpress) {
224 key.longpresskey = keychar;
225 } else {
226 key.key = keychar;
227 Xindex += keyWidth;
228 key.end_x = Xindex - 1;
229 }
230
231 return 0;
Dees_Troy51a0e822012-09-05 15:24:24 -0400232}
233
234int GUIKeyboard::Render(void)
235{
236 if (!isConditionTrue())
237 {
238 mRendered = false;
239 return 0;
240 }
241
242 int ret = 0;
243
244 if (keyboardImg[currentLayout - 1] && keyboardImg[currentLayout - 1]->GetResource())
245 gr_blit(keyboardImg[currentLayout - 1]->GetResource(), 0, 0, KeyboardWidth, KeyboardHeight, mRenderX, mRenderY);
246
Ethan Yonkerc3120d42014-02-17 07:55:00 -0600247 // Draw highlight for capslock
248 if (hasCapsHighlight && caps_tracking[currentLayout - 1].capslock == 0 && caps_tracking[currentLayout - 1].set_capslock) {
249 int boxheight, boxwidth, x;
250 gr_color(mCapsHighlightColor.red, mCapsHighlightColor.green, mCapsHighlightColor.blue, mCapsHighlightColor.alpha);
251 for (int indexy=0; indexy<MAX_KEYBOARD_ROWS; indexy++) {
252 for (int indexx=0; indexx<MAX_KEYBOARD_KEYS; indexx++) {
253 if ((int)keyboard_keys[currentLayout - 1][indexy][indexx].key == KEYBOARD_LAYOUT && (int)keyboard_keys[currentLayout - 1][indexy][indexx].layout == caps_tracking[currentLayout - 1].revert_layout) {
254 if (indexy == 0)
255 boxheight = row_heights[currentLayout - 1][indexy];
256 else
257 boxheight = row_heights[currentLayout - 1][indexy] - row_heights[currentLayout - 1][indexy - 1];
258 if (indexx == 0) {
259 x = mRenderX;
260 boxwidth = keyboard_keys[currentLayout - 1][indexy][indexx].end_x;
261 } else {
262 x = mRenderX + keyboard_keys[currentLayout - 1][indexy][indexx - 1].end_x;
263 boxwidth = keyboard_keys[currentLayout - 1][indexy][indexx].end_x - keyboard_keys[currentLayout - 1][indexy][indexx - 1].end_x;
264 }
265 gr_fill(x, mRenderY + row_heights[currentLayout - 1][indexy - 1], boxwidth, boxheight);
266 }
267 }
268 }
269 }
270
Dees_Troy30b962e2012-10-19 20:48:59 -0400271 if (hasHighlight && highlightRenderCount != 0) {
272 int boxheight, boxwidth, x;
273 if (rowY == 0)
274 boxheight = row_heights[currentLayout - 1][rowY];
275 else
276 boxheight = row_heights[currentLayout - 1][rowY] - row_heights[currentLayout - 1][rowY - 1];
277 if (colX == 0) {
278 x = mRenderX;
279 boxwidth = keyboard_keys[currentLayout - 1][rowY][colX].end_x;
280 } else {
281 x = mRenderX + keyboard_keys[currentLayout - 1][rowY][colX - 1].end_x;
282 boxwidth = keyboard_keys[currentLayout - 1][rowY][colX].end_x - keyboard_keys[currentLayout - 1][rowY][colX - 1].end_x;
283 }
284 gr_color(mHighlightColor.red, mHighlightColor.green, mHighlightColor.blue, mHighlightColor.alpha);
285 gr_fill(x, mRenderY + row_heights[currentLayout - 1][rowY - 1], boxwidth, boxheight);
286 if (highlightRenderCount > 0)
287 highlightRenderCount--;
288 } else
289 mRendered = true;
290
Dees_Troy51a0e822012-09-05 15:24:24 -0400291 return ret;
292}
293
294int GUIKeyboard::Update(void)
295{
296 if (!isConditionTrue()) return (mRendered ? 2 : 0);
297 if (!mRendered) return 2;
298
299 return 0;
300}
301
302int GUIKeyboard::SetRenderPos(int x, int y, int w, int h)
303{
304 mRenderX = x;
305 mRenderY = y;
thate79878b2015-03-14 23:07:23 +0100306 mRenderW = KeyboardWidth;
307 mRenderH = KeyboardHeight;
Dees_Troy51a0e822012-09-05 15:24:24 -0400308 SetActionPos(mRenderX, mRenderY, mRenderW, mRenderH);
309 return 0;
310}
311
thate79878b2015-03-14 23:07:23 +0100312GUIKeyboard::Key* GUIKeyboard::HitTestKey(int x, int y)
Dees_Troy51a0e822012-09-05 15:24:24 -0400313{
thate79878b2015-03-14 23:07:23 +0100314 if (!IsInRegion(x, y))
315 return NULL;
316
317 int rely = y - mRenderY;
318 int relx = x - mRenderX;
319
320 // Find the correct row
321 int row;
322 for (row = 0; row < MAX_KEYBOARD_ROWS; ++row) {
323 if (row_heights[currentLayout - 1][row] > rely)
324 break;
325 }
326 if (row == MAX_KEYBOARD_ROWS)
327 return NULL;
328
329 // Find the correct key (column)
330 int col;
331 int x1 = 0;
332 for (col = 0; col < MAX_KEYBOARD_KEYS; ++col) {
333 Key& key = keyboard_keys[currentLayout - 1][row][col];
334 if (x1 <= relx && relx < key.end_x && key.key != 0) {
335 // This is the key that was pressed!
336 rowY = row;
337 colX = col;
338 return &key;
339 }
340 x1 = key.end_x;
341 }
342 return NULL;
Dees_Troy51a0e822012-09-05 15:24:24 -0400343}
344
345int GUIKeyboard::NotifyTouch(TOUCH_STATE state, int x, int y)
346{
thate79878b2015-03-14 23:07:23 +0100347 static int was_held = 0, startX = 0;
348 static Key* initial_key = 0;
Dees_Troy51a0e822012-09-05 15:24:24 -0400349
350 if (!isConditionTrue()) return -1;
351
352 switch (state)
353 {
354 case TOUCH_START:
thate79878b2015-03-14 23:07:23 +0100355 was_held = 0;
356 startX = x;
357 initial_key = HitTestKey(x, y);
358 if (initial_key)
359 highlightRenderCount = -1;
360 else
Dees_Troy30b962e2012-10-19 20:48:59 -0400361 highlightRenderCount = 0;
thate79878b2015-03-14 23:07:23 +0100362 mRendered = false;
Dees_Troy51a0e822012-09-05 15:24:24 -0400363 break;
thate79878b2015-03-14 23:07:23 +0100364
Dees_Troy51a0e822012-09-05 15:24:24 -0400365 case TOUCH_DRAG:
366 break;
thate79878b2015-03-14 23:07:23 +0100367
Dees_Troy51a0e822012-09-05 15:24:24 -0400368 case TOUCH_RELEASE:
Dees_Troy0cb64e52012-10-15 15:56:10 -0400369 if (x < startX - (KeyboardWidth * 0.5)) {
Dees_Troy30b962e2012-10-19 20:48:59 -0400370 if (highlightRenderCount != 0) {
371 highlightRenderCount = 0;
372 mRendered = false;
373 }
Dees_Troy51a0e822012-09-05 15:24:24 -0400374 PageManager::NotifyKeyboard(KEYBOARD_SWIPE_LEFT);
375 return 0;
Dees_Troy0cb64e52012-10-15 15:56:10 -0400376 } else if (x > startX + (KeyboardWidth * 0.5)) {
Dees_Troy30b962e2012-10-19 20:48:59 -0400377 if (highlightRenderCount != 0) {
378 highlightRenderCount = 0;
379 mRendered = false;
380 }
Dees_Troy51a0e822012-09-05 15:24:24 -0400381 PageManager::NotifyKeyboard(KEYBOARD_SWIPE_RIGHT);
382 return 0;
383 }
thate79878b2015-03-14 23:07:23 +0100384 // fall through
Dees_Troy51a0e822012-09-05 15:24:24 -0400385 case TOUCH_HOLD:
386 case TOUCH_REPEAT:
thate79878b2015-03-14 23:07:23 +0100387 if (!initial_key) {
Dees_Troy30b962e2012-10-19 20:48:59 -0400388 if (highlightRenderCount != 0) {
389 highlightRenderCount = 0;
390 mRendered = false;
391 }
Dees_Troy51a0e822012-09-05 15:24:24 -0400392 return 0;
thate79878b2015-03-14 23:07:23 +0100393 }
394
395 if (highlightRenderCount != 0) {
Dees_Troy30b962e2012-10-19 20:48:59 -0400396 if (state == TOUCH_RELEASE)
397 highlightRenderCount = 2;
398 else
399 highlightRenderCount = -1;
400 mRendered = false;
401 }
Dees_Troy51a0e822012-09-05 15:24:24 -0400402
thate79878b2015-03-14 23:07:23 +0100403 if (HitTestKey(x, y) != initial_key) {
404 // We dragged off of the starting key
405 if (highlightRenderCount != 0) {
406 highlightRenderCount = 0;
407 mRendered = false;
Dees_Troy51a0e822012-09-05 15:24:24 -0400408 }
thate79878b2015-03-14 23:07:23 +0100409 return 0;
410 } else {
411 Key& key = *initial_key;
412 if (state == TOUCH_RELEASE && was_held == 0) {
413 DataManager::Vibrate("tw_keyboard_vibrate");
414 if ((int)key.key < KEYBOARD_SPECIAL_KEYS && (int)key.key > 0) {
415 // Regular key
416 PageManager::NotifyKeyboard(key.key);
417 if (caps_tracking[currentLayout - 1].capslock == 0 && !caps_tracking[currentLayout - 1].set_capslock) {
418 // caps lock was not set, change layouts
419 currentLayout = caps_tracking[currentLayout - 1].revert_layout;
420 mRendered = false;
421 }
422 } else if ((int)key.key == KEYBOARD_LAYOUT) {
423 // Switch layouts
424 if (caps_tracking[currentLayout - 1].capslock == 0 && key.layout == caps_tracking[currentLayout - 1].revert_layout) {
425 if (!caps_tracking[currentLayout - 1].set_capslock) {
426 caps_tracking[currentLayout - 1].set_capslock = 1; // Set the caps lock
Ethan Yonkerc3120d42014-02-17 07:55:00 -0600427 } else {
thate79878b2015-03-14 23:07:23 +0100428 caps_tracking[currentLayout - 1].set_capslock = 0; // Unset the caps lock and change layouts
that1a7ba972015-02-01 19:48:19 +0100429 currentLayout = key.layout;
Ethan Yonkerc3120d42014-02-17 07:55:00 -0600430 }
thate79878b2015-03-14 23:07:23 +0100431 } else {
432 currentLayout = key.layout;
Dees_Troy51a0e822012-09-05 15:24:24 -0400433 }
thate79878b2015-03-14 23:07:23 +0100434 mRendered = false;
435 } else if ((int)key.key == KEYBOARD_ACTION) {
436 // Action
437 highlightRenderCount = 0;
438 // Send action notification
439 PageManager::NotifyKeyboard(key.key);
Dees_Troy51a0e822012-09-05 15:24:24 -0400440 }
thate79878b2015-03-14 23:07:23 +0100441 } else if (state == TOUCH_HOLD) {
442 was_held = 1;
443 if ((int)key.key == KEYBOARD_BACKSPACE) {
444 // Repeat backspace
445 PageManager::NotifyKeyboard(key.key);
446 } else if ((int)key.longpresskey < KEYBOARD_SPECIAL_KEYS && (int)key.longpresskey > 0) {
447 // Long Press Key
448 DataManager::Vibrate("tw_keyboard_vibrate");
449 PageManager::NotifyKeyboard(key.longpresskey);
450 }
451 } else if (state == TOUCH_REPEAT) {
452 was_held = 1;
453 if ((int)key.key == KEYBOARD_BACKSPACE) {
454 // Repeat backspace
455 PageManager::NotifyKeyboard(key.key);
456 }
Dees_Troy51a0e822012-09-05 15:24:24 -0400457 }
458 }
459 break;
460 }
461
462 return 0;
463}