CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutSign UpSign In
hrydgard

CoCalc provides the best real-time collaborative environment for Jupyter Notebooks, LaTeX documents, and SageMath, scalable from individual users to large groups and classes!

GitHub Repository: hrydgard/ppsspp
Path: blob/master/Core/Dialog/PSPOskDialog.cpp
Views: 1401
1
// Copyright (c) 2012- PPSSPP Project.
2
3
// This program is free software: you can redistribute it and/or modify
4
// it under the terms of the GNU General Public License as published by
5
// the Free Software Foundation, version 2.0 or later versions.
6
7
// This program is distributed in the hope that it will be useful,
8
// but WITHOUT ANY WARRANTY; without even the implied warranty of
9
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10
// GNU General Public License 2.0 for more details.
11
12
// A copy of the GPL 2.0 should have been included with the program.
13
// If not, see http://www.gnu.org/licenses/
14
15
// Official git repository and contact information can be found at
16
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
17
18
#include "ppsspp_config.h"
19
#include <algorithm>
20
21
#include "Common/Data/Text/I18n.h"
22
#include "Common/Math/math_util.h"
23
#include "Common/Data/Encoding/Utf8.h"
24
#include "Common/Serialize/SerializeFuncs.h"
25
#include "Common/System/Request.h"
26
#include "Common/Serialize/Serializer.h"
27
28
#include "Core/Dialog/PSPOskDialog.h"
29
#include "Core/Util/PPGeDraw.h"
30
#include "Core/HLE/sceCtrl.h"
31
#include "Core/HLE/sceUtility.h"
32
#include "Core/HW/Display.h"
33
#include "Core/Config.h"
34
#include "Core/Reporting.h"
35
#include "GPU/GPUState.h"
36
37
#ifndef _WIN32
38
#include <ctype.h>
39
#include <math.h>
40
#endif
41
42
// These are rough, it seems to take a long time to init, and probably depends on threads.
43
// TODO: This takes like 700ms on a PSP but that's annoyingly long.
44
const static int OSK_INIT_DELAY_US = 300000;
45
const static int OSK_SHUTDOWN_DELAY_US = 40000;
46
47
static std::map<std::string, std::pair<std::string, int>, std::less<>> languageMapping;
48
49
const uint8_t numKeyCols[OSK_KEYBOARD_COUNT] = {12, 12, 13, 13, 12, 12, 12, 12, 12};
50
const uint8_t numKeyRows[OSK_KEYBOARD_COUNT] = {4, 4, 6, 6, 5, 4, 4, 4, 4};
51
52
// Japanese (Kana) diacritics
53
static const wchar_t diacritics[2][103] =
54
{
55
{L"かがきぎくぐけげこごさざしじすずせぜそぞただちぢつづてでとどはばぱばひびぴびふぶぷぶへべぺべほぼぽぼウヴカガキギクグケゲコゴサザシジスズセゼソゾタダチヂツヅテデトドハバパバヒビピビフブプブヘベペベホボポボ"},
56
{L"はぱばぱひぴびぴふぷぶぷへぺべぺほぽぼぽハパバパヒピビピフプブプヘペベペホポボポ"}
57
};
58
59
// Korean (Hangul) consonant
60
static const wchar_t kor_cons[] = L"ㄱㄲㄴㄷㄸㄹㅁㅂㅃㅅㅆㅇㅈㅉㅊㅋㅌㅍㅎ";
61
62
// Korean (Hangul) vowels, Some vowels are not used, they will be spaces
63
static const wchar_t kor_vowel[] = L"ㅏㅐㅑㅒㅓㅔㅕㅖㅗ ㅛㅜ ㅠㅡ ㅣ";
64
65
// Korean (Hangul) vowel Combination key
66
const uint8_t kor_vowelCom[] = {0,8,9,1,8,10,20,8,11,4,13,14,5,13,15,20,13,16,20,18,19};
67
68
// Korean (Hangul) last consonant(diacritics)
69
static const wchar_t kor_lcons[] = L"ㄱㄲㄳㄴㄵㄶㄷㄹㄺㄻㄼㄽㄾㄿㅀㅁㅂㅄㅅㅆㅇㅈㅊㅋㅌㅍㅎ";
70
71
// Korean (Hangul) last consonant Combination key
72
const uint8_t kor_lconsCom[] = {18,0,2,21,3,4,26,3,5,0,7,8,15,7,9,16,7,10,18,7,11,24,7,12,25,7,13,26,7,14,18,16,17};
73
74
// Korean (Hangul) last consonant Separation key
75
const uint8_t kor_lconsSpr[] = {2,1,9,4,4,12,5,4,18,8,8,0,9,8,6,10,8,7,11,8,9,12,8,16,13,8,17,14,8,18,17,17,9};
76
77
static const char16_t oskKeys[OSK_KEYBOARD_COUNT][6][14] =
78
{
79
{
80
// Latin Lowercase
81
{u"1234567890-+"},
82
{u"qwertyuiop[]"},
83
{u"asdfghjkl;@~"},
84
{u"zxcvbnm,./?\\"},
85
},
86
{
87
// Latin Uppercase
88
{u"!@#$%^&*()_+"},
89
{u"QWERTYUIOP{}"},
90
{u"ASDFGHJKL:\"`"},
91
{u"ZXCVBNM<>/?|"},
92
},
93
{
94
// Hiragana
95
{u"あかさたなはまやらわぁゃっ"},
96
{u"いきしちにひみ り ぃ  "},
97
{u"うくすつぬふむゆるをぅゅ゛"},
98
{u"えけせてねへめ れ ぇ ゜"},
99
{u"おこそとのほもよろんぉょー"},
100
{u"・。、「」『』〜 "},
101
},
102
{
103
// Katakana
104
{u"アカサタナハマヤラワァャッ"},
105
{u"イキシチニヒミ リ ィ  "},
106
{u"ウクスツヌフムユルヲゥュ゛"},
107
{u"エケセテネヘメ レ ェ ゜"},
108
{u"オコソトノホモヨロンォョー"},
109
{u"・。、「」『』〜 "},
110
},
111
{
112
// Korean(Hangul)
113
{u"1234567890-+"},
114
{u"ㅃㅉㄸㄲㅆ!@#$%^&"},
115
{u"ㅂㅈㄷㄱㅅㅛㅕㅑㅐㅔ[]"},
116
{u"ㅁㄴㅇㄹㅎㅗㅓㅏㅣ;@~"},
117
{u"ㅋㅌㅊㅍㅠㅜㅡ<>/?|"},
118
},
119
{
120
// Russian Lowercase
121
{u"1234567890-+"},
122
{u"йцукенгшщзхъ"},
123
{u"фывапролджэё"},
124
{u"ячсмитьбю/?|"},
125
},
126
{
127
// Russian Uppercase
128
{u"!@#$%^&*()_+"},
129
{u"ЙЦУКЕНГШЩЗХЪ"},
130
{u"ФЫВАПРОЛДЖЭЁ"},
131
{u"ЯЧСМИТЬБЮ/?|"},
132
},
133
{
134
// Latin Full-width Lowercase
135
{ u"1234567890-+" },
136
{ u"qwertyuiop[]" },
137
{ u"asdfghjkl;@~" },
138
{ u"zxcvbnm,./?¥¥" },
139
},
140
{
141
// Latin Full-width Uppercase
142
{ u"!@#$%^&*()_+" },
143
{ u"QWERTYUIOP{}" },
144
{ u"ASDFGHJKL:¥”‘" },
145
{ u"ZXCVBNM<>/?|" },
146
},
147
};
148
149
// This isn't a complete representation of these flags, it just helps ensure we show the right keyboards.
150
static const int allowedInputFlagsMap[OSK_KEYBOARD_COUNT] = {
151
PSP_UTILITY_OSK_INPUTTYPE_LATIN_LOWERCASE | PSP_UTILITY_OSK_INPUTTYPE_LATIN_UPPERCASE | PSP_UTILITY_OSK_INPUTTYPE_LATIN_SYMBOL | PSP_UTILITY_OSK_INPUTTYPE_LATIN_DIGIT,
152
PSP_UTILITY_OSK_INPUTTYPE_LATIN_LOWERCASE | PSP_UTILITY_OSK_INPUTTYPE_LATIN_UPPERCASE | PSP_UTILITY_OSK_INPUTTYPE_LATIN_SYMBOL,
153
PSP_UTILITY_OSK_INPUTTYPE_JAPANESE_HIRAGANA,
154
PSP_UTILITY_OSK_INPUTTYPE_JAPANESE_KATAKANA | PSP_UTILITY_OSK_INPUTTYPE_JAPANESE_HALF_KATAKANA,
155
PSP_UTILITY_OSK_INPUTTYPE_KOREAN,
156
PSP_UTILITY_OSK_INPUTTYPE_RUSSIAN_LOWERCASE | PSP_UTILITY_OSK_INPUTTYPE_RUSSIAN_UPPERCASE,
157
PSP_UTILITY_OSK_INPUTTYPE_RUSSIAN_LOWERCASE | PSP_UTILITY_OSK_INPUTTYPE_RUSSIAN_UPPERCASE,
158
PSP_UTILITY_OSK_INPUTTYPE_JAPANESE_LOWERCASE | PSP_UTILITY_OSK_INPUTTYPE_JAPANESE_UPPERCASE | PSP_UTILITY_OSK_INPUTTYPE_JAPANESE_SYMBOL | PSP_UTILITY_OSK_INPUTTYPE_JAPANESE_DIGIT,
159
PSP_UTILITY_OSK_INPUTTYPE_JAPANESE_LOWERCASE | PSP_UTILITY_OSK_INPUTTYPE_JAPANESE_UPPERCASE | PSP_UTILITY_OSK_INPUTTYPE_JAPANESE_SYMBOL,
160
};
161
static const int defaultInputFlagsMap[OSK_KEYBOARD_COUNT] = {
162
PSP_UTILITY_OSK_INPUTTYPE_LATIN_LOWERCASE | PSP_UTILITY_OSK_INPUTTYPE_LATIN_SYMBOL | PSP_UTILITY_OSK_INPUTTYPE_LATIN_DIGIT,
163
PSP_UTILITY_OSK_INPUTTYPE_LATIN_UPPERCASE | PSP_UTILITY_OSK_INPUTTYPE_LATIN_SYMBOL,
164
PSP_UTILITY_OSK_INPUTTYPE_JAPANESE_HIRAGANA,
165
PSP_UTILITY_OSK_INPUTTYPE_JAPANESE_KATAKANA | PSP_UTILITY_OSK_INPUTTYPE_JAPANESE_HALF_KATAKANA,
166
PSP_UTILITY_OSK_INPUTTYPE_KOREAN,
167
PSP_UTILITY_OSK_INPUTTYPE_RUSSIAN_LOWERCASE,
168
PSP_UTILITY_OSK_INPUTTYPE_RUSSIAN_UPPERCASE,
169
PSP_UTILITY_OSK_INPUTTYPE_JAPANESE_LOWERCASE | PSP_UTILITY_OSK_INPUTTYPE_JAPANESE_SYMBOL | PSP_UTILITY_OSK_INPUTTYPE_JAPANESE_DIGIT,
170
PSP_UTILITY_OSK_INPUTTYPE_JAPANESE_UPPERCASE | PSP_UTILITY_OSK_INPUTTYPE_JAPANESE_SYMBOL,
171
};
172
173
PSPOskDialog::PSPOskDialog(UtilityDialogType type) : PSPDialog(type) {
174
// This can break all kinds of stuff, changing the decimal point in sprintf for example.
175
// Not sure what the intended effect is so commented out for now.
176
// setlocale(LC_ALL, "");
177
}
178
179
PSPOskDialog::~PSPOskDialog() {
180
}
181
182
void PSPOskDialog::ConvertUCS2ToUTF8(std::string& _string, const PSPPointer<u16_le>& em_address)
183
{
184
if (!em_address.IsValid())
185
{
186
_string.clear();
187
return;
188
}
189
190
const size_t maxLength = 2047;
191
char stringBuffer[maxLength + 1];
192
char *string = stringBuffer;
193
194
u16_le *input = &em_address[0];
195
int c;
196
while ((c = *input++) != 0 && string < stringBuffer + maxLength)
197
{
198
if (c < 0x80)
199
*string++ = c;
200
else if (c < 0x800) {
201
*string++ = 0xC0 | (c >> 6);
202
*string++ = 0x80 | (c & 0x3F);
203
} else {
204
*string++ = 0xE0 | (c >> 12);
205
*string++ = 0x80 | ((c >> 6) & 0x3F);
206
*string++ = 0x80 | (c & 0x3F);
207
}
208
}
209
*string++ = '\0';
210
_string = stringBuffer;
211
}
212
213
void GetWideStringFromPSPPointer(std::u16string& _string, const PSPPointer<u16_le>& em_address)
214
{
215
if (!em_address.IsValid())
216
{
217
_string.clear();
218
return;
219
}
220
221
const size_t maxLength = 2047;
222
char16_t stringBuffer[maxLength + 1];
223
char16_t *string = stringBuffer;
224
225
u16_le *input = &em_address[0];
226
int c;
227
while ((c = *input++) != 0 && string < stringBuffer + maxLength)
228
*string++ = c;
229
*string++ = '\0';
230
_string = stringBuffer;
231
}
232
233
void PSPOskDialog::ConvertUCS2ToUTF8(std::string& _string, const char16_t *input)
234
{
235
char stringBuffer[2048];
236
char *string = stringBuffer;
237
238
int c;
239
while ((c = *input++) != 0)
240
{
241
if (c < 0x80)
242
*string++ = c;
243
else if (c < 0x800) {
244
*string++ = 0xC0 | (c >> 6);
245
*string++ = 0x80 | (c & 0x3F);
246
} else {
247
*string++ = 0xE0 | (c >> 12);
248
*string++ = 0x80 | ((c >> 6) & 0x3F);
249
*string++ = 0x80 | (c & 0x3F);
250
}
251
}
252
*string++ = '\0';
253
_string = stringBuffer;
254
}
255
256
static void FindValidKeyboard(s32 inputType, int direction, OskKeyboardLanguage &lang, OskKeyboardDisplay &disp) {
257
OskKeyboardLanguage origLang = lang;
258
OskKeyboardDisplay origDisp = disp;
259
260
if (inputType == 0) {
261
return;
262
}
263
// We use direction = 0 for default, but we actually move "forward".
264
const int *matchMap = allowedInputFlagsMap;
265
if (direction == 0) {
266
direction = 1;
267
matchMap = defaultInputFlagsMap;
268
}
269
270
// TODO: Limit by allowed keyboards properly... this is just an approximation.
271
int tries = OSK_LANGUAGE_COUNT * 2;
272
while (!(inputType & matchMap[disp]) && tries > 0) {
273
if ((--tries % 2) == 0) {
274
lang = (OskKeyboardLanguage)((OSK_LANGUAGE_COUNT + lang + direction) % OSK_LANGUAGE_COUNT);
275
disp = OskKeyboardCases[lang][LOWERCASE];
276
} else {
277
disp = OskKeyboardCases[lang][UPPERCASE];
278
}
279
}
280
281
if (tries == 0) {
282
// In case of error, let's just fall back to allowing all.
283
lang = origLang;
284
disp = origDisp;
285
}
286
}
287
288
static bool IsKeyboardShiftValid(s32 inputType, OskKeyboardLanguage lang, OskKeyboardDisplay disp) {
289
// Swap disp and check if it's valid.
290
if (disp == OskKeyboardCases[lang][UPPERCASE])
291
disp = OskKeyboardCases[lang][LOWERCASE];
292
else
293
disp = OskKeyboardCases[lang][UPPERCASE];
294
295
return inputType == 0 || (inputType & allowedInputFlagsMap[disp]) != 0;
296
}
297
298
int PSPOskDialog::Init(u32 oskPtr) {
299
// Ignore if already running
300
if (GetStatus() != SCE_UTILITY_STATUS_NONE) {
301
ERROR_LOG_REPORT(Log::sceUtility, "sceUtilityOskInitStart: invalid status");
302
return SCE_ERROR_UTILITY_INVALID_STATUS;
303
}
304
// Seems like this should crash?
305
if (!Memory::IsValidAddress(oskPtr)) {
306
ERROR_LOG_REPORT(Log::sceUtility, "sceUtilityOskInitStart: invalid params (%08x)", oskPtr);
307
return -1;
308
}
309
310
oskParams = oskPtr;
311
if (oskParams->base.size != sizeof(SceUtilityOskParams))
312
{
313
ERROR_LOG_REPORT(Log::sceUtility, "sceUtilityOskInitStart: invalid size %d", oskParams->base.size);
314
return SCE_ERROR_UTILITY_INVALID_PARAM_SIZE;
315
}
316
// Also seems to crash.
317
if (!oskParams->fields.IsValid())
318
{
319
ERROR_LOG_REPORT(Log::sceUtility, "sceUtilityOskInitStart: invalid field data (%08x)", oskParams->fields.ptr);
320
return -1;
321
}
322
323
if (oskParams->unk_60 != 0)
324
WARN_LOG_REPORT(Log::sceUtility, "sceUtilityOskInitStart: unknown param is non-zero (%08x)", oskParams->unk_60);
325
if (oskParams->fieldCount != 1)
326
WARN_LOG_REPORT(Log::sceUtility, "sceUtilityOskInitStart: unsupported field count %d", oskParams->fieldCount);
327
328
ChangeStatusInit(OSK_INIT_DELAY_US);
329
selectedChar = 0;
330
currentKeyboardLanguage = OSK_LANGUAGE_ENGLISH;
331
currentKeyboard = OSK_KEYBOARD_LATIN_LOWERCASE;
332
FindValidKeyboard(oskParams->fields[0].inputtype, 0, currentKeyboardLanguage, currentKeyboard);
333
334
ConvertUCS2ToUTF8(oskDesc, oskParams->fields[0].desc);
335
ConvertUCS2ToUTF8(oskIntext, oskParams->fields[0].intext);
336
ConvertUCS2ToUTF8(oskOuttext, oskParams->fields[0].outtext);
337
338
i_level = 0;
339
340
inputChars.clear();
341
342
if (oskParams->fields[0].intext.IsValid()) {
343
auto src = oskParams->fields[0].intext;
344
int c;
345
while ((c = *src++) != 0)
346
inputChars += c;
347
}
348
349
languageMapping = g_Config.GetLangValuesMapping();
350
351
// Eat any keys pressed before the dialog inited.
352
UpdateButtons();
353
InitCommon();
354
355
std::lock_guard<std::mutex> guard(nativeMutex_);
356
nativeStatus_ = PSPOskNativeStatus::IDLE;
357
358
StartFade(true);
359
return 0;
360
}
361
362
std::u16string PSPOskDialog::CombinationKorean(bool isInput)
363
{
364
std::u16string string;
365
366
isCombinated = true;
367
368
int selectedRow = selectedChar / numKeyCols[currentKeyboard];
369
int selectedCol = selectedChar % numKeyCols[currentKeyboard];
370
371
if (inputChars.size() == 0) {
372
wchar_t sw = oskKeys[currentKeyboard][selectedRow][selectedCol];
373
374
if (inputChars.size() < FieldMaxLength()) {
375
string += sw;
376
377
i_value[0] = GetIndex(kor_cons, sw);
378
379
if(i_value[0] != -1 && isInput == true)
380
i_level = 1;
381
} else {
382
isCombinated = false;
383
}
384
} else {
385
for(u32 i = 0; i < inputChars.size(); i++) {
386
if(i + 1 == inputChars.size()) {
387
wchar_t sw = oskKeys[currentKeyboard][selectedRow][selectedCol];
388
389
if(i_level == 0) {
390
string += inputChars[i];
391
if (inputChars.size() < FieldMaxLength()) {
392
string += sw;
393
394
i_value[0] = GetIndex(kor_cons, sw);
395
396
if(i_value[0] != -1 && isInput == true)
397
i_level = 1;
398
} else {
399
isCombinated = false;
400
}
401
} else if(i_level == 1) {
402
i_value[1] = GetIndex(kor_vowel, sw);
403
404
if(i_value[1] == -1) {
405
string += inputChars[i];
406
if (inputChars.size() < FieldMaxLength()) {
407
string += sw;
408
409
if(isInput == true) {
410
i_value[0] = GetIndex(kor_cons, sw);
411
412
if(i_value[0] != -1)
413
i_level = 1;
414
else
415
i_level = 0;
416
}
417
} else {
418
isCombinated = false;
419
}
420
} else {
421
u16 code = 0xAC00 + i_value[0] * 0x24C + i_value[1] * 0x1C;
422
string += code;
423
424
if(isInput == true) {
425
i_level = 2;
426
}
427
}
428
} else if(i_level == 2) {
429
int tmp = GetIndex(kor_vowel, sw);
430
if(tmp != -1) {
431
int tmp2 = -1;
432
for(size_t j = 0; j < sizeof(kor_vowelCom) / 4; j+=3) {
433
if(kor_vowelCom[j] == tmp && kor_vowelCom[j + 1] == i_value[1]) {
434
tmp2 = kor_vowelCom[j + 2];
435
break;
436
}
437
}
438
if(tmp2 != -1) {
439
if(isInput == true) {
440
i_value[1] = tmp2;
441
}
442
443
u16 code = 0xAC00 + i_value[0] * 0x24C + tmp2 * 0x1C;
444
445
string += code;
446
} else {
447
string += inputChars[i];
448
if (inputChars.size() < FieldMaxLength()) {
449
string += sw;
450
451
if(isInput == true) {
452
i_level = 0;
453
}
454
} else {
455
isCombinated = false;
456
}
457
}
458
} else {
459
int tmp2 = GetIndex(kor_lcons, sw);
460
461
if (tmp2 == -1) {
462
string += inputChars[i];
463
if (inputChars.size() < FieldMaxLength()) {
464
string += sw;
465
466
if (isInput == true) {
467
i_value[0] = GetIndex(kor_cons, sw);
468
469
if(i_value[0] != -1)
470
i_level = 1;
471
else
472
i_level = 0;
473
}
474
} else {
475
isCombinated = false;
476
}
477
} else {
478
u16 code = 0xAC00 + i_value[0] * 0x24C + i_value[1] * 0x1C + tmp2 + 1;
479
480
string += code;
481
482
if (isInput == true) {
483
i_level = 3;
484
i_value[2] = tmp2;
485
}
486
}
487
}
488
} else if(i_level == 3) {
489
int tmp = GetIndex(kor_lcons, sw);
490
if(tmp != -1) {
491
int tmp2 = -1;
492
for(size_t j = 0; j < sizeof(kor_lconsCom) / 4; j+=3) {
493
if(kor_lconsCom[j] == tmp && kor_lconsCom[j + 1] == i_value[2]) {
494
tmp2 = kor_lconsCom[j + 2];
495
break;
496
}
497
}
498
if(tmp2 != -1) {
499
if(isInput == true) {
500
i_value[2] = tmp2;
501
}
502
503
u16 code = 0xAC00 + i_value[0] * 0x24C + tmp2 * 0x1C + i_value[2] + 1;
504
505
string += code;
506
} else {
507
string += inputChars[i];
508
if (inputChars.size() < FieldMaxLength()) {
509
string += sw;
510
511
if(isInput == true) {
512
i_value[0] = GetIndex(kor_cons, sw);
513
514
if(i_value[0] != -1)
515
i_level = 1;
516
else
517
i_level = 0;
518
}
519
} else {
520
isCombinated = false;
521
}
522
}
523
} else {
524
int tmp3 = GetIndex(kor_vowel, sw);
525
if (tmp3 == -1) {
526
string += inputChars[i];
527
if (inputChars.size() < FieldMaxLength()) {
528
string += sw;
529
530
if(isInput == true) {
531
i_value[0] = GetIndex(kor_cons, sw);
532
533
if(i_value[0] != -1)
534
i_level = 1;
535
else
536
i_level = 0;
537
}
538
} else {
539
isCombinated = false;
540
}
541
} else {
542
if (inputChars.size() < FieldMaxLength()) {
543
int tmp2 = -1;
544
for(size_t j = 0; j < sizeof(kor_lconsSpr) / 4; j+=3) {
545
if(kor_lconsSpr[j] == i_value[2]) {
546
tmp2 = (int)j;
547
break;
548
}
549
}
550
if(tmp2 != -1) {
551
u16 code = 0xAC00 + i_value[0] * 0x24C + i_value[1] * 0x1C + kor_lconsSpr[tmp2 + 1];
552
string += code;
553
554
code = 0xAC00 + kor_lconsSpr[tmp2 + 2] * 0x24C + tmp3 * 0x1C;
555
string += code;
556
557
if(isInput == true) {
558
i_value[0] = kor_lconsSpr[tmp2 + 2];
559
i_value[1] = tmp3;
560
i_level = 2;
561
}
562
} else {
563
int tmp4 = GetIndex(kor_cons, kor_lcons[i_value[2]]);
564
565
if (tmp4 != -1) {
566
u16 code = 0xAC00 + i_value[0] * 0x24C + i_value[1] * 0x1C;
567
568
string += code;
569
570
code = 0xAC00 + tmp4 * 0x24C + tmp3 * 0x1C;
571
572
string += code;
573
574
if(isInput == true) {
575
i_value[0] = tmp4;
576
i_value[1] = tmp3;
577
i_level = 2;
578
}
579
} else {
580
string += inputChars[i];
581
string += sw;
582
583
if(isInput == true) {
584
i_level = 0;
585
}
586
}
587
}
588
} else {
589
string += inputChars[i];
590
isCombinated = false;
591
}
592
}
593
}
594
}
595
} else {
596
string += inputChars[i];
597
}
598
}
599
}
600
601
return string;
602
}
603
604
std::u16string PSPOskDialog::CombinationString(bool isInput)
605
{
606
std::u16string string;
607
608
isCombinated = false;
609
610
int selectedRow = selectedChar / numKeyCols[currentKeyboard];
611
int selectedCol = selectedChar % numKeyCols[currentKeyboard];
612
613
if(currentKeyboard == OSK_KEYBOARD_KOREAN)
614
{
615
string = CombinationKorean(isInput);
616
}
617
else
618
{
619
if(isInput == true)
620
{
621
i_level = 0;
622
}
623
624
if(oskKeys[currentKeyboard][selectedRow][selectedCol] == L'゛')
625
{
626
for(u32 i = 0; i < inputChars.size(); i++)
627
{
628
if(i + 1 == inputChars.size())
629
{
630
for(u32 j = 0; j < wcslen(diacritics[0]); j+=2)
631
{
632
if(inputChars[i] == diacritics[0][j])
633
{
634
string += diacritics[0][j + 1];
635
isCombinated = true;
636
break;
637
}
638
}
639
640
if(isCombinated == false)
641
{
642
string += inputChars[i];
643
}
644
}
645
else
646
{
647
string += inputChars[i];
648
}
649
}
650
}
651
else if(oskKeys[currentKeyboard][selectedRow][selectedCol] == L'゜')
652
{
653
for(u32 i = 0; i < inputChars.size(); i++)
654
{
655
if(i + 1 == inputChars.size())
656
{
657
for(u32 j = 0; j < wcslen(diacritics[1]); j+=2)
658
{
659
if(inputChars[i] == diacritics[1][j])
660
{
661
string += diacritics[1][j + 1];
662
isCombinated = true;
663
break;
664
}
665
}
666
667
if(isCombinated == false)
668
{
669
string += inputChars[i];
670
}
671
}
672
else
673
{
674
string += inputChars[i];
675
}
676
}
677
}
678
else
679
{
680
for(u32 i = 0; i < inputChars.size(); i++)
681
{
682
string += inputChars[i];
683
}
684
685
if (string.size() < FieldMaxLength())
686
{
687
string += oskKeys[currentKeyboard][selectedRow][selectedCol];
688
}
689
isCombinated = true;
690
}
691
}
692
693
return string;
694
}
695
696
void PSPOskDialog::RemoveKorean()
697
{
698
if(i_level == 1)
699
{
700
i_level = 0;
701
}
702
else if(i_level == 2)
703
{
704
int tmp = -1;
705
for(size_t i = 2; i < sizeof(kor_vowelCom) / 4; i+=3)
706
{
707
if(kor_vowelCom[i] == i_value[1])
708
{
709
tmp = kor_vowelCom[i - 1];
710
break;
711
}
712
}
713
714
if(tmp != -1)
715
{
716
i_value[1] = tmp;
717
u16 code = 0xAC00 + i_value[0] * 0x24C + i_value[1] * 0x1C;
718
inputChars += code;
719
}
720
else
721
{
722
i_level = 1;
723
inputChars += kor_cons[i_value[0]];
724
}
725
}
726
else if(i_level == 3)
727
{
728
int tmp = -1;
729
for(size_t i = 2; i < sizeof(kor_lconsCom) / 4; i+=3)
730
{
731
if(kor_lconsCom[i] == i_value[2])
732
{
733
tmp = kor_lconsCom[i - 1];
734
break;
735
}
736
}
737
738
if(tmp != -1)
739
{
740
i_value[2] = tmp;
741
u16 code = 0xAC00 + i_value[0] * 0x24C + i_value[1] * 0x1C + i_value[2] + 1;
742
inputChars += code;
743
}
744
else
745
{
746
i_level = 2;
747
u16 code = 0xAC00 + i_value[0] * 0x24C + i_value[1] * 0x1C;
748
inputChars += code;
749
}
750
}
751
}
752
753
int PSPOskDialog::GetIndex(const wchar_t* src, wchar_t ch)
754
{
755
for(int i = 0, end = (int)wcslen(src); i < end; i++)
756
{
757
if(src[i] == ch)
758
{
759
return i;
760
}
761
}
762
763
return -1;
764
}
765
766
u32 PSPOskDialog::FieldMaxLength()
767
{
768
if ((oskParams->fields[0].outtextlimit > oskParams->fields[0].outtextlength - 1) || oskParams->fields[0].outtextlimit == 0)
769
return oskParams->fields[0].outtextlength - 1;
770
return oskParams->fields[0].outtextlimit;
771
}
772
773
void PSPOskDialog::RenderKeyboard()
774
{
775
// Sanity check that a valid keyboard is selected.
776
if ((int)currentKeyboard < 0 || (int)currentKeyboard >= OSK_KEYBOARD_COUNT) {
777
return;
778
}
779
780
int selectedRow = selectedChar / numKeyCols[currentKeyboard];
781
int selectedCol = selectedChar % numKeyCols[currentKeyboard];
782
783
char16_t temp[2];
784
temp[1] = '\0';
785
786
std::string buffer;
787
788
static const u32 FIELDDRAWMAX = 16;
789
u32 limit = FieldMaxLength();
790
u32 drawLimit = std::min(FIELDDRAWMAX, limit); // Field drew length limit.
791
792
const float keyboardLeftSide = (480.0f - (24.0f * numKeyCols[currentKeyboard])) / 2.0f;
793
const float characterWidth = 12.0f;
794
float previewLeftSide = (480.0f - (12.0f * drawLimit)) / 2.0f;
795
float title = (480.0f - (0.5f * drawLimit)) / 2.0f;
796
797
PPGeStyle descStyle = FadedStyle(PPGeAlign::BOX_CENTER, 0.5f);
798
PPGeDrawText(oskDesc.c_str(), title, 20, descStyle);
799
800
PPGeStyle textStyle = FadedStyle(PPGeAlign::BOX_HCENTER, 0.5f);
801
802
PPGeStyle keyStyle = FadedStyle(PPGeAlign::BOX_HCENTER, 0.6f);
803
PPGeStyle selectedKeyStyle = FadedStyle(PPGeAlign::BOX_HCENTER, 0.6f);
804
selectedKeyStyle.color = CalcFadedColor(0xFF3060FF);
805
806
std::u16string result;
807
808
result = CombinationString(false);
809
810
u32 drawIndex = (u32)(result.size() > drawLimit ? result.size() - drawLimit : 0);
811
drawIndex = result.size() == limit + 1 ? drawIndex - 1 : drawIndex; // When the length reached limit, the last character don't fade in and out.
812
for (u32 i = 0; i < drawLimit; ++i, ++drawIndex)
813
{
814
if (drawIndex + 1 < result.size())
815
{
816
temp[0] = result[drawIndex];
817
ConvertUCS2ToUTF8(buffer, temp);
818
PPGeDrawText(buffer.c_str(), previewLeftSide + (i * characterWidth), 40.0f, textStyle);
819
}
820
else
821
{
822
if (drawIndex + 1 == result.size())
823
{
824
temp[0] = result[drawIndex];
825
826
if(isCombinated == true)
827
{
828
float animStep = (float)(__DisplayGetNumVblanks() % 40) / 20.0f;
829
// Fade in and out the next character so they know it's not part of the string yet.
830
u32 alpha = (0.5f - (cosf(animStep * M_PI) / 2.0f)) * 128 + 127;
831
PPGeStyle animStyle = textStyle;
832
animStyle.color = CalcFadedColor((alpha << 24) | 0x00FFFFFF);
833
834
ConvertUCS2ToUTF8(buffer, temp);
835
836
PPGeDrawText(buffer.c_str(), previewLeftSide + (i * characterWidth), 40.0f, animStyle);
837
838
// Also draw the underline for the same reason.
839
PPGeDrawText("_", previewLeftSide + (i * characterWidth), 40.0f, textStyle);
840
}
841
else
842
{
843
ConvertUCS2ToUTF8(buffer, temp);
844
PPGeDrawText(buffer.c_str(), previewLeftSide + (i * characterWidth), 40.0f, textStyle);
845
}
846
}
847
else
848
{
849
PPGeDrawText("_", previewLeftSide + (i * characterWidth), 40.0f, textStyle);
850
}
851
}
852
}
853
854
for (int row = 0; row < numKeyRows[currentKeyboard]; ++row)
855
{
856
for (int col = 0; col < numKeyCols[currentKeyboard]; ++col)
857
{
858
temp[0] = oskKeys[currentKeyboard][row][col];
859
860
ConvertUCS2ToUTF8(buffer, temp);
861
862
if (selectedRow == row && col == selectedCol) {
863
PPGeDrawText(buffer.c_str(), keyboardLeftSide + (25.0f * col) + characterWidth / 2.0, 70.0f + (25.0f * row), selectedKeyStyle);
864
PPGeDrawText("_", keyboardLeftSide + (25.0f * col) + characterWidth / 2.0, 70.0f + (25.0f * row), keyStyle);
865
} else {
866
PPGeDrawText(buffer.c_str(), keyboardLeftSide + (25.0f * col) + characterWidth / 2.0, 70.0f + (25.0f * row), keyStyle);
867
}
868
}
869
}
870
}
871
872
// TODO: Why does this have a 2 button press lag/delay when
873
// re-opening the dialog box? I don't get it.
874
int PSPOskDialog::NativeKeyboard() {
875
if (GetStatus() != SCE_UTILITY_STATUS_RUNNING) {
876
return SCE_ERROR_UTILITY_INVALID_STATUS;
877
}
878
879
#if defined(USING_WIN_UI) || defined(USING_QT_UI) || PPSSPP_PLATFORM(ANDROID)
880
bool beginInputBox = false;
881
if (nativeStatus_ == PSPOskNativeStatus::IDLE) {
882
std::lock_guard<std::mutex> guard(nativeMutex_);
883
if (nativeStatus_ == PSPOskNativeStatus::IDLE) {
884
nativeStatus_ = PSPOskNativeStatus::WAITING;
885
beginInputBox = true;
886
}
887
}
888
889
if (beginInputBox) {
890
std::u16string titleText;
891
GetWideStringFromPSPPointer(titleText, oskParams->fields[0].desc);
892
893
std::u16string defaultText;
894
GetWideStringFromPSPPointer(defaultText, oskParams->fields[0].intext);
895
896
if (defaultText.empty())
897
defaultText.assign(u"VALUE");
898
899
// There's already ConvertUCS2ToUTF8 in this file. Should we use that instead of the global ones?
900
System_InputBoxGetString(NON_EPHEMERAL_TOKEN, ::ConvertUCS2ToUTF8(titleText), ::ConvertUCS2ToUTF8(defaultText), false,
901
[&](const std::string &value, int) {
902
// Success callback
903
std::lock_guard<std::mutex> guard(nativeMutex_);
904
if (nativeStatus_ != PSPOskNativeStatus::WAITING) {
905
return;
906
}
907
nativeValue_ = value;
908
nativeStatus_ = PSPOskNativeStatus::SUCCESS;
909
},
910
[&]() {
911
// Failure callback
912
std::lock_guard<std::mutex> guard(nativeMutex_);
913
if (nativeStatus_ != PSPOskNativeStatus::WAITING) {
914
return;
915
}
916
nativeValue_ = "";
917
nativeStatus_ = PSPOskNativeStatus::FAILURE;
918
}
919
);
920
} else if (nativeStatus_ == PSPOskNativeStatus::SUCCESS) {
921
inputChars = ConvertUTF8ToUCS2(nativeValue_);
922
nativeValue_.clear();
923
924
u32 maxLength = FieldMaxLength();
925
if (inputChars.length() > maxLength) {
926
ERROR_LOG(Log::sceUtility, "NativeKeyboard: input text too long(%d characters/glyphs max), truncating to game-requested length.", maxLength);
927
inputChars.erase(maxLength, std::string::npos);
928
}
929
ChangeStatus(SCE_UTILITY_STATUS_FINISHED, 0);
930
nativeStatus_ = PSPOskNativeStatus::DONE;
931
} else if (nativeStatus_ == PSPOskNativeStatus::FAILURE) {
932
ChangeStatus(SCE_UTILITY_STATUS_FINISHED, 0);
933
nativeStatus_ = PSPOskNativeStatus::DONE;
934
}
935
#endif
936
937
u16_le *outText = oskParams->fields[0].outtext;
938
939
size_t end = oskParams->fields[0].outtextlength;
940
if (end > inputChars.size())
941
end = inputChars.size() + 1;
942
// Only write the bytes of the output and the null terminator, don't write the rest.
943
for (size_t i = 0; i < end; ++i) {
944
u16 value = 0;
945
if (i < FieldMaxLength() && i < inputChars.size())
946
value = inputChars[i];
947
outText[i] = value;
948
}
949
950
oskParams->base.result = 0;
951
oskParams->fields[0].result = PSP_UTILITY_OSK_RESULT_CHANGED;
952
953
return 0;
954
}
955
956
int PSPOskDialog::Update(int animSpeed) {
957
if (GetStatus() != SCE_UTILITY_STATUS_RUNNING) {
958
return SCE_ERROR_UTILITY_INVALID_STATUS;
959
}
960
961
int cancelButton = GetCancelButton();
962
int confirmButton = GetConfirmButton();
963
964
static int cancelBtnFramesHeld = 0;
965
static int confirmBtnFramesHeld = 0;
966
static int leftBtnFramesHeld = 0;
967
static int upBtnFramesHeld = 0;
968
static int downBtnFramesHeld = 0;
969
static int rightBtnFramesHeld = 0;
970
const int framesHeldThreshold = 10;
971
const int framesHeldRepeatRate = 5;
972
973
UpdateButtons();
974
UpdateCommon();
975
int selectedRow = selectedChar / numKeyCols[currentKeyboard];
976
int selectedExtra = selectedChar % numKeyCols[currentKeyboard];
977
978
#if defined(USING_WIN_UI) || defined(USING_QT_UI) || PPSSPP_PLATFORM(ANDROID) || PPSSPP_PLATFORM(SWITCH)
979
// Windows: Fall back to the OSK/continue normally if we're in fullscreen.
980
// The dialog box doesn't work right if in fullscreen.
981
if (System_GetPropertyBool(SYSPROP_HAS_KEYBOARD)) {
982
if (g_Config.bBypassOSKWithKeyboard && !g_Config.UseFullScreen())
983
return NativeKeyboard();
984
}
985
#endif
986
987
UpdateFade(animSpeed);
988
989
StartDraw();
990
PPGeDrawRect(0, 0, 480, 272, CalcFadedColor(0x63636363));
991
RenderKeyboard();
992
993
auto di = GetI18NCategory(I18NCat::DIALOG);
994
995
PPGeStyle actionStyle = FadedStyle(PPGeAlign::BOX_LEFT, 0.5f);
996
PPGeStyle guideStyle = FadedStyle(PPGeAlign::BOX_LEFT, 0.6f);
997
998
PPGeDrawImage(ImageID("I_SQUARE"), 365, 222, 16, 16, guideStyle);
999
PPGeDrawText(di->T("Space"), 390, 222, actionStyle);
1000
1001
if (GetConfirmButton() != CTRL_CIRCLE) {
1002
PPGeDrawImage(ImageID("I_CROSS"), 45, 222, 16, 16, guideStyle);
1003
PPGeDrawImage(ImageID("I_CIRCLE"), 45, 247, 16, 16, guideStyle);
1004
} else {
1005
PPGeDrawImage(ImageID("I_CIRCLE"), 45, 222, 16, 16, guideStyle);
1006
PPGeDrawImage(ImageID("I_CROSS"), 45, 247, 16, 16, guideStyle);
1007
}
1008
1009
PPGeDrawText(di->T("Select"), 75, 222, actionStyle);
1010
PPGeDrawText(di->T("Delete"), 75, 247, actionStyle);
1011
1012
PPGeDrawText("Start", 135, 220, guideStyle);
1013
PPGeDrawText(di->T("Finish"), 185, 222, actionStyle);
1014
1015
auto lookupLangName = [&](int direction) {
1016
// First, find the valid one...
1017
OskKeyboardLanguage lang = (OskKeyboardLanguage)((OSK_LANGUAGE_COUNT + currentKeyboardLanguage + direction) % OSK_LANGUAGE_COUNT);
1018
OskKeyboardDisplay disp = OskKeyboardCases[lang][LOWERCASE];
1019
FindValidKeyboard(oskParams->fields[0].inputtype, direction, lang, disp);
1020
1021
if (lang == currentKeyboardLanguage) {
1022
return (const char *)nullptr;
1023
}
1024
1025
// Now, let's grab the name.
1026
const char *countryCode = OskKeyboardNames[lang].c_str();
1027
const char *language = languageMapping[countryCode].first.c_str();
1028
1029
// It seems like this is a "fake" country code for extra keyboard purposes.
1030
if (!strcmp(countryCode, "English Full-width"))
1031
language = "English Full-width";
1032
1033
return language;
1034
};
1035
1036
if (OskKeyboardNames[currentKeyboardLanguage] != "ko_KR" && IsKeyboardShiftValid(oskParams->fields[0].inputtype, currentKeyboardLanguage, currentKeyboard)) {
1037
PPGeDrawText("Select", 135, 245, guideStyle);
1038
PPGeDrawText(di->T("Shift"), 185, 247, actionStyle);
1039
}
1040
1041
const char *prevLang = lookupLangName(-1);
1042
if (prevLang) {
1043
PPGeDrawText("L", 235, 220, guideStyle);
1044
PPGeDrawText(prevLang, 255, 222, actionStyle);
1045
}
1046
1047
const char *nextLang = lookupLangName(1);
1048
if (nextLang) {
1049
PPGeDrawText("R", 235, 245, guideStyle);
1050
PPGeDrawText(nextLang, 255, 247, actionStyle);
1051
}
1052
1053
if (IsButtonPressed(CTRL_UP) || IsButtonHeld(CTRL_UP, upBtnFramesHeld, framesHeldThreshold, framesHeldRepeatRate)) {
1054
selectedChar -= numKeyCols[currentKeyboard];
1055
} else if (IsButtonPressed(CTRL_DOWN) || IsButtonHeld(CTRL_DOWN, downBtnFramesHeld, framesHeldThreshold, framesHeldRepeatRate)) {
1056
selectedChar += numKeyCols[currentKeyboard];
1057
} else if (IsButtonPressed(CTRL_LEFT) || IsButtonHeld(CTRL_LEFT, leftBtnFramesHeld, framesHeldThreshold, framesHeldRepeatRate)) {
1058
selectedChar--;
1059
if (((selectedChar + numKeyCols[currentKeyboard]) % numKeyCols[currentKeyboard]) == numKeyCols[currentKeyboard] - 1)
1060
selectedChar += numKeyCols[currentKeyboard];
1061
} else if (IsButtonPressed(CTRL_RIGHT) || IsButtonHeld(CTRL_RIGHT, rightBtnFramesHeld, framesHeldThreshold, framesHeldRepeatRate)) {
1062
selectedChar++;
1063
if ((selectedChar % numKeyCols[currentKeyboard]) == 0)
1064
selectedChar -= numKeyCols[currentKeyboard];
1065
}
1066
1067
selectedChar = (selectedChar + (numKeyCols[currentKeyboard] * numKeyRows[currentKeyboard])) % (numKeyCols[currentKeyboard] * numKeyRows[currentKeyboard]);
1068
1069
if (IsButtonPressed(confirmButton) || IsButtonHeld(confirmButton, confirmBtnFramesHeld, framesHeldThreshold, framesHeldRepeatRate)) {
1070
inputChars = CombinationString(true);
1071
} else if (IsButtonPressed(CTRL_SELECT)) {
1072
// Select now swaps case.
1073
if (IsKeyboardShiftValid(oskParams->fields[0].inputtype, currentKeyboardLanguage, currentKeyboard)) {
1074
if (currentKeyboard == OskKeyboardCases[currentKeyboardLanguage][UPPERCASE])
1075
currentKeyboard = OskKeyboardCases[currentKeyboardLanguage][LOWERCASE];
1076
else
1077
currentKeyboard = OskKeyboardCases[currentKeyboardLanguage][UPPERCASE];
1078
}
1079
1080
if (selectedRow >= numKeyRows[currentKeyboard]) {
1081
selectedRow = numKeyRows[currentKeyboard] - 1;
1082
}
1083
1084
if (selectedExtra >= numKeyCols[currentKeyboard]) {
1085
selectedExtra = numKeyCols[currentKeyboard] - 1;
1086
}
1087
1088
selectedChar = selectedRow * numKeyCols[currentKeyboard] + selectedExtra;
1089
} else if (IsButtonPressed(CTRL_RTRIGGER)) {
1090
// RTRIGGER now cycles languages forward.
1091
currentKeyboardLanguage = (OskKeyboardLanguage)((currentKeyboardLanguage + 1) % OSK_LANGUAGE_COUNT);
1092
currentKeyboard = OskKeyboardCases[currentKeyboardLanguage][LOWERCASE];
1093
FindValidKeyboard(oskParams->fields[0].inputtype, 1, currentKeyboardLanguage, currentKeyboard);
1094
1095
if (selectedRow >= numKeyRows[currentKeyboard]) {
1096
selectedRow = numKeyRows[currentKeyboard] - 1;
1097
}
1098
1099
if (selectedExtra >= numKeyCols[currentKeyboard]) {
1100
selectedExtra = numKeyCols[currentKeyboard] - 1;
1101
}
1102
1103
selectedChar = selectedRow * numKeyCols[currentKeyboard] + selectedExtra;
1104
} else if (IsButtonPressed(CTRL_LTRIGGER)) {
1105
// LTRIGGER now cycles languages backward.
1106
if (currentKeyboardLanguage - 1 >= 0)
1107
currentKeyboardLanguage = (OskKeyboardLanguage)((currentKeyboardLanguage - 1) % OSK_LANGUAGE_COUNT);
1108
else
1109
currentKeyboardLanguage = (OskKeyboardLanguage)(OSK_LANGUAGE_COUNT - 1);
1110
currentKeyboard = OskKeyboardCases[currentKeyboardLanguage][LOWERCASE];
1111
FindValidKeyboard(oskParams->fields[0].inputtype, -1, currentKeyboardLanguage, currentKeyboard);
1112
1113
if (selectedRow >= numKeyRows[currentKeyboard]) {
1114
selectedRow = numKeyRows[currentKeyboard] - 1;
1115
}
1116
1117
if (selectedExtra >= numKeyCols[currentKeyboard]) {
1118
selectedExtra = numKeyCols[currentKeyboard] - 1;
1119
}
1120
1121
selectedChar = selectedRow * numKeyCols[currentKeyboard] + selectedExtra;
1122
} else if (IsButtonPressed(cancelButton) || IsButtonHeld(cancelButton, cancelBtnFramesHeld, framesHeldThreshold, framesHeldRepeatRate)) {
1123
if (inputChars.size() > 0) {
1124
inputChars.resize(inputChars.size() - 1);
1125
if (i_level != 0) {
1126
RemoveKorean();
1127
}
1128
}
1129
} else if (IsButtonPressed(CTRL_START)) {
1130
StartFade(false);
1131
} else if (IsButtonPressed(CTRL_SQUARE) && inputChars.size() < FieldMaxLength()) {
1132
// Use a regular space if the current keyboard isn't Japanese nor full-width English
1133
if (currentKeyboardLanguage != OSK_LANGUAGE_JAPANESE && currentKeyboardLanguage != OSK_LANGUAGE_ENGLISH_FW)
1134
inputChars += u" ";
1135
else
1136
inputChars += u" ";
1137
}
1138
1139
EndDraw();
1140
1141
u16_le *outText = oskParams->fields[0].outtext;
1142
size_t end = oskParams->fields[0].outtextlength;
1143
// Only write the bytes of the output and the null terminator, don't write the rest.
1144
if (end > inputChars.size())
1145
end = inputChars.size() + 1;
1146
for (size_t i = 0; i < end; ++i)
1147
{
1148
u16 value = 0;
1149
if (i < FieldMaxLength() && i < inputChars.size())
1150
value = inputChars[i];
1151
outText[i] = value;
1152
}
1153
1154
oskParams->base.result = 0;
1155
oskParams->fields[0].result = PSP_UTILITY_OSK_RESULT_CHANGED;
1156
return 0;
1157
}
1158
1159
int PSPOskDialog::Shutdown(bool force)
1160
{
1161
if (GetStatus() != SCE_UTILITY_STATUS_FINISHED && !force)
1162
return SCE_ERROR_UTILITY_INVALID_STATUS;
1163
1164
PSPDialog::Shutdown(force);
1165
if (!force) {
1166
ChangeStatusShutdown(OSK_SHUTDOWN_DELAY_US);
1167
}
1168
nativeStatus_ = PSPOskNativeStatus::IDLE;
1169
1170
return 0;
1171
}
1172
1173
void PSPOskDialog::DoState(PointerWrap &p)
1174
{
1175
PSPDialog::DoState(p);
1176
1177
auto s = p.Section("PSPOskDialog", 1, 2);
1178
if (!s)
1179
return;
1180
1181
// TODO: Should we save currentKeyboard/currentKeyboardLanguage?
1182
1183
Do(p, oskParams);
1184
Do(p, oskDesc);
1185
Do(p, oskIntext);
1186
Do(p, oskOuttext);
1187
Do(p, selectedChar);
1188
if (s >= 2) {
1189
Do(p, inputChars);
1190
} else {
1191
// Discard the wstring.
1192
std::wstring wstr;
1193
Do(p, wstr);
1194
}
1195
// Don't need to save state native status or value.
1196
}
1197
1198
pspUtilityDialogCommon *PSPOskDialog::GetCommonParam()
1199
{
1200
return &oskParams->base;
1201
}
1202
1203