blob: 8ab2280a17e86b17a53a7601e2d0c2a667f97c1b [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
thatd86f49d2015-03-15 00:56:57 +010047 for (layoutindex=0; layoutindex<MAX_KEYBOARD_LAYOUTS; layoutindex++) {
48 layouts[layoutindex].keyboardImg = NULL;
49 memset(layouts[layoutindex].keys, 0, sizeof(Layout::keys));
50 memset(layouts[layoutindex].row_end_y, 0, sizeof(Layout::row_end_y));
51 }
Dees_Troy51a0e822012-09-05 15:24:24 -040052
53 mRendered = false;
54 currentLayout = 1;
thatd86f49d2015-03-15 00:56:57 +010055 CapsLockOn = false;
Dees_Troy51a0e822012-09-05 15:24:24 -040056
57 if (!node) return;
58
Ethan Yonker21ff02a2015-02-18 14:35:00 -060059 mHighlightColor = LoadAttrColor(FindNode(node, "highlight"), "color", &hasHighlight);
60 mCapsHighlightColor = LoadAttrColor(FindNode(node, "capshighlight"), "color", &hasCapsHighlight);
Ethan Yonkerc3120d42014-02-17 07:55:00 -060061
thatf256b722015-05-23 20:44:12 +020062 child = FindNode(node, "keymargin");
63 mKeyMarginX = LoadAttrIntScaleX(child, "x", 0);
64 mKeyMarginY = LoadAttrIntScaleY(child, "y", 0);
65
66 child = FindNode(node, "background");
67 mBackgroundColor = LoadAttrColor(child, "color", COLOR(32,32,32,255));
68
69 child = FindNode(node, "key-alphanumeric");
70 mFont = PageManager::GetResources()->FindFont(LoadAttrString(child, "font", "keylabel"));
71 mFontColor = LoadAttrColor(child, "textcolor", COLOR(255,255,255,255));
72 mKeyColorAlphanumeric = LoadAttrColor(child, "color", COLOR(0,0,0,0));
73
74 child = FindNode(node, "key-other");
75 mSmallFont = PageManager::GetResources()->FindFont(LoadAttrString(child, "font", "keylabel-small"));
76 mFontColorSmall = LoadAttrColor(child, "textcolor", COLOR(192,192,192,255));
77 mKeyColorOther = LoadAttrColor(child, "color", COLOR(0,0,0,0));
78
79 child = FindNode(node, "longpress");
80 mLongpressFont = PageManager::GetResources()->FindFont(LoadAttrString(child, "font", "keylabel-longpress"));
81 mLongpressFontColor = LoadAttrColor(child, "textcolor", COLOR(128,128,128,255));
82
83 LoadKeyLabels(node, 0); // load global key labels
84
thatd86f49d2015-03-15 00:56:57 +010085 // compatibility ugliness: resources should be specified in the layouts themselves instead
Dees_Troy51a0e822012-09-05 15:24:24 -040086 // Load the images for the different layouts
Ethan Yonker21ff02a2015-02-18 14:35:00 -060087 child = FindNode(node, "layout");
Dees_Troy51a0e822012-09-05 15:24:24 -040088 if (child)
89 {
90 layoutindex = 1;
91 strcpy(resource, "resource1");
92 attr = child->first_attribute(resource);
93 while (attr && layoutindex < (MAX_KEYBOARD_LAYOUTS + 1)) {
thatd86f49d2015-03-15 00:56:57 +010094 layouts[layoutindex - 1].keyboardImg = LoadAttrImage(child, resource);
Dees_Troy51a0e822012-09-05 15:24:24 -040095
96 layoutindex++;
97 resource[8] = (char)(layoutindex + 48);
98 attr = child->first_attribute(resource);
99 }
100 }
101
102 // Check the first image to get height and width
thatd86f49d2015-03-15 00:56:57 +0100103 if (layouts[0].keyboardImg && layouts[0].keyboardImg->GetResource())
Dees_Troy51a0e822012-09-05 15:24:24 -0400104 {
thatf256b722015-05-23 20:44:12 +0200105 mRenderW = layouts[0].keyboardImg->GetWidth();
106 mRenderH = layouts[0].keyboardImg->GetHeight();
Dees_Troy51a0e822012-09-05 15:24:24 -0400107 }
108
109 // Load all of the layout maps
110 layoutindex = 1;
111 strcpy(layout, "layout1");
Ethan Yonker21ff02a2015-02-18 14:35:00 -0600112 keylayout = FindNode(node, layout);
Dees_Troy51a0e822012-09-05 15:24:24 -0400113 while (keylayout)
114 {
115 if (layoutindex > MAX_KEYBOARD_LAYOUTS) {
Dees_Troy2673cec2013-04-02 20:22:16 +0000116 LOGERR("Too many layouts defined in keyboard.\n");
Dees_Troy51a0e822012-09-05 15:24:24 -0400117 return;
118 }
119
thatf256b722015-05-23 20:44:12 +0200120 LoadKeyLabels(keylayout, layoutindex); // load per-layout key labels
121
thatd86f49d2015-03-15 00:56:57 +0100122 Layout& lay = layouts[layoutindex - 1];
123
Dees_Troy51a0e822012-09-05 15:24:24 -0400124 child = keylayout->first_node("keysize");
thatd86f49d2015-03-15 00:56:57 +0100125 keyHeight = LoadAttrIntScaleY(child, "height", 0);
126 keyWidth = LoadAttrIntScaleX(child, "width", 0);
127 // compatibility ugliness: capslock="0" means that this is the caps layout. Also it has nothing to do with keysize.
128 lay.is_caps = (LoadAttrInt(child, "capslock", 1) == 0);
129 // compatibility ugliness: revert_layout has nothing to do with keysize.
130 lay.revert_layout = LoadAttrInt(child, "revert_layout", -1);
Dees_Troy51a0e822012-09-05 15:24:24 -0400131
132 rowindex = 1;
133 Yindex = 0;
134 strcpy(row, "row1");
135 keyrow = keylayout->first_node(row);
136 while (keyrow)
137 {
138 if (rowindex > MAX_KEYBOARD_ROWS) {
Dees_Troy2673cec2013-04-02 20:22:16 +0000139 LOGERR("Too many rows defined in keyboard.\n");
Dees_Troy51a0e822012-09-05 15:24:24 -0400140 return;
141 }
142
143 Yindex += keyHeight;
thatd86f49d2015-03-15 00:56:57 +0100144 lay.row_end_y[rowindex - 1] = Yindex;
Dees_Troy51a0e822012-09-05 15:24:24 -0400145
146 keyindex = 1;
147 Xindex = 0;
148 strcpy(key, "key01");
149 attr = keyrow->first_attribute(key);
150
151 while (attr) {
Dees_Troy51a0e822012-09-05 15:24:24 -0400152 if (keyindex > MAX_KEYBOARD_KEYS) {
Dees_Troy2673cec2013-04-02 20:22:16 +0000153 LOGERR("Too many keys defined in a keyboard row.\n");
Dees_Troy51a0e822012-09-05 15:24:24 -0400154 return;
155 }
156
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 key info on layout%i, row%i, key%dd.\n", layoutindex, rowindex, keyindex);
Dees_Troy51a0e822012-09-05 15:24:24 -0400161 return;
162 }
163
thatd86f49d2015-03-15 00:56:57 +0100164 if (ParseKey(keyinfo, lay.keys[rowindex - 1][keyindex - 1], Xindex, keyWidth, false))
that1a7ba972015-02-01 19:48:19 +0100165 LOGERR("Invalid key info on layout%i, row%i, key%02i.\n", layoutindex, rowindex, keyindex);
Dees_Troy51a0e822012-09-05 15:24:24 -0400166
Dees_Troy51a0e822012-09-05 15:24:24 -0400167
168 // PROCESS LONG PRESS INFO IF EXISTS
169 sprintf(longpress, "long%02i", keyindex);
170 attr = keyrow->first_attribute(longpress);
171 if (attr) {
that1a7ba972015-02-01 19:48:19 +0100172 const char* keyinfo = attr->value();
Dees_Troy51a0e822012-09-05 15:24:24 -0400173
174 if (strlen(keyinfo) == 0) {
Dees_Troy2673cec2013-04-02 20:22:16 +0000175 LOGERR("No long press info on layout%i, row%i, long%dd.\n", layoutindex, rowindex, keyindex);
Dees_Troy51a0e822012-09-05 15:24:24 -0400176 return;
177 }
178
thatd86f49d2015-03-15 00:56:57 +0100179 if (ParseKey(keyinfo, lay.keys[rowindex - 1][keyindex - 1], Xindex, keyWidth, true))
that1a7ba972015-02-01 19:48:19 +0100180 LOGERR("Invalid long press key info on layout%i, row%i, long%02i.\n", layoutindex, rowindex, keyindex);
Dees_Troy51a0e822012-09-05 15:24:24 -0400181 }
182 keyindex++;
183 sprintf(key, "key%02i", keyindex);
184 attr = keyrow->first_attribute(key);
185 }
186 rowindex++;
187 row[3] = (char)(rowindex + 48);
188 keyrow = keylayout->first_node(row);
189 }
190 layoutindex++;
191 layout[6] = (char)(layoutindex + 48);
Ethan Yonker21ff02a2015-02-18 14:35:00 -0600192 keylayout = FindNode(node, layout);
Dees_Troy51a0e822012-09-05 15:24:24 -0400193 }
194
thate79878b2015-03-14 23:07:23 +0100195 int x, y;
Dees_Troy51a0e822012-09-05 15:24:24 -0400196 // Load the placement
thatf256b722015-05-23 20:44:12 +0200197 LoadPlacement(FindNode(node, "placement"), &x, &y, &mRenderW, &mRenderH);
198 SetRenderPos(x, y, mRenderW, mRenderH);
Dees_Troy51a0e822012-09-05 15:24:24 -0400199 return;
200}
201
202GUIKeyboard::~GUIKeyboard()
203{
that1a7ba972015-02-01 19:48:19 +0100204}
Dees_Troy51a0e822012-09-05 15:24:24 -0400205
thate79878b2015-03-14 23:07:23 +0100206int GUIKeyboard::ParseKey(const char* keyinfo, Key& key, int& Xindex, int keyWidth, bool longpress)
that1a7ba972015-02-01 19:48:19 +0100207{
thatf256b722015-05-23 20:44:12 +0200208 key.layout = 0;
that1a7ba972015-02-01 19:48:19 +0100209 int keychar = 0;
210 if (strlen(keyinfo) == 1) {
211 // This is a single key, simple definition
212 keychar = keyinfo[0];
213 } else {
214 // This key has extra data: {keywidth}:{what_the_key_does}
Ethan Yonker63e414f2015-02-06 15:44:39 -0600215 keyWidth = scale_theme_x(atoi(keyinfo));
that1a7ba972015-02-01 19:48:19 +0100216
217 const char* ptr = keyinfo;
218 while (*ptr > 32 && *ptr != ':')
219 ptr++;
220 if (*ptr != ':')
221 return -1; // no colon is an error
222 ptr++;
223
224 if (*ptr == 0) { // This is an empty area
225 keychar = 0;
226 } else if (strlen(ptr) == 1) { // This is the character that this key uses
227 keychar = *ptr;
228 } else if (*ptr == 'c') { // This is an ASCII character code: "c:{number}"
229 keychar = atoi(ptr + 2);
230 } else if (*ptr == 'l') { // This is a different layout: "layout{number}"
231 keychar = KEYBOARD_LAYOUT;
232 key.layout = atoi(ptr + 6);
233 } else if (*ptr == 'a') { // This is an action: "action"
234 keychar = KEYBOARD_ACTION;
235 } else
236 return -1;
237 }
238
239 if (longpress) {
240 key.longpresskey = keychar;
241 } else {
242 key.key = keychar;
243 Xindex += keyWidth;
244 key.end_x = Xindex - 1;
245 }
246
247 return 0;
Dees_Troy51a0e822012-09-05 15:24:24 -0400248}
249
thatf256b722015-05-23 20:44:12 +0200250void GUIKeyboard::LoadKeyLabels(xml_node<>* parent, int layout)
251{
252 for (xml_node<>* child = parent->first_node(); child; child = child->next_sibling()) {
253 std::string name = child->name();
254 if (name == "keylabel") {
255 std::string keydef = LoadAttrString(child, "key", "");
256 Key tempkey;
257 int dummyX;
258 if (ParseKey(keydef.c_str(), tempkey, dummyX, 0, false) == 0) {
259 KeyLabel keylabel;
260 keylabel.key = tempkey.key;
261 keylabel.layout_from = layout;
262 keylabel.layout_to = tempkey.layout;
263 keylabel.text = LoadAttrString(child, "text", "");
264 keylabel.image = LoadAttrImage(child, "resource");
265 mKeyLabels.push_back(keylabel);
266 } else {
267 LOGERR("Ignoring invalid keylabel in layout %d: '%s'.\n", layout, keydef.c_str());
268 }
269 }
270 }
271}
272
Dees_Troy51a0e822012-09-05 15:24:24 -0400273int GUIKeyboard::Render(void)
274{
275 if (!isConditionTrue())
276 {
277 mRendered = false;
278 return 0;
279 }
280
thatd86f49d2015-03-15 00:56:57 +0100281 Layout& lay = layouts[currentLayout - 1];
Dees_Troy51a0e822012-09-05 15:24:24 -0400282
thatd86f49d2015-03-15 00:56:57 +0100283 if (lay.keyboardImg && lay.keyboardImg->GetResource())
thatf256b722015-05-23 20:44:12 +0200284 gr_blit(lay.keyboardImg->GetResource(), 0, 0, mRenderW, mRenderH, mRenderX, mRenderY);
285 else {
286 gr_color(mBackgroundColor.red, mBackgroundColor.green, mBackgroundColor.blue, mBackgroundColor.alpha);
287 gr_fill(mRenderX, mRenderY, mRenderW, mRenderH);
288 // draw keys
289 int y1 = 0;
290 for (int row = 0; row < MAX_KEYBOARD_ROWS; ++row) {
291 int rowY = mRenderY + y1;
292 int rowH = lay.row_end_y[row] - y1;
293 y1 = lay.row_end_y[row];
294 int x1 = 0;
295 for (int col = 0; col < MAX_KEYBOARD_KEYS; ++col) {
296 Key& key = lay.keys[row][col];
297 int keyY = rowY;
298 int keyH = rowH;
299 int keyX = mRenderX + x1;
300 int keyW = key.end_x - x1;
301 x1 = key.end_x;
302
303 unsigned char keychar = key.key;
304 if (!keychar)
305 continue;
306
307 // draw a single key
308 // key background
309 COLOR& c = (keychar >= 32 && keychar < 127) ? mKeyColorAlphanumeric : mKeyColorOther;
310 gr_color(c.red, c.green, c.blue, c.alpha);
311 keyX += mKeyMarginX;
312 keyY += mKeyMarginY;
313 keyW -= mKeyMarginX * 2;
314 keyH -= mKeyMarginY * 2;
315 gr_fill(keyX, keyY, keyW, keyH);
316
317 // key label
318 FontResource* labelFont = mFont;
319 string labelText;
320 ImageResource* labelImage = NULL;
321 if (keychar > 32 && keychar < 127) {
322 labelText = (char) keychar;
323 gr_color(mFontColor.red, mFontColor.green, mFontColor.blue, mFontColor.alpha);
324 }
325 else {
326 /*
327 static const char* shiftLabels[] = {"abc", "ABC", "?123", "~\\{"};
328 switch (keychar) {
329 case KEYBOARD_LAYOUT:
330 labelText = shiftLabels[key.layout - 1];
331 break;
332 case KEYBOARD_BACKSPACE:
333 labelText = "Bksp";
334 break;
335 case KEYBOARD_ACTION:
336 labelText = "Enter";
337 break;
338 }
339 */
340 // search for a special key label
341 for (std::vector<KeyLabel>::iterator it = mKeyLabels.begin(); it != mKeyLabels.end(); ++it) {
342 if (it->layout_from > 0 && it->layout_from != currentLayout)
343 continue; // this label is for another layout
344 if (it->key == key.key && it->layout_to == key.layout)
345 {
346 // found a label
347 labelText = it->text;
348 labelImage = it->image;
349 break;
350 }
351 }
352 labelFont = mSmallFont;
353 gr_color(mFontColorSmall.red, mFontColorSmall.green, mFontColorSmall.blue, mFontColorSmall.alpha);
354 }
355
356 if (labelImage)
357 {
358 int w = labelImage->GetWidth();
359 int h = labelImage->GetHeight();
360 int x = keyX + (keyW - w) / 2;
361 int y = keyY + (keyH - h) / 2;
362 gr_blit(labelImage->GetResource(), 0, 0, w, h, x, y);
363 }
364 else if (!labelText.empty())
365 {
366 void* fontResource = labelFont->GetResource();
367 int textW = gr_measureEx(labelText.c_str(), fontResource);
368 int textH = labelFont->GetHeight();
369 int textX = keyX + (keyW - textW) / 2;
370 int textY = keyY + (keyH - textH) / 2;
371 gr_textEx(textX, textY, labelText.c_str(), fontResource);
372 }
373
374 // longpress key label (only if font is defined)
375 keychar = key.longpresskey;
376 if (keychar > 32 && keychar < 127 && mLongpressFont->GetResource()) {
377 void* fontResource = mLongpressFont->GetResource();
378 gr_color(mLongpressFontColor.red, mLongpressFontColor.green, mLongpressFontColor.blue, mLongpressFontColor.alpha);
379 string text(1, keychar);
380 int textH = mLongpressFont->GetHeight();
381 int textW = gr_measureEx(text.c_str(), fontResource);
382 int textX = keyX + keyW - 5 - textW; // TODO: configure these offsets
383 int textY = keyY + 0;
384 gr_textEx(textX, textY, text.c_str(), fontResource);
385 }
386 }
387 }
388 }
Dees_Troy51a0e822012-09-05 15:24:24 -0400389
Ethan Yonkerc3120d42014-02-17 07:55:00 -0600390 // Draw highlight for capslock
thatf256b722015-05-23 20:44:12 +0200391 // TODO: integrate with key drawing
thatd86f49d2015-03-15 00:56:57 +0100392 if (hasCapsHighlight && lay.is_caps && CapsLockOn) {
Ethan Yonkerc3120d42014-02-17 07:55:00 -0600393 gr_color(mCapsHighlightColor.red, mCapsHighlightColor.green, mCapsHighlightColor.blue, mCapsHighlightColor.alpha);
394 for (int indexy=0; indexy<MAX_KEYBOARD_ROWS; indexy++) {
395 for (int indexx=0; indexx<MAX_KEYBOARD_KEYS; indexx++) {
thatd86f49d2015-03-15 00:56:57 +0100396 if ((int)lay.keys[indexy][indexx].key == KEYBOARD_LAYOUT && (int)lay.keys[indexy][indexx].layout == lay.revert_layout) {
397 int boxheight, boxwidth, x;
Ethan Yonkerc3120d42014-02-17 07:55:00 -0600398 if (indexy == 0)
thatd86f49d2015-03-15 00:56:57 +0100399 boxheight = lay.row_end_y[indexy];
Ethan Yonkerc3120d42014-02-17 07:55:00 -0600400 else
thatd86f49d2015-03-15 00:56:57 +0100401 boxheight = lay.row_end_y[indexy] - lay.row_end_y[indexy - 1];
Ethan Yonkerc3120d42014-02-17 07:55:00 -0600402 if (indexx == 0) {
403 x = mRenderX;
thatd86f49d2015-03-15 00:56:57 +0100404 boxwidth = lay.keys[indexy][indexx].end_x;
Ethan Yonkerc3120d42014-02-17 07:55:00 -0600405 } else {
thatd86f49d2015-03-15 00:56:57 +0100406 x = mRenderX + lay.keys[indexy][indexx - 1].end_x;
407 boxwidth = lay.keys[indexy][indexx].end_x - lay.keys[indexy][indexx - 1].end_x;
Ethan Yonkerc3120d42014-02-17 07:55:00 -0600408 }
thatd86f49d2015-03-15 00:56:57 +0100409 gr_fill(x, mRenderY + lay.row_end_y[indexy - 1], boxwidth, boxheight);
Ethan Yonkerc3120d42014-02-17 07:55:00 -0600410 }
411 }
412 }
413 }
414
thatf256b722015-05-23 20:44:12 +0200415 // TODO: integrate with key drawing
Dees_Troy30b962e2012-10-19 20:48:59 -0400416 if (hasHighlight && highlightRenderCount != 0) {
417 int boxheight, boxwidth, x;
418 if (rowY == 0)
thatd86f49d2015-03-15 00:56:57 +0100419 boxheight = lay.row_end_y[rowY];
Dees_Troy30b962e2012-10-19 20:48:59 -0400420 else
thatd86f49d2015-03-15 00:56:57 +0100421 boxheight = lay.row_end_y[rowY] - lay.row_end_y[rowY - 1];
Dees_Troy30b962e2012-10-19 20:48:59 -0400422 if (colX == 0) {
423 x = mRenderX;
thatd86f49d2015-03-15 00:56:57 +0100424 boxwidth = lay.keys[rowY][colX].end_x;
Dees_Troy30b962e2012-10-19 20:48:59 -0400425 } else {
thatd86f49d2015-03-15 00:56:57 +0100426 x = mRenderX + lay.keys[rowY][colX - 1].end_x;
427 boxwidth = lay.keys[rowY][colX].end_x - lay.keys[rowY][colX - 1].end_x;
Dees_Troy30b962e2012-10-19 20:48:59 -0400428 }
429 gr_color(mHighlightColor.red, mHighlightColor.green, mHighlightColor.blue, mHighlightColor.alpha);
thatd86f49d2015-03-15 00:56:57 +0100430 gr_fill(x, mRenderY + lay.row_end_y[rowY - 1], boxwidth, boxheight);
Dees_Troy30b962e2012-10-19 20:48:59 -0400431 if (highlightRenderCount > 0)
432 highlightRenderCount--;
433 } else
434 mRendered = true;
435
thatd86f49d2015-03-15 00:56:57 +0100436 return 0;
Dees_Troy51a0e822012-09-05 15:24:24 -0400437}
438
439int GUIKeyboard::Update(void)
440{
441 if (!isConditionTrue()) return (mRendered ? 2 : 0);
442 if (!mRendered) return 2;
443
444 return 0;
445}
446
447int GUIKeyboard::SetRenderPos(int x, int y, int w, int h)
448{
thatf256b722015-05-23 20:44:12 +0200449 RenderObject::SetRenderPos(x, y, w, h);
Dees_Troy51a0e822012-09-05 15:24:24 -0400450 SetActionPos(mRenderX, mRenderY, mRenderW, mRenderH);
451 return 0;
452}
453
thate79878b2015-03-14 23:07:23 +0100454GUIKeyboard::Key* GUIKeyboard::HitTestKey(int x, int y)
Dees_Troy51a0e822012-09-05 15:24:24 -0400455{
thate79878b2015-03-14 23:07:23 +0100456 if (!IsInRegion(x, y))
457 return NULL;
458
459 int rely = y - mRenderY;
460 int relx = x - mRenderX;
461
thatd86f49d2015-03-15 00:56:57 +0100462 Layout& lay = layouts[currentLayout - 1];
463
thate79878b2015-03-14 23:07:23 +0100464 // Find the correct row
465 int row;
466 for (row = 0; row < MAX_KEYBOARD_ROWS; ++row) {
thatd86f49d2015-03-15 00:56:57 +0100467 if (lay.row_end_y[row] > rely)
thate79878b2015-03-14 23:07:23 +0100468 break;
469 }
470 if (row == MAX_KEYBOARD_ROWS)
471 return NULL;
472
473 // Find the correct key (column)
474 int col;
475 int x1 = 0;
476 for (col = 0; col < MAX_KEYBOARD_KEYS; ++col) {
thatd86f49d2015-03-15 00:56:57 +0100477 Key& key = lay.keys[row][col];
thate79878b2015-03-14 23:07:23 +0100478 if (x1 <= relx && relx < key.end_x && key.key != 0) {
479 // This is the key that was pressed!
480 rowY = row;
481 colX = col;
482 return &key;
483 }
484 x1 = key.end_x;
485 }
486 return NULL;
Dees_Troy51a0e822012-09-05 15:24:24 -0400487}
488
489int GUIKeyboard::NotifyTouch(TOUCH_STATE state, int x, int y)
490{
thate79878b2015-03-14 23:07:23 +0100491 static int was_held = 0, startX = 0;
492 static Key* initial_key = 0;
Dees_Troy51a0e822012-09-05 15:24:24 -0400493
494 if (!isConditionTrue()) return -1;
495
496 switch (state)
497 {
498 case TOUCH_START:
thate79878b2015-03-14 23:07:23 +0100499 was_held = 0;
500 startX = x;
501 initial_key = HitTestKey(x, y);
502 if (initial_key)
503 highlightRenderCount = -1;
504 else
Dees_Troy30b962e2012-10-19 20:48:59 -0400505 highlightRenderCount = 0;
thate79878b2015-03-14 23:07:23 +0100506 mRendered = false;
Dees_Troy51a0e822012-09-05 15:24:24 -0400507 break;
thate79878b2015-03-14 23:07:23 +0100508
Dees_Troy51a0e822012-09-05 15:24:24 -0400509 case TOUCH_DRAG:
510 break;
thate79878b2015-03-14 23:07:23 +0100511
Dees_Troy51a0e822012-09-05 15:24:24 -0400512 case TOUCH_RELEASE:
thatf256b722015-05-23 20:44:12 +0200513 if (x < startX - (mRenderW * 0.5)) {
Dees_Troy30b962e2012-10-19 20:48:59 -0400514 if (highlightRenderCount != 0) {
515 highlightRenderCount = 0;
516 mRendered = false;
517 }
Dees_Troy51a0e822012-09-05 15:24:24 -0400518 PageManager::NotifyKeyboard(KEYBOARD_SWIPE_LEFT);
519 return 0;
thatf256b722015-05-23 20:44:12 +0200520 } else if (x > startX + (mRenderW * 0.5)) {
Dees_Troy30b962e2012-10-19 20:48:59 -0400521 if (highlightRenderCount != 0) {
522 highlightRenderCount = 0;
523 mRendered = false;
524 }
Dees_Troy51a0e822012-09-05 15:24:24 -0400525 PageManager::NotifyKeyboard(KEYBOARD_SWIPE_RIGHT);
526 return 0;
527 }
thate79878b2015-03-14 23:07:23 +0100528 // fall through
Dees_Troy51a0e822012-09-05 15:24:24 -0400529 case TOUCH_HOLD:
530 case TOUCH_REPEAT:
thate79878b2015-03-14 23:07:23 +0100531 if (!initial_key) {
Dees_Troy30b962e2012-10-19 20:48:59 -0400532 if (highlightRenderCount != 0) {
533 highlightRenderCount = 0;
534 mRendered = false;
535 }
Dees_Troy51a0e822012-09-05 15:24:24 -0400536 return 0;
thate79878b2015-03-14 23:07:23 +0100537 }
538
539 if (highlightRenderCount != 0) {
Dees_Troy30b962e2012-10-19 20:48:59 -0400540 if (state == TOUCH_RELEASE)
541 highlightRenderCount = 2;
542 else
543 highlightRenderCount = -1;
544 mRendered = false;
545 }
Dees_Troy51a0e822012-09-05 15:24:24 -0400546
thate79878b2015-03-14 23:07:23 +0100547 if (HitTestKey(x, y) != initial_key) {
548 // We dragged off of the starting key
549 if (highlightRenderCount != 0) {
550 highlightRenderCount = 0;
551 mRendered = false;
Dees_Troy51a0e822012-09-05 15:24:24 -0400552 }
thate79878b2015-03-14 23:07:23 +0100553 return 0;
554 } else {
555 Key& key = *initial_key;
thatd86f49d2015-03-15 00:56:57 +0100556 Layout& lay = layouts[currentLayout - 1];
thate79878b2015-03-14 23:07:23 +0100557 if (state == TOUCH_RELEASE && was_held == 0) {
558 DataManager::Vibrate("tw_keyboard_vibrate");
thatd86f49d2015-03-15 00:56:57 +0100559 if ((int)key.key == KEYBOARD_LAYOUT) {
thate79878b2015-03-14 23:07:23 +0100560 // Switch layouts
thatd86f49d2015-03-15 00:56:57 +0100561 if (lay.is_caps && key.layout == lay.revert_layout && !CapsLockOn) {
562 CapsLockOn = true; // Set the caps lock
thate79878b2015-03-14 23:07:23 +0100563 } else {
thatd86f49d2015-03-15 00:56:57 +0100564 CapsLockOn = false; // Unset the caps lock and change layouts
thate79878b2015-03-14 23:07:23 +0100565 currentLayout = key.layout;
Dees_Troy51a0e822012-09-05 15:24:24 -0400566 }
thate79878b2015-03-14 23:07:23 +0100567 mRendered = false;
568 } else if ((int)key.key == KEYBOARD_ACTION) {
569 // Action
570 highlightRenderCount = 0;
571 // Send action notification
572 PageManager::NotifyKeyboard(key.key);
thatd86f49d2015-03-15 00:56:57 +0100573 } else if ((int)key.key < KEYBOARD_SPECIAL_KEYS && (int)key.key > 0) {
574 // Regular key
575 PageManager::NotifyKeyboard(key.key);
576 if (!CapsLockOn && lay.is_caps) {
577 // caps lock was not set, change layouts
578 currentLayout = lay.revert_layout;
579 mRendered = false;
580 }
Dees_Troy51a0e822012-09-05 15:24:24 -0400581 }
thate79878b2015-03-14 23:07:23 +0100582 } else if (state == TOUCH_HOLD) {
583 was_held = 1;
584 if ((int)key.key == KEYBOARD_BACKSPACE) {
585 // Repeat backspace
586 PageManager::NotifyKeyboard(key.key);
587 } else if ((int)key.longpresskey < KEYBOARD_SPECIAL_KEYS && (int)key.longpresskey > 0) {
588 // Long Press Key
589 DataManager::Vibrate("tw_keyboard_vibrate");
590 PageManager::NotifyKeyboard(key.longpresskey);
591 }
592 } else if (state == TOUCH_REPEAT) {
593 was_held = 1;
594 if ((int)key.key == KEYBOARD_BACKSPACE) {
595 // Repeat backspace
596 PageManager::NotifyKeyboard(key.key);
597 }
Dees_Troy51a0e822012-09-05 15:24:24 -0400598 }
599 }
600 break;
601 }
602
603 return 0;
604}