blob: 458eb5519efe816b113fd75f47e34cb5d8df1a78 [file] [log] [blame]
Dees Troy3be70a82013-10-22 14:25:12 +00001/*
bigbiffd58ba182020-03-23 10:02:29 -04002 Copyright 2012 to 2020 TeamWin
Dees Troy3be70a82013-10-22 14:25:12 +00003 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*/
18
Dees_Troy51a0e822012-09-05 15:24:24 -040019// input.cpp - GUIInput object
20
21#include <linux/input.h>
22#include <pthread.h>
23#include <stdarg.h>
24#include <stdio.h>
25#include <stdlib.h>
26#include <string.h>
27#include <fcntl.h>
28#include <sys/reboot.h>
29#include <sys/stat.h>
30#include <sys/time.h>
31#include <sys/mman.h>
32#include <sys/types.h>
33#include <sys/ioctl.h>
34#include <time.h>
35#include <unistd.h>
36#include <stdlib.h>
37
38#include <string>
39
40extern "C" {
Dees_Troy2673cec2013-04-02 20:22:16 +000041#include "../twcommon.h"
Dees_Troy51a0e822012-09-05 15:24:24 -040042}
Ethan Yonkerfbb43532015-12-28 21:54:50 +010043#include "../minuitwrp/minui.h"
bigbiffd58ba182020-03-23 10:02:29 -040044#include "../minuitwrp/truetype.hpp"
Dees_Troy51a0e822012-09-05 15:24:24 -040045
46#include "rapidxml.hpp"
47#include "objects.hpp"
48#include "../data.hpp"
49
Ethan Yonkera5db7122016-03-14 15:47:09 -050050#define TW_INPUT_NO_UPDATE -1000 // Magic value for HandleTextLocation when no change in scrolling has occurred
51
Dees_Troy51a0e822012-09-05 15:24:24 -040052GUIInput::GUIInput(xml_node<>* node)
Vojtech Bocekede51c52014-02-07 23:58:09 +010053 : GUIObject(node)
Dees_Troy51a0e822012-09-05 15:24:24 -040054{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +020055 xml_attribute<>* attr;
56 xml_node<>* child;
Dees_Troy51a0e822012-09-05 15:24:24 -040057
Vojtech Bocekfafb0c52013-07-25 22:53:02 +020058 mInputText = NULL;
Dees_Troy51a0e822012-09-05 15:24:24 -040059 mAction = NULL;
60 mBackground = NULL;
61 mCursor = NULL;
62 mFont = NULL;
Vojtech Bocekfafb0c52013-07-25 22:53:02 +020063 mRendered = false;
Dees_Troy51a0e822012-09-05 15:24:24 -040064 HasMask = false;
65 DrawCursor = false;
66 isLocalChange = true;
67 HasAllowed = false;
68 HasDisabled = false;
Ethan Yonkera5db7122016-03-14 15:47:09 -050069 cursorX = textWidth = scrollingX = mFontHeight = mFontY = lastX = 0;
Dees_Troy51a0e822012-09-05 15:24:24 -040070 mBackgroundX = mBackgroundY = mBackgroundW = mBackgroundH = MinLen = MaxLen = 0;
71 mCursorLocation = -1; // -1 is always the end of the string
72 CursorWidth = 3;
73 ConvertStrToColor("black", &mBackgroundColor);
74 ConvertStrToColor("white", &mCursorColor);
Sultan Qasim Khan14138d92016-04-04 04:11:25 -040075 mValue = "";
Ethan Yonkera5db7122016-03-14 15:47:09 -050076 displayValue = "";
Dees_Troy51a0e822012-09-05 15:24:24 -040077
Vojtech Bocekfafb0c52013-07-25 22:53:02 +020078 if (!node)
79 return;
Dees_Troy51a0e822012-09-05 15:24:24 -040080
Vojtech Bocekfafb0c52013-07-25 22:53:02 +020081 // Load text directly from the node
82 mInputText = new GUIText(node);
Dees_Troy51a0e822012-09-05 15:24:24 -040083 // Load action directly from the node
84 mAction = new GUIAction(node);
85
86 if (mInputText->Render() < 0)
Vojtech Bocekfafb0c52013-07-25 22:53:02 +020087 {
88 delete mInputText;
89 mInputText = NULL;
90 }
Dees_Troy51a0e822012-09-05 15:24:24 -040091
92 // Load the background
Ethan Yonker21ff02a2015-02-18 14:35:00 -060093 child = FindNode(node, "background");
Dees_Troy51a0e822012-09-05 15:24:24 -040094 if (child)
95 {
thatf6ed8fc2015-02-14 20:23:16 +010096 mBackground = LoadAttrImage(child, "resource");
97 mBackgroundColor = LoadAttrColor(child, "color", mBackgroundColor);
Dees_Troy51a0e822012-09-05 15:24:24 -040098 }
99 if (mBackground && mBackground->GetResource())
100 {
thatf6ed8fc2015-02-14 20:23:16 +0100101 mBackgroundW = mBackground->GetWidth();
102 mBackgroundH = mBackground->GetHeight();
Dees_Troy51a0e822012-09-05 15:24:24 -0400103 }
104
105 // Load the cursor color
Ethan Yonker21ff02a2015-02-18 14:35:00 -0600106 child = FindNode(node, "cursor");
Dees_Troy51a0e822012-09-05 15:24:24 -0400107 if (child)
108 {
thatf6ed8fc2015-02-14 20:23:16 +0100109 mCursor = LoadAttrImage(child, "resource");
110 mCursorColor = LoadAttrColor(child, "color", mCursorColor);
Dees_Troy51a0e822012-09-05 15:24:24 -0400111 attr = child->first_attribute("hasfocus");
112 if (attr)
113 {
Ethan Yonker21ff02a2015-02-18 14:35:00 -0600114 std::string focus = attr->value();
115 SetInputFocus(atoi(focus.c_str()));
Dees_Troy51a0e822012-09-05 15:24:24 -0400116 }
Ethan Yonker21ff02a2015-02-18 14:35:00 -0600117 CursorWidth = LoadAttrIntScaleX(child, "width", CursorWidth);
Dees_Troy51a0e822012-09-05 15:24:24 -0400118 }
119 DrawCursor = HasInputFocus;
120
thatf6ed8fc2015-02-14 20:23:16 +0100121 // Load the font
Ethan Yonker21ff02a2015-02-18 14:35:00 -0600122 child = FindNode(node, "font");
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200123 if (child)
124 {
thatf6ed8fc2015-02-14 20:23:16 +0100125 mFont = LoadAttrFont(child, "resource");
Ethan Yonker58f21322018-08-24 11:17:36 -0500126 if (mFont && mFont->GetResource())
127 mFontHeight = mFont->GetHeight();
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200128 }
Dees_Troy51a0e822012-09-05 15:24:24 -0400129
Ethan Yonker21ff02a2015-02-18 14:35:00 -0600130 child = FindNode(node, "data");
Dees_Troy51a0e822012-09-05 15:24:24 -0400131 if (child)
132 {
133 attr = child->first_attribute("name");
134 if (attr)
135 mVariable = attr->value();
136 attr = child->first_attribute("default");
137 if (attr)
138 DataManager::SetValue(mVariable, attr->value());
Ethan Yonker21ff02a2015-02-18 14:35:00 -0600139 mMask = LoadAttrString(child, "mask");
140 HasMask = !mMask.empty();
Dees_Troy51a0e822012-09-05 15:24:24 -0400141 }
142
143 // Load input restrictions
Ethan Yonker21ff02a2015-02-18 14:35:00 -0600144 child = FindNode(node, "restrict");
Dees_Troy51a0e822012-09-05 15:24:24 -0400145 if (child)
146 {
Ethan Yonker21ff02a2015-02-18 14:35:00 -0600147 MinLen = LoadAttrInt(child, "minlen", MinLen);
148 MaxLen = LoadAttrInt(child, "maxlen", MaxLen);
149 AllowedList = LoadAttrString(child, "allow");
150 HasAllowed = !AllowedList.empty();
151 DisabledList = LoadAttrString(child, "disable");
152 HasDisabled = !DisabledList.empty();
Dees_Troy51a0e822012-09-05 15:24:24 -0400153 }
154
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200155 // Load the placement
Ethan Yonker21ff02a2015-02-18 14:35:00 -0600156 LoadPlacement(FindNode(node, "placement"), &mRenderX, &mRenderY, &mRenderW, &mRenderH);
Dees_Troy51a0e822012-09-05 15:24:24 -0400157 SetActionPos(mRenderX, mRenderY, mRenderW, mRenderH);
158
159 if (mInputText && mFontHeight && mFontHeight < (unsigned)mRenderH) {
160 mFontY = ((mRenderH - mFontHeight) / 2) + mRenderY;
161 mInputText->SetRenderPos(mRenderX, mFontY);
162 } else
163 mFontY = mRenderY;
164
165 if (mInputText)
Ethan Yonkera5db7122016-03-14 15:47:09 -0500166 mInputText->SetMaxWidth(0);
Dees_Troy51a0e822012-09-05 15:24:24 -0400167}
168
169GUIInput::~GUIInput()
170{
thatf6ed8fc2015-02-14 20:23:16 +0100171 delete mInputText;
172 delete mAction;
Dees_Troy51a0e822012-09-05 15:24:24 -0400173}
174
Ethan Yonkera5db7122016-03-14 15:47:09 -0500175void GUIInput::HandleTextLocation(int x) {
176 mRendered = false;
177 if (textWidth <= mRenderW) {
178 if (x != TW_INPUT_NO_UPDATE)
179 lastX = x;
180 scrollingX = 0;
181 return;
182 }
183 if (scrollingX + textWidth < mRenderW) {
184 scrollingX = mRenderW - textWidth;
185 }
186
187 if (x == TW_INPUT_NO_UPDATE)
188 return;
189
190 scrollingX += x - lastX;
191 if (scrollingX > 0)
192 scrollingX = 0;
193 else if (scrollingX + textWidth < mRenderW)
194 scrollingX = mRenderW - textWidth;
195 lastX = x;
196}
197
Sultan Qasim Khan14138d92016-04-04 04:11:25 -0400198void GUIInput::UpdateDisplayText() {
Dees_Troy51a0e822012-09-05 15:24:24 -0400199 void* fontResource = NULL;
200
Ethan Yonkera5db7122016-03-14 15:47:09 -0500201 if (mFont) {
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200202 fontResource = mFont->GetResource();
Ethan Yonkera5db7122016-03-14 15:47:09 -0500203 } else {
204 textWidth = 0;
205 return;
206 }
Dees_Troy51a0e822012-09-05 15:24:24 -0400207
Sultan Qasim Khan14138d92016-04-04 04:11:25 -0400208 DataManager::GetValue(mVariable, mValue);
Dees_Troy51a0e822012-09-05 15:24:24 -0400209 if (HasMask) {
Sultan Qasim Khan14138d92016-04-04 04:11:25 -0400210 int index, string_size = mValue.size();
Dees_Troy51a0e822012-09-05 15:24:24 -0400211 string maskedValue;
212 for (index=0; index<string_size; index++)
213 maskedValue += mMask;
214 displayValue = maskedValue;
Sultan Qasim Khan14138d92016-04-04 04:11:25 -0400215 } else {
216 displayValue = mValue;
Dees_Troy51a0e822012-09-05 15:24:24 -0400217 }
Sultan Qasim Khan14138d92016-04-04 04:11:25 -0400218
bigbiffd58ba182020-03-23 10:02:29 -0400219 textWidth = twrpTruetype::gr_ttf_measureEx(displayValue.c_str(), fontResource);
Ethan Yonkera5db7122016-03-14 15:47:09 -0500220}
221
222void GUIInput::HandleCursorByTouch(int x) {
223// Uses x to find mCursorLocation and cursorX
224 if (displayValue.size() == 0) {
225 mCursorLocation = -1;
226 cursorX = mRenderX;
227 return;
Dees_Troy51a0e822012-09-05 15:24:24 -0400228 }
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200229
Ethan Yonkera5db7122016-03-14 15:47:09 -0500230 void* fontResource = NULL;
231 if (mFont) {
232 fontResource = mFont->GetResource();
233 } else {
234 return;
235 }
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200236
Ethan Yonkera5db7122016-03-14 15:47:09 -0500237 string cursorString;
238 unsigned index = 0, displaySize = displayValue.size();
239 int prevX = mRenderX + scrollingX;
Dees_Troy51a0e822012-09-05 15:24:24 -0400240
Matt Mowera8a89d12016-12-30 18:10:37 -0600241 for (index = 0; index <= displaySize; index++) {
Ethan Yonkera5db7122016-03-14 15:47:09 -0500242 cursorString = displayValue.substr(0, index);
bigbiffd58ba182020-03-23 10:02:29 -0400243 cursorX = twrpTruetype::gr_ttf_measureEx(cursorString.c_str(), fontResource) + mRenderX + scrollingX;
Ethan Yonkera5db7122016-03-14 15:47:09 -0500244 if (cursorX > x) {
245 if (index > 0 && x <= cursorX - ((x - prevX) / 2) && prevX >= mRenderX) {
246 // This helps make sure that we can place the cursor before the very first char if the first char is
247 // is fully visible while also still letting us place the cursor after the last char if fully visible
248 mCursorLocation = index - 1;
249 cursorX = prevX;
250 return;
Dees_Troy51a0e822012-09-05 15:24:24 -0400251 }
Ethan Yonkera5db7122016-03-14 15:47:09 -0500252 mCursorLocation = index;
253 if (cursorX > mRenderX + mRenderW) {
254 cursorX = prevX; // This makes sure that the cursor doesn't get placed after the end of the input box
Dees_Troy51a0e822012-09-05 15:24:24 -0400255 mCursorLocation--;
Ethan Yonkera5db7122016-03-14 15:47:09 -0500256 return;
Dees_Troy51a0e822012-09-05 15:24:24 -0400257 }
Ethan Yonkera5db7122016-03-14 15:47:09 -0500258 if (cursorX >= mRenderX) {
259 return; // This makes sure that the cursor doesn't get placed before the beginning of the input box
Dees_Troy51a0e822012-09-05 15:24:24 -0400260 }
261 }
Ethan Yonkera5db7122016-03-14 15:47:09 -0500262 prevX = cursorX;
Dees_Troy51a0e822012-09-05 15:24:24 -0400263 }
Ethan Yonkera5db7122016-03-14 15:47:09 -0500264 mCursorLocation = -1; // x is at or past the end of the string
265}
266
267void GUIInput::HandleCursorByText() {
Matt Mowera8a89d12016-12-30 18:10:37 -0600268// Uses mCursorLocation to find cursorX
Ethan Yonkera5db7122016-03-14 15:47:09 -0500269 if (!DrawCursor)
270 return;
271
272 void* fontResource = NULL;
273 if (mFont) {
274 fontResource = mFont->GetResource();
275 } else {
276 return;
277 }
278
Sultan Qasim Khan14138d92016-04-04 04:11:25 -0400279 int cursorTextWidth = textWidth; // width of text to the left of the cursor
Ethan Yonkera5db7122016-03-14 15:47:09 -0500280
281 if (mCursorLocation != -1) {
282 string cursorDisplay = displayValue;
283 cursorDisplay.resize(mCursorLocation);
bigbiffd58ba182020-03-23 10:02:29 -0400284 cursorTextWidth = twrpTruetype::gr_ttf_measureEx(cursorDisplay.c_str(), fontResource);
Ethan Yonkera5db7122016-03-14 15:47:09 -0500285 }
Sultan Qasim Khan14138d92016-04-04 04:11:25 -0400286 cursorX = mRenderX + cursorTextWidth + scrollingX;
Ethan Yonkera5db7122016-03-14 15:47:09 -0500287 if (cursorX >= mRenderX + mRenderW) {
Sultan Qasim Khan14138d92016-04-04 04:11:25 -0400288 scrollingX = mRenderW - cursorTextWidth;
Ethan Yonkera5db7122016-03-14 15:47:09 -0500289 cursorX = mRenderX + mRenderW - CursorWidth;
290 } else if (cursorX < mRenderX) {
Sultan Qasim Khan14138d92016-04-04 04:11:25 -0400291 scrollingX = cursorTextWidth * -1;
Ethan Yonkera5db7122016-03-14 15:47:09 -0500292 cursorX = mRenderX;
293 }
Dees_Troy51a0e822012-09-05 15:24:24 -0400294}
295
296int GUIInput::Render(void)
297{
298 if (!isConditionTrue())
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200299 {
300 mRendered = false;
301 return 0;
302 }
Dees_Troy51a0e822012-09-05 15:24:24 -0400303
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200304 // First step, fill background
Dees_Troy51a0e822012-09-05 15:24:24 -0400305 gr_color(mBackgroundColor.red, mBackgroundColor.green, mBackgroundColor.blue, 255);
306 gr_fill(mRenderX, mRenderY, mRenderW, mRenderH);
307
308 // Next, render the background resource (if it exists)
309 if (mBackground && mBackground->GetResource())
310 {
311 mBackgroundX = mRenderX + ((mRenderW - mBackgroundW) / 2);
312 mBackgroundY = mRenderY + ((mRenderH - mBackgroundH) / 2);
313 gr_blit(mBackground->GetResource(), 0, 0, mBackgroundW, mBackgroundH, mBackgroundX, mBackgroundY);
314 }
315
316 int ret = 0;
317
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200318 // Render the text
Ethan Yonkera5db7122016-03-14 15:47:09 -0500319 if (mInputText) {
320 mInputText->SetRenderPos(mRenderX + scrollingX, mFontY);
321 mInputText->SetText(displayValue);
322 gr_clip(mRenderX, mRenderY, mRenderW, mRenderH);
323 ret = mInputText->Render();
324 gr_noclip();
325 }
326 if (ret < 0)
327 return ret;
Dees_Troy51a0e822012-09-05 15:24:24 -0400328
329 if (HasInputFocus && DrawCursor) {
330 // Render the cursor
Dees_Troy51a0e822012-09-05 15:24:24 -0400331 gr_color(mCursorColor.red, mCursorColor.green, mCursorColor.blue, 255);
332 gr_fill(cursorX, mFontY, CursorWidth, mFontHeight);
333 }
334
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200335 mRendered = true;
336 return ret;
Dees_Troy51a0e822012-09-05 15:24:24 -0400337}
338
339int GUIInput::Update(void)
340{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200341 if (!isConditionTrue()) return (mRendered ? 2 : 0);
342 if (!mRendered) return 2;
Dees_Troy51a0e822012-09-05 15:24:24 -0400343
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200344 int ret = 0;
Dees_Troy51a0e822012-09-05 15:24:24 -0400345
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200346 if (mInputText) ret = mInputText->Update();
347 if (ret < 0) return ret;
Dees_Troy51a0e822012-09-05 15:24:24 -0400348
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200349 return ret;
Dees_Troy51a0e822012-09-05 15:24:24 -0400350}
351
352int GUIInput::GetSelection(int x, int y)
353{
354 if (x < mRenderX || x - mRenderX > mRenderW || y < mRenderY || y - mRenderY > mRenderH) return -1;
355 return (x - mRenderX);
356}
357
358int GUIInput::NotifyTouch(TOUCH_STATE state, int x, int y)
359{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200360 static int startSelection = -1;
Dees_Troy51a0e822012-09-05 15:24:24 -0400361
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200362 if (!isConditionTrue())
363 return -1;
Dees_Troy51a0e822012-09-05 15:24:24 -0400364
365 if (!HasInputFocus) {
366 if (state != TOUCH_RELEASE)
367 return 0; // Only change focus if touch releases within the input box
368 if (GetSelection(x, y) >= 0) {
369 // When changing focus, we don't scroll or change the cursor location
370 PageManager::SetKeyBoardFocus(0);
that8834a0f2016-01-05 23:29:30 +0100371 PageManager::NotifyCharInput(0);
Dees_Troy51a0e822012-09-05 15:24:24 -0400372 SetInputFocus(1);
373 DrawCursor = true;
374 mRendered = false;
375 }
376 } else {
377 switch (state) {
378 case TOUCH_HOLD:
379 case TOUCH_REPEAT:
380 break;
381 case TOUCH_START:
382 startSelection = GetSelection(x,y);
383 lastX = x;
384 DrawCursor = false;
385 mRendered = false;
386 break;
387
388 case TOUCH_DRAG:
389 // Check if we dragged out of the selection window
390 if (GetSelection(x, y) == -1) {
391 lastX = 0;
392 break;
393 }
394
395 DrawCursor = false;
396
397 // Provide some debounce on initial touches
398 if (startSelection != -1 && abs(x - lastX) < 6) {
399 break;
400 }
401
402 startSelection = -1;
403 if (lastX != x)
404 HandleTextLocation(x);
405 break;
406
407 case TOUCH_RELEASE:
408 // We've moved the cursor location
Dees_Troy51a0e822012-09-05 15:24:24 -0400409 mRendered = false;
410 DrawCursor = true;
Ethan Yonkera5db7122016-03-14 15:47:09 -0500411 HandleCursorByTouch(x);
Dees_Troy51a0e822012-09-05 15:24:24 -0400412 break;
413 }
414 }
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200415 return 0;
Dees_Troy51a0e822012-09-05 15:24:24 -0400416}
417
Vojtech Bocek07220562014-02-08 02:05:33 +0100418int GUIInput::NotifyVarChange(const std::string& varName, const std::string& value)
Dees_Troy51a0e822012-09-05 15:24:24 -0400419{
Vojtech Bocek07220562014-02-08 02:05:33 +0100420 GUIObject::NotifyVarChange(varName, value);
421
Ethan Yonkera5db7122016-03-14 15:47:09 -0500422 if (varName == mVariable) {
423 if (!isLocalChange) {
Sultan Qasim Khan14138d92016-04-04 04:11:25 -0400424 UpdateDisplayText();
Ethan Yonkera5db7122016-03-14 15:47:09 -0500425 HandleTextLocation(TW_INPUT_NO_UPDATE);
426 } else
427 isLocalChange = false;
Dees_Troy51a0e822012-09-05 15:24:24 -0400428 return 0;
429 }
Ethan Yonkera5db7122016-03-14 15:47:09 -0500430 if (varName.empty()) {
Sultan Qasim Khan14138d92016-04-04 04:11:25 -0400431 UpdateDisplayText();
Ethan Yonkera5db7122016-03-14 15:47:09 -0500432 HandleTextLocation(TW_INPUT_NO_UPDATE);
433 HandleCursorByText();
434 }
Dees_Troy51a0e822012-09-05 15:24:24 -0400435 return 0;
436}
437
that8834a0f2016-01-05 23:29:30 +0100438int GUIInput::NotifyKey(int key, bool down)
439{
440 if (!HasInputFocus || !down)
441 return 1;
442
that8834a0f2016-01-05 23:29:30 +0100443 switch (key)
444 {
445 case KEY_LEFT:
Ethan Yonkera5db7122016-03-14 15:47:09 -0500446 if (mCursorLocation == 0)
that8834a0f2016-01-05 23:29:30 +0100447 return 0; // we're already at the beginning
448 if (mCursorLocation == -1) {
Ethan Yonkera5db7122016-03-14 15:47:09 -0500449 if (displayValue.size() == 0) {
450 cursorX = mRenderX;
that8834a0f2016-01-05 23:29:30 +0100451 return 0;
Ethan Yonkera5db7122016-03-14 15:47:09 -0500452 }
453 mCursorLocation = displayValue.size() - 1;
that8834a0f2016-01-05 23:29:30 +0100454 } else {
455 mCursorLocation--;
that8834a0f2016-01-05 23:29:30 +0100456 }
457 mRendered = false;
Ethan Yonkera5db7122016-03-14 15:47:09 -0500458 HandleCursorByText();
that8834a0f2016-01-05 23:29:30 +0100459 return 0;
460
461 case KEY_RIGHT:
462 if (mCursorLocation == -1)
463 return 0; // we're already at the end
464 mCursorLocation++;
Ethan Yonkera5db7122016-03-14 15:47:09 -0500465 if ((int)displayValue.size() <= mCursorLocation)
that8834a0f2016-01-05 23:29:30 +0100466 mCursorLocation = -1;
Ethan Yonkera5db7122016-03-14 15:47:09 -0500467 HandleCursorByText();
that8834a0f2016-01-05 23:29:30 +0100468 mRendered = false;
469 return 0;
470
471 case KEY_HOME:
472 case KEY_UP:
Ethan Yonkera5db7122016-03-14 15:47:09 -0500473 if (displayValue.size() == 0)
that8834a0f2016-01-05 23:29:30 +0100474 return 0;
475 mCursorLocation = 0;
that8834a0f2016-01-05 23:29:30 +0100476 mRendered = false;
Ethan Yonkera5db7122016-03-14 15:47:09 -0500477 cursorX = mRenderX;
that8834a0f2016-01-05 23:29:30 +0100478 return 0;
479
480 case KEY_END:
481 case KEY_DOWN:
482 mCursorLocation = -1;
483 mRendered = false;
Ethan Yonkera5db7122016-03-14 15:47:09 -0500484 HandleCursorByText();
that8834a0f2016-01-05 23:29:30 +0100485 return 0;
486 }
487
488 return 1;
489}
490
491int GUIInput::NotifyCharInput(int key)
Dees_Troy51a0e822012-09-05 15:24:24 -0400492{
Dees_Troy51a0e822012-09-05 15:24:24 -0400493 if (HasInputFocus) {
494 if (key == KEYBOARD_BACKSPACE) {
495 //Backspace
Sultan Qasim Khan14138d92016-04-04 04:11:25 -0400496 if (mValue.size() > 0 && mCursorLocation != 0) {
Dees_Troy51a0e822012-09-05 15:24:24 -0400497 if (mCursorLocation == -1) {
Sultan Qasim Khan14138d92016-04-04 04:11:25 -0400498 mValue.resize(mValue.size() - 1);
Dees_Troy51a0e822012-09-05 15:24:24 -0400499 } else {
Sultan Qasim Khan14138d92016-04-04 04:11:25 -0400500 mValue.erase(mCursorLocation - 1, 1);
Ethan Yonkera5db7122016-03-14 15:47:09 -0500501 mCursorLocation--;
Dees_Troy51a0e822012-09-05 15:24:24 -0400502 }
503 isLocalChange = true;
Sultan Qasim Khan14138d92016-04-04 04:11:25 -0400504 DataManager::SetValue(mVariable, mValue);
505 UpdateDisplayText();
Ethan Yonkera5db7122016-03-14 15:47:09 -0500506 HandleTextLocation(TW_INPUT_NO_UPDATE);
507 HandleCursorByText();
Dees_Troy51a0e822012-09-05 15:24:24 -0400508 }
509 } else if (key == KEYBOARD_SWIPE_LEFT) {
510 // Delete all
511 isLocalChange = true;
512 if (mCursorLocation == -1) {
513 DataManager::SetValue (mVariable, "");
Sultan Qasim Khan14138d92016-04-04 04:11:25 -0400514 mValue = "";
Ethan Yonkera5db7122016-03-14 15:47:09 -0500515 textWidth = 0;
Dees_Troy51a0e822012-09-05 15:24:24 -0400516 mCursorLocation = -1;
517 } else {
Sultan Qasim Khan14138d92016-04-04 04:11:25 -0400518 mValue.erase(0, mCursorLocation);
519 DataManager::SetValue(mVariable, mValue);
Dees_Troy51a0e822012-09-05 15:24:24 -0400520 mCursorLocation = 0;
521 }
Sultan Qasim Khan14138d92016-04-04 04:11:25 -0400522 UpdateDisplayText();
Ethan Yonkera5db7122016-03-14 15:47:09 -0500523 cursorX = mRenderX;
Dees_Troy51a0e822012-09-05 15:24:24 -0400524 scrollingX = 0;
Dees_Troy51a0e822012-09-05 15:24:24 -0400525 mRendered = false;
526 return 0;
that8834a0f2016-01-05 23:29:30 +0100527 } else if (key >= 32) {
Dees_Troy51a0e822012-09-05 15:24:24 -0400528 // Regular key
529 if (HasAllowed && AllowedList.find((char)key) == string::npos) {
530 return 0;
531 }
532 if (HasDisabled && DisabledList.find((char)key) != string::npos) {
533 return 0;
534 }
Sultan Qasim Khan14138d92016-04-04 04:11:25 -0400535 if (MaxLen != 0 && mValue.size() >= MaxLen) {
Dees_Troy51a0e822012-09-05 15:24:24 -0400536 return 0;
537 }
538 if (mCursorLocation == -1) {
Sultan Qasim Khan14138d92016-04-04 04:11:25 -0400539 mValue += key;
Dees_Troy51a0e822012-09-05 15:24:24 -0400540 } else {
Sultan Qasim Khan14138d92016-04-04 04:11:25 -0400541 mValue.insert(mCursorLocation, 1, key);
Dees_Troy51a0e822012-09-05 15:24:24 -0400542 mCursorLocation++;
543 }
544 isLocalChange = true;
Sultan Qasim Khan14138d92016-04-04 04:11:25 -0400545 DataManager::SetValue(mVariable, mValue);
546 UpdateDisplayText();
Ethan Yonkera5db7122016-03-14 15:47:09 -0500547 HandleTextLocation(TW_INPUT_NO_UPDATE);
548 HandleCursorByText();
Dees_Troy51a0e822012-09-05 15:24:24 -0400549 } else if (key == KEYBOARD_ACTION) {
550 // Action
Dees_Troy51a0e822012-09-05 15:24:24 -0400551 if (mAction) {
Sultan Qasim Khan14138d92016-04-04 04:11:25 -0400552 unsigned inputLen = mValue.length();
Dees_Troy51a0e822012-09-05 15:24:24 -0400553 if (inputLen < MinLen)
554 return 0;
555 else if (MaxLen != 0 && inputLen > MaxLen)
556 return 0;
557 else
558 return (mAction ? mAction->NotifyTouch(TOUCH_RELEASE, mRenderX, mRenderY) : 1);
559 }
560 }
561 return 0;
562 } else {
563 if (key == 0) {
564 // Somewhat ugly hack-ish way to tell the box to redraw after losing focus to remove the cursor
565 mRendered = false;
566 return 1;
567 }
568 }
569 return 1;
570}