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/UI/GamepadEmu.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 <algorithm>
19
20
#include "Common/Data/Color/RGBAUtil.h"
21
#include "Common/Data/Text/I18n.h"
22
#include "Common/System/Display.h"
23
#include "Common/System/System.h"
24
#include "Common/Render/TextureAtlas.h"
25
#include "Common/Math/math_util.h"
26
#include "Common/UI/Context.h"
27
28
#include "Common/Log.h"
29
#include "Common/TimeUtil.h"
30
#include "Core/Config.h"
31
#include "Core/Core.h"
32
#include "Core/System.h"
33
#include "Core/HLE/sceCtrl.h"
34
#include "Core/ControlMapper.h"
35
#include "UI/GamepadEmu.h"
36
37
const float TOUCH_SCALE_FACTOR = 1.5f;
38
39
static uint32_t usedPointerMask = 0;
40
static uint32_t analogPointerMask = 0;
41
42
static float g_gamepadOpacity;
43
static double g_lastTouch;
44
45
void GamepadUpdateOpacity(float force) {
46
if (force >= 0.0f) {
47
g_gamepadOpacity = force;
48
return;
49
}
50
if (coreState != CORE_RUNNING) {
51
g_gamepadOpacity = 0.0f;
52
return;
53
}
54
55
float fadeAfterSeconds = g_Config.iTouchButtonHideSeconds;
56
float fadeTransitionSeconds = std::min(fadeAfterSeconds, 0.5f);
57
float opacity = g_Config.iTouchButtonOpacity / 100.0f;
58
59
float multiplier = 1.0f;
60
float secondsWithoutTouch = time_now_d() - g_lastTouch;
61
if (secondsWithoutTouch >= fadeAfterSeconds && fadeAfterSeconds > 0.0f) {
62
if (secondsWithoutTouch >= fadeAfterSeconds + fadeTransitionSeconds) {
63
multiplier = 0.0f;
64
} else {
65
float secondsIntoFade = secondsWithoutTouch - fadeAfterSeconds;
66
multiplier = 1.0f - (secondsIntoFade / fadeTransitionSeconds);
67
}
68
}
69
70
g_gamepadOpacity = opacity * multiplier;
71
}
72
73
void GamepadTouch(bool reset) {
74
g_lastTouch = reset ? 0.0f : time_now_d();
75
}
76
77
float GamepadGetOpacity() {
78
return g_gamepadOpacity;
79
}
80
81
static u32 GetButtonColor() {
82
return g_Config.iTouchButtonStyle != 0 ? 0xFFFFFF : 0xc0b080;
83
}
84
85
GamepadView::GamepadView(const char *key, UI::LayoutParams *layoutParams) : UI::View(layoutParams), key_(key) {}
86
87
std::string GamepadView::DescribeText() const {
88
auto co = GetI18NCategory(I18NCat::CONTROLS);
89
return std::string(co->T(key_));
90
}
91
92
void MultiTouchButton::GetContentDimensions(const UIContext &dc, float &w, float &h) const {
93
const AtlasImage *image = dc.Draw()->GetAtlas()->getImage(bgImg_);
94
if (image) {
95
w = image->w * scale_;
96
h = image->h * scale_;
97
} else {
98
w = 0.0f;
99
h = 0.0f;
100
}
101
}
102
103
bool MultiTouchButton::Touch(const TouchInput &input) {
104
bool retval = GamepadView::Touch(input);
105
if ((input.flags & TOUCH_DOWN) && bounds_.Contains(input.x, input.y)) {
106
pointerDownMask_ |= 1 << input.id;
107
usedPointerMask |= 1 << input.id;
108
}
109
if (input.flags & TOUCH_MOVE) {
110
if (bounds_.Contains(input.x, input.y) && !(analogPointerMask & (1 << input.id)))
111
pointerDownMask_ |= 1 << input.id;
112
else
113
pointerDownMask_ &= ~(1 << input.id);
114
}
115
if (input.flags & TOUCH_UP) {
116
pointerDownMask_ &= ~(1 << input.id);
117
usedPointerMask &= ~(1 << input.id);
118
}
119
if (input.flags & TOUCH_RELEASE_ALL) {
120
pointerDownMask_ = 0;
121
usedPointerMask = 0;
122
}
123
return retval;
124
}
125
126
void MultiTouchButton::Draw(UIContext &dc) {
127
float opacity = g_gamepadOpacity;
128
if (opacity <= 0.0f)
129
return;
130
131
float scale = scale_;
132
if (IsDown()) {
133
if (g_Config.iTouchButtonStyle == 2) {
134
opacity *= 1.35f;
135
} else {
136
scale *= TOUCH_SCALE_FACTOR;
137
opacity *= 1.15f;
138
}
139
}
140
141
uint32_t colorBg = colorAlpha(GetButtonColor(), opacity);
142
uint32_t downBg = colorAlpha(0xFFFFFF, opacity * 0.5f);
143
uint32_t color = colorAlpha(0xFFFFFF, opacity);
144
145
if (IsDown() && g_Config.iTouchButtonStyle == 2) {
146
if (bgImg_ != bgDownImg_)
147
dc.Draw()->DrawImageRotated(bgDownImg_, bounds_.centerX(), bounds_.centerY(), scale, bgAngle_ * (M_PI * 2 / 360.0f), downBg, flipImageH_);
148
}
149
150
dc.Draw()->DrawImageRotated(bgImg_, bounds_.centerX(), bounds_.centerY(), scale, bgAngle_ * (M_PI * 2 / 360.0f), colorBg, flipImageH_);
151
152
int y = bounds_.centerY();
153
// Hack round the fact that the center of the rectangular picture the triangle is contained in
154
// is not at the "weight center" of the triangle.
155
if (img_ == ImageID("I_TRIANGLE"))
156
y -= 2.8f * scale;
157
dc.Draw()->DrawImageRotated(img_, bounds_.centerX(), y, scale, angle_ * (M_PI * 2 / 360.0f), color);
158
}
159
160
bool BoolButton::Touch(const TouchInput &input) {
161
bool lastDown = pointerDownMask_ != 0;
162
bool retval = MultiTouchButton::Touch(input);
163
bool down = pointerDownMask_ != 0;
164
165
if (down != lastDown) {
166
*value_ = down;
167
UI::EventParams params{ this };
168
params.a = down;
169
OnChange.Trigger(params);
170
}
171
return retval;
172
}
173
174
bool PSPButton::Touch(const TouchInput &input) {
175
bool lastDown = pointerDownMask_ != 0;
176
bool retval = MultiTouchButton::Touch(input);
177
bool down = pointerDownMask_ != 0;
178
if (down && !lastDown) {
179
if (g_Config.bHapticFeedback) {
180
System_Vibrate(HAPTIC_VIRTUAL_KEY);
181
}
182
__CtrlUpdateButtons(pspButtonBit_, 0);
183
} else if (lastDown && !down) {
184
__CtrlUpdateButtons(0, pspButtonBit_);
185
}
186
return retval;
187
}
188
189
bool CustomButton::IsDown() {
190
return (toggle_ && on_) || (!toggle_ && pointerDownMask_ != 0);
191
}
192
193
void CustomButton::GetContentDimensions(const UIContext &dc, float &w, float &h) const {
194
MultiTouchButton::GetContentDimensions(dc, w, h);
195
if (invertedContextDimension_) {
196
float tmp = w;
197
w = h;
198
h = tmp;
199
}
200
}
201
202
bool CustomButton::Touch(const TouchInput &input) {
203
using namespace CustomKeyData;
204
bool lastDown = pointerDownMask_ != 0;
205
bool retval = MultiTouchButton::Touch(input);
206
bool down = pointerDownMask_ != 0;
207
208
if (down && !lastDown) {
209
if (g_Config.bHapticFeedback)
210
System_Vibrate(HAPTIC_VIRTUAL_KEY);
211
212
if (!repeat_) {
213
for (int i = 0; i < ARRAY_SIZE(customKeyList); i++) {
214
if (pspButtonBit_ & (1ULL << i)) {
215
controlMapper_->PSPKey(DEVICE_ID_TOUCH, customKeyList[i].c, (on_ && toggle_) ? KEY_UP : KEY_DOWN);
216
}
217
}
218
}
219
on_ = toggle_ ? !on_ : true;
220
} else if (!toggle_ && lastDown && !down) {
221
if (!repeat_) {
222
for (int i = 0; i < ARRAY_SIZE(customKeyList); i++) {
223
if (pspButtonBit_ & (1ULL << i)) {
224
controlMapper_->PSPKey(DEVICE_ID_TOUCH, customKeyList[i].c, KEY_UP);
225
}
226
}
227
}
228
on_ = false;
229
}
230
return retval;
231
}
232
233
void CustomButton::Update() {
234
MultiTouchButton::Update();
235
using namespace CustomKeyData;
236
237
if (repeat_) {
238
// Give the game some time to process the input, frame based so it's faster when fast-forwarding.
239
static constexpr int DOWN_FRAME = 5;
240
241
if (pressedFrames_ == 2*DOWN_FRAME) {
242
pressedFrames_ = 0;
243
} else if (pressedFrames_ == DOWN_FRAME) {
244
for (int i = 0; i < ARRAY_SIZE(customKeyList); i++) {
245
if (pspButtonBit_ & (1ULL << i)) {
246
controlMapper_->PSPKey(DEVICE_ID_TOUCH, customKeyList[i].c, KEY_UP);
247
}
248
}
249
} else if (on_ && pressedFrames_ == 0) {
250
for (int i = 0; i < ARRAY_SIZE(customKeyList); i++) {
251
if (pspButtonBit_ & (1ULL << i)) {
252
controlMapper_->PSPKey(DEVICE_ID_TOUCH, customKeyList[i].c, KEY_DOWN);
253
}
254
}
255
pressedFrames_ = 1;
256
}
257
258
if (pressedFrames_ > 0)
259
pressedFrames_++;
260
}
261
}
262
263
bool PSPButton::IsDown() {
264
return (__CtrlPeekButtonsVisual() & pspButtonBit_) != 0;
265
}
266
267
PSPDpad::PSPDpad(ImageID arrowIndex, const char *key, ImageID arrowDownIndex, ImageID overlayIndex, float scale, float spacing, UI::LayoutParams *layoutParams)
268
: GamepadView(key, layoutParams), arrowIndex_(arrowIndex), arrowDownIndex_(arrowDownIndex), overlayIndex_(overlayIndex),
269
scale_(scale), spacing_(spacing), dragPointerId_(-1), down_(0) {
270
}
271
272
void PSPDpad::GetContentDimensions(const UIContext &dc, float &w, float &h) const {
273
const AtlasImage *image = dc.Draw()->GetAtlas()->getImage(arrowIndex_);
274
if (image) {
275
w = 2.0f * D_pad_Radius * spacing_ + image->w * scale_;
276
h = w;
277
} else {
278
w = 0.0f;
279
h = 0.0f;
280
}
281
}
282
283
bool PSPDpad::Touch(const TouchInput &input) {
284
bool retval = GamepadView::Touch(input);
285
286
if (input.flags & TOUCH_DOWN) {
287
if (dragPointerId_ == -1 && bounds_.Contains(input.x, input.y)) {
288
dragPointerId_ = input.id;
289
usedPointerMask |= 1 << input.id;
290
ProcessTouch(input.x, input.y, true);
291
}
292
}
293
if (input.flags & TOUCH_MOVE) {
294
if (dragPointerId_ == -1 && bounds_.Contains(input.x, input.y) && !(analogPointerMask & (1 << input.id))) {
295
dragPointerId_ = input.id;
296
}
297
if (input.id == dragPointerId_) {
298
ProcessTouch(input.x, input.y, true);
299
}
300
}
301
if (input.flags & TOUCH_UP) {
302
if (input.id == dragPointerId_) {
303
dragPointerId_ = -1;
304
usedPointerMask &= ~(1 << input.id);
305
ProcessTouch(input.x, input.y, false);
306
}
307
}
308
return retval;
309
}
310
311
void PSPDpad::ProcessTouch(float x, float y, bool down) {
312
float stick_size = bounds_.w;
313
float inv_stick_size = 1.0f / stick_size;
314
const float deadzone = 0.05f;
315
316
float dx = (x - bounds_.centerX()) * inv_stick_size;
317
float dy = (y - bounds_.centerY()) * inv_stick_size;
318
float rad = sqrtf(dx * dx + dy * dy);
319
if (!g_Config.bStickyTouchDPad && (rad < deadzone || fabs(dx) > 0.5f || fabs(dy) > 0.5))
320
down = false;
321
322
int ctrlMask = 0;
323
bool fourWay = g_Config.bDisableDpadDiagonals || rad < 0.2f;
324
if (down) {
325
if (fourWay) {
326
int direction = (int)(floorf((atan2f(dy, dx) / (2 * M_PI) * 4) + 0.5f)) & 3;
327
switch (direction) {
328
case 0: ctrlMask = CTRL_RIGHT; break;
329
case 1: ctrlMask = CTRL_DOWN; break;
330
case 2: ctrlMask = CTRL_LEFT; break;
331
case 3: ctrlMask = CTRL_UP; break;
332
}
333
// 4 way pad
334
} else {
335
// 8 way pad
336
int direction = (int)(floorf((atan2f(dy, dx) / (2 * M_PI) * 8) + 0.5f)) & 7;
337
switch (direction) {
338
case 0: ctrlMask = CTRL_RIGHT; break;
339
case 1: ctrlMask = CTRL_RIGHT | CTRL_DOWN; break;
340
case 2: ctrlMask = CTRL_DOWN; break;
341
case 3: ctrlMask = CTRL_DOWN | CTRL_LEFT; break;
342
case 4: ctrlMask = CTRL_LEFT; break;
343
case 5: ctrlMask = CTRL_UP | CTRL_LEFT; break;
344
case 6: ctrlMask = CTRL_UP; break;
345
case 7: ctrlMask = CTRL_UP | CTRL_RIGHT; break;
346
}
347
}
348
}
349
350
int lastDown = down_;
351
int pressed = ctrlMask & ~lastDown;
352
int released = (~ctrlMask) & lastDown;
353
down_ = ctrlMask;
354
bool vibrate = false;
355
static const int dir[4] = { CTRL_RIGHT, CTRL_DOWN, CTRL_LEFT, CTRL_UP };
356
for (int i = 0; i < 4; i++) {
357
if (pressed & dir[i]) {
358
vibrate = true;
359
__CtrlUpdateButtons(dir[i], 0);
360
}
361
if (released & dir[i]) {
362
__CtrlUpdateButtons(0, dir[i]);
363
}
364
}
365
if (vibrate && g_Config.bHapticFeedback) {
366
System_Vibrate(HAPTIC_VIRTUAL_KEY);
367
}
368
}
369
370
void PSPDpad::Draw(UIContext &dc) {
371
float opacity = g_gamepadOpacity;
372
if (opacity <= 0.0f)
373
return;
374
375
static const float xoff[4] = {1, 0, -1, 0};
376
static const float yoff[4] = {0, 1, 0, -1};
377
static const int dir[4] = {CTRL_RIGHT, CTRL_DOWN, CTRL_LEFT, CTRL_UP};
378
int buttons = __CtrlPeekButtons();
379
float r = D_pad_Radius * spacing_;
380
for (int i = 0; i < 4; i++) {
381
bool isDown = (buttons & dir[i]) != 0;
382
383
float x = bounds_.centerX() + xoff[i] * r;
384
float y = bounds_.centerY() + yoff[i] * r;
385
float x2 = bounds_.centerX() + xoff[i] * (r + 10.f * scale_);
386
float y2 = bounds_.centerY() + yoff[i] * (r + 10.f * scale_);
387
float angle = i * (M_PI / 2.0f);
388
float imgScale = isDown ? scale_ * TOUCH_SCALE_FACTOR : scale_;
389
float imgOpacity = opacity;
390
391
if (isDown && g_Config.iTouchButtonStyle == 2) {
392
imgScale = scale_;
393
imgOpacity *= 1.35f;
394
395
uint32_t downBg = colorAlpha(0x00FFFFFF, imgOpacity * 0.5f);
396
if (arrowIndex_ != arrowDownIndex_)
397
dc.Draw()->DrawImageRotated(arrowDownIndex_, x, y, imgScale, angle + PI, downBg, false);
398
}
399
400
uint32_t colorBg = colorAlpha(GetButtonColor(), imgOpacity);
401
uint32_t color = colorAlpha(0xFFFFFF, imgOpacity);
402
403
dc.Draw()->DrawImageRotated(arrowIndex_, x, y, imgScale, angle + PI, colorBg, false);
404
if (overlayIndex_.isValid())
405
dc.Draw()->DrawImageRotated(overlayIndex_, x2, y2, imgScale, angle + PI, color);
406
}
407
}
408
409
PSPStick::PSPStick(ImageID bgImg, const char *key, ImageID stickImg, ImageID stickDownImg, int stick, float scale, UI::LayoutParams *layoutParams)
410
: GamepadView(key, layoutParams), dragPointerId_(-1), bgImg_(bgImg), stickImageIndex_(stickImg), stickDownImg_(stickDownImg), stick_(stick), scale_(scale), centerX_(-1), centerY_(-1) {
411
stick_size_ = 50;
412
}
413
414
void PSPStick::GetContentDimensions(const UIContext &dc, float &w, float &h) const {
415
dc.Draw()->GetAtlas()->measureImage(bgImg_, &w, &h);
416
w *= scale_;
417
h *= scale_;
418
}
419
420
void PSPStick::Draw(UIContext &dc) {
421
float opacity = g_gamepadOpacity;
422
if (opacity <= 0.0f)
423
return;
424
425
if (dragPointerId_ != -1 && g_Config.iTouchButtonStyle == 2) {
426
opacity *= 1.35f;
427
}
428
429
uint32_t colorBg = colorAlpha(GetButtonColor(), opacity);
430
uint32_t downBg = colorAlpha(0x00FFFFFF, opacity * 0.5f);
431
432
if (centerX_ < 0.0f) {
433
centerX_ = bounds_.centerX();
434
centerY_ = bounds_.centerY();
435
}
436
437
float stickX = centerX_;
438
float stickY = centerY_;
439
440
float dx, dy;
441
__CtrlPeekAnalog(stick_, &dx, &dy);
442
443
if (!g_Config.bHideStickBackground)
444
dc.Draw()->DrawImage(bgImg_, stickX, stickY, 1.0f * scale_, colorBg, ALIGN_CENTER);
445
float headScale = stick_ ? g_Config.fRightStickHeadScale : g_Config.fLeftStickHeadScale;
446
if (dragPointerId_ != -1 && g_Config.iTouchButtonStyle == 2 && stickDownImg_ != stickImageIndex_)
447
dc.Draw()->DrawImage(stickDownImg_, stickX + dx * stick_size_ * scale_, stickY - dy * stick_size_ * scale_, 1.0f * scale_ * headScale, downBg, ALIGN_CENTER);
448
dc.Draw()->DrawImage(stickImageIndex_, stickX + dx * stick_size_ * scale_, stickY - dy * stick_size_ * scale_, 1.0f * scale_ * headScale, colorBg, ALIGN_CENTER);
449
}
450
451
bool PSPStick::Touch(const TouchInput &input) {
452
bool retval = GamepadView::Touch(input);
453
if (input.flags & TOUCH_RELEASE_ALL) {
454
dragPointerId_ = -1;
455
centerX_ = bounds_.centerX();
456
centerY_ = bounds_.centerY();
457
__CtrlSetAnalogXY(stick_, 0.0f, 0.0f);
458
usedPointerMask = 0;
459
analogPointerMask = 0;
460
return retval;
461
}
462
if (input.flags & TOUCH_DOWN) {
463
float fac = 0.5f*(stick_ ? g_Config.fRightStickHeadScale : g_Config.fLeftStickHeadScale)-0.5f;
464
if (dragPointerId_ == -1 && bounds_.Expand(bounds_.w*fac, bounds_.h*fac).Contains(input.x, input.y)) {
465
if (g_Config.bAutoCenterTouchAnalog) {
466
centerX_ = input.x;
467
centerY_ = input.y;
468
} else {
469
centerX_ = bounds_.centerX();
470
centerY_ = bounds_.centerY();
471
}
472
dragPointerId_ = input.id;
473
usedPointerMask |= 1 << input.id;
474
analogPointerMask |= 1 << input.id;
475
ProcessTouch(input.x, input.y, true);
476
retval = true;
477
}
478
}
479
if (input.flags & TOUCH_MOVE) {
480
if (input.id == dragPointerId_) {
481
ProcessTouch(input.x, input.y, true);
482
retval = true;
483
}
484
}
485
if (input.flags & TOUCH_UP) {
486
if (input.id == dragPointerId_) {
487
dragPointerId_ = -1;
488
centerX_ = bounds_.centerX();
489
centerY_ = bounds_.centerY();
490
usedPointerMask &= ~(1 << input.id);
491
analogPointerMask &= ~(1 << input.id);
492
ProcessTouch(input.x, input.y, false);
493
retval = true;
494
}
495
}
496
return retval;
497
}
498
499
void PSPStick::ProcessTouch(float x, float y, bool down) {
500
if (down && centerX_ >= 0.0f) {
501
float inv_stick_size = 1.0f / (stick_size_ * scale_);
502
503
float dx = (x - centerX_) * inv_stick_size;
504
float dy = (y - centerY_) * inv_stick_size;
505
// Do not clamp to a circle! The PSP has nearly square range!
506
507
// Old code to clamp to a circle
508
// float len = sqrtf(dx * dx + dy * dy);
509
// if (len > 1.0f) {
510
// dx /= len;
511
// dy /= len;
512
//}
513
514
// Still need to clamp to a square
515
dx = std::min(1.0f, std::max(-1.0f, dx));
516
dy = std::min(1.0f, std::max(-1.0f, dy));
517
518
__CtrlSetAnalogXY(stick_, dx, -dy);
519
} else {
520
__CtrlSetAnalogXY(stick_, 0.0f, 0.0f);
521
}
522
}
523
524
PSPCustomStick::PSPCustomStick(ImageID bgImg, const char *key, ImageID stickImg, ImageID stickDownImg, int stick, float scale, UI::LayoutParams *layoutParams)
525
: PSPStick(bgImg, key, stickImg, stickDownImg, stick, scale, layoutParams) {
526
}
527
528
void PSPCustomStick::Draw(UIContext &dc) {
529
float opacity = g_gamepadOpacity;
530
if (opacity <= 0.0f)
531
return;
532
533
if (dragPointerId_ != -1 && g_Config.iTouchButtonStyle == 2) {
534
opacity *= 1.35f;
535
}
536
537
uint32_t colorBg = colorAlpha(GetButtonColor(), opacity);
538
uint32_t downBg = colorAlpha(0x00FFFFFF, opacity * 0.5f);
539
540
if (centerX_ < 0.0f) {
541
centerX_ = bounds_.centerX();
542
centerY_ = bounds_.centerY();
543
}
544
545
float stickX = centerX_;
546
float stickY = centerY_;
547
548
float dx, dy;
549
dx = posX_;
550
dy = -posY_;
551
552
if (!g_Config.bHideStickBackground)
553
dc.Draw()->DrawImage(bgImg_, stickX, stickY, 1.0f * scale_, colorBg, ALIGN_CENTER);
554
if (dragPointerId_ != -1 && g_Config.iTouchButtonStyle == 2 && stickDownImg_ != stickImageIndex_)
555
dc.Draw()->DrawImage(stickDownImg_, stickX + dx * stick_size_ * scale_, stickY - dy * stick_size_ * scale_, 1.0f*scale_*g_Config.fRightStickHeadScale, downBg, ALIGN_CENTER);
556
dc.Draw()->DrawImage(stickImageIndex_, stickX + dx * stick_size_ * scale_, stickY - dy * stick_size_ * scale_, 1.0f*scale_*g_Config.fRightStickHeadScale, colorBg, ALIGN_CENTER);
557
}
558
559
bool PSPCustomStick::Touch(const TouchInput &input) {
560
bool retval = GamepadView::Touch(input);
561
if (input.flags & TOUCH_RELEASE_ALL) {
562
dragPointerId_ = -1;
563
centerX_ = bounds_.centerX();
564
centerY_ = bounds_.centerY();
565
posX_ = 0.0f;
566
posY_ = 0.0f;
567
usedPointerMask = 0;
568
analogPointerMask = 0;
569
return false;
570
}
571
if (input.flags & TOUCH_DOWN) {
572
float fac = 0.5f*g_Config.fRightStickHeadScale-0.5f;
573
if (dragPointerId_ == -1 && bounds_.Expand(bounds_.w*fac, bounds_.h*fac).Contains(input.x, input.y)) {
574
if (g_Config.bAutoCenterTouchAnalog) {
575
centerX_ = input.x;
576
centerY_ = input.y;
577
} else {
578
centerX_ = bounds_.centerX();
579
centerY_ = bounds_.centerY();
580
}
581
dragPointerId_ = input.id;
582
usedPointerMask |= 1 << input.id;
583
analogPointerMask |= 1 << input.id;
584
ProcessTouch(input.x, input.y, true);
585
retval = true;
586
}
587
}
588
if (input.flags & TOUCH_MOVE) {
589
if (input.id == dragPointerId_) {
590
ProcessTouch(input.x, input.y, true);
591
retval = true;
592
}
593
}
594
if (input.flags & TOUCH_UP) {
595
if (input.id == dragPointerId_) {
596
dragPointerId_ = -1;
597
centerX_ = bounds_.centerX();
598
centerY_ = bounds_.centerY();
599
usedPointerMask &= ~(1 << input.id);
600
analogPointerMask &= ~(1 << input.id);
601
ProcessTouch(input.x, input.y, false);
602
retval = true;
603
}
604
}
605
return retval;
606
}
607
608
void PSPCustomStick::ProcessTouch(float x, float y, bool down) {
609
static const int buttons[] = {0, CTRL_LTRIGGER, CTRL_RTRIGGER, CTRL_SQUARE, CTRL_TRIANGLE, CTRL_CIRCLE, CTRL_CROSS, CTRL_UP, CTRL_DOWN, CTRL_LEFT, CTRL_RIGHT, CTRL_START, CTRL_SELECT};
610
static const int analogs[] = {VIRTKEY_AXIS_RIGHT_Y_MAX, VIRTKEY_AXIS_RIGHT_Y_MIN, VIRTKEY_AXIS_RIGHT_X_MIN, VIRTKEY_AXIS_RIGHT_X_MAX, VIRTKEY_AXIS_Y_MAX, VIRTKEY_AXIS_Y_MIN, VIRTKEY_AXIS_X_MIN, VIRTKEY_AXIS_X_MAX};
611
u32 press = 0;
612
u32 release = 0;
613
614
auto toggle = [&](int config, bool simpleCheck, bool diagCheck = true) {
615
if (config <= 0 || (size_t)config >= ARRAY_SIZE(buttons))
616
return;
617
618
if (simpleCheck && (!g_Config.bRightAnalogDisableDiagonal || diagCheck))
619
press |= buttons[config];
620
else
621
release |= buttons[config];
622
};
623
624
auto analog = [&](float dx, float dy) {
625
if (g_Config.bRightAnalogDisableDiagonal) {
626
if (fabs(dx) > fabs(dy)) {
627
dy = 0.0f;
628
} else {
629
dx = 0.0f;
630
}
631
}
632
633
auto assign = [&](int config, float value) {
634
if (config < ARRAY_SIZE(buttons) || config >= ARRAY_SIZE(buttons) + ARRAY_SIZE(analogs)) {
635
return;
636
}
637
switch(analogs[config - ARRAY_SIZE(buttons)]) {
638
case VIRTKEY_AXIS_Y_MAX:
639
__CtrlSetAnalogY(0, value);
640
break;
641
case VIRTKEY_AXIS_Y_MIN:
642
__CtrlSetAnalogY(0, value * -1.0f);
643
break;
644
case VIRTKEY_AXIS_X_MIN:
645
__CtrlSetAnalogX(0, value * -1.0f);
646
break;
647
case VIRTKEY_AXIS_X_MAX:
648
__CtrlSetAnalogX(0, value);
649
break;
650
case VIRTKEY_AXIS_RIGHT_Y_MAX:
651
__CtrlSetAnalogY(1, value);
652
break;
653
case VIRTKEY_AXIS_RIGHT_Y_MIN:
654
__CtrlSetAnalogY(1, value * -1.0f);
655
break;
656
case VIRTKEY_AXIS_RIGHT_X_MIN:
657
__CtrlSetAnalogX(1, value * -1.0f);
658
break;
659
case VIRTKEY_AXIS_RIGHT_X_MAX:
660
__CtrlSetAnalogX(1, value);
661
break;
662
}
663
};
664
665
// if/when we ever get iLeftAnalog settings, check stick_ for the config to use
666
// let 0.0f through during centering
667
if (dy >= 0.0f) {
668
// down
669
assign(g_Config.iRightAnalogUp, 0.0f);
670
assign(g_Config.iRightAnalogDown, dy);
671
}
672
if (dy <= 0.0f) {
673
// up
674
assign(g_Config.iRightAnalogDown, 0.0f);
675
assign(g_Config.iRightAnalogUp, dy * -1.0f);
676
}
677
if (dx <= 0.0f) {
678
// left
679
assign(g_Config.iRightAnalogRight, 0.0f);
680
assign(g_Config.iRightAnalogLeft, dx * -1.0f);
681
}
682
if (dx >= 0.0f) {
683
// right
684
assign(g_Config.iRightAnalogLeft, 0.0f);
685
assign(g_Config.iRightAnalogRight, dx);
686
}
687
};
688
689
if (down && centerX_ >= 0.0f) {
690
float inv_stick_size = 1.0f / (stick_size_ * scale_);
691
692
float dx = (x - centerX_) * inv_stick_size;
693
float dy = (y - centerY_) * inv_stick_size;
694
695
dx = std::min(1.0f, std::max(-1.0f, dx));
696
dy = std::min(1.0f, std::max(-1.0f, dy));
697
698
toggle(g_Config.iRightAnalogRight, dx > 0.5f, fabs(dx) > fabs(dy));
699
toggle(g_Config.iRightAnalogLeft, dx < -0.5f, fabs(dx) > fabs(dy));
700
toggle(g_Config.iRightAnalogUp, dy < -0.5f, fabs(dx) <= fabs(dy));
701
toggle(g_Config.iRightAnalogDown, dy > 0.5f, fabs(dx) <= fabs(dy));
702
toggle(g_Config.iRightAnalogPress, true);
703
704
analog(dx, dy);
705
706
posX_ = dx;
707
posY_ = dy;
708
709
} else {
710
toggle(g_Config.iRightAnalogRight, false);
711
toggle(g_Config.iRightAnalogLeft, false);
712
toggle(g_Config.iRightAnalogUp, false);
713
toggle(g_Config.iRightAnalogDown, false);
714
toggle(g_Config.iRightAnalogPress, false);
715
716
analog(0.0f, 0.0f);
717
718
posX_ = 0.0f;
719
posY_ = 0.0f;
720
}
721
722
if (release || press) {
723
__CtrlUpdateButtons(press, release);
724
}
725
}
726
727
void InitPadLayout(float xres, float yres, float globalScale) {
728
const float scale = globalScale;
729
const int halfW = xres / 2;
730
731
auto initTouchPos = [=](ConfigTouchPos &touch, float x, float y) {
732
if (touch.x == -1.0f || touch.y == -1.0f) {
733
touch.x = x / xres;
734
touch.y = std::max(y, 20.0f * globalScale) / yres;
735
touch.scale = scale;
736
}
737
};
738
739
// PSP buttons (triangle, circle, square, cross)---------------------
740
// space between the PSP buttons (triangle, circle, square and cross)
741
if (g_Config.fActionButtonSpacing < 0) {
742
g_Config.fActionButtonSpacing = 1.0f;
743
}
744
745
// Position of the circle button (the PSP circle button). It is the farthest to the left
746
float Action_button_spacing = g_Config.fActionButtonSpacing * baseActionButtonSpacing;
747
int Action_button_center_X = xres - Action_button_spacing * 2;
748
int Action_button_center_Y = yres - Action_button_spacing * 2;
749
if (g_Config.touchRightAnalogStick.show) {
750
Action_button_center_Y -= 150 * scale;
751
}
752
initTouchPos(g_Config.touchActionButtonCenter, Action_button_center_X, Action_button_center_Y);
753
754
//D-PAD (up down left right) (aka PSP cross)----------------------------
755
//radius to the D-pad
756
// TODO: Make configurable
757
758
int D_pad_X = 2.5 * D_pad_Radius * scale;
759
int D_pad_Y = yres - D_pad_Radius * scale;
760
if (g_Config.touchAnalogStick.show) {
761
D_pad_Y -= 200 * scale;
762
}
763
initTouchPos(g_Config.touchDpad, D_pad_X, D_pad_Y);
764
765
//analog stick-------------------------------------------------------
766
//keep the analog stick right below the D pad
767
int analog_stick_X = D_pad_X;
768
int analog_stick_Y = yres - 80 * scale;
769
initTouchPos(g_Config.touchAnalogStick, analog_stick_X, analog_stick_Y);
770
771
//right analog stick-------------------------------------------------
772
//keep the right analog stick right below the face buttons
773
int right_analog_stick_X = Action_button_center_X;
774
int right_analog_stick_Y = yres - 80 * scale;
775
initTouchPos(g_Config.touchRightAnalogStick, right_analog_stick_X, right_analog_stick_Y);
776
777
//select, start, throttle--------------------------------------------
778
//space between the bottom keys (space between select, start and un-throttle)
779
float bottom_key_spacing = 100;
780
if (g_display.dp_xres < 750) {
781
bottom_key_spacing *= 0.8f;
782
}
783
784
// On IOS, nudge the bottom button up a little to avoid the task switcher.
785
#if PPSSPP_PLATFORM(IOS)
786
const float bottom_button_Y = 80.0f;
787
#else
788
const float bottom_button_Y = 60.0f;
789
#endif
790
791
int start_key_X = halfW + bottom_key_spacing * scale;
792
int start_key_Y = yres - bottom_button_Y * scale;
793
initTouchPos(g_Config.touchStartKey, start_key_X, start_key_Y);
794
795
int select_key_X = halfW;
796
int select_key_Y = yres - bottom_button_Y * scale;
797
initTouchPos(g_Config.touchSelectKey, select_key_X, select_key_Y);
798
799
int fast_forward_key_X = halfW - bottom_key_spacing * scale;
800
int fast_forward_key_Y = yres - bottom_button_Y * scale;
801
initTouchPos(g_Config.touchFastForwardKey, fast_forward_key_X, fast_forward_key_Y);
802
803
// L and R------------------------------------------------------------
804
// Put them above the analog stick / above the buttons to the right.
805
// The corners were very hard to reach..
806
807
int l_key_X = 60 * scale;
808
int l_key_Y = yres - 380 * scale;
809
initTouchPos(g_Config.touchLKey, l_key_X, l_key_Y);
810
811
int r_key_X = xres - 60 * scale;
812
int r_key_Y = l_key_Y;
813
initTouchPos(g_Config.touchRKey, r_key_X, r_key_Y);
814
815
struct { float x; float y; } customButtonPositions[10] = {
816
{ 1.2f, 0.5f },
817
{ 2.2f, 0.5f },
818
{ 3.2f, 0.5f },
819
{ 1.2f, 0.333f },
820
{ 2.2f, 0.333f },
821
{ -1.2f, 0.5f },
822
{ -2.2f, 0.5f },
823
{ -3.2f, 0.5f },
824
{ -1.2f, 0.333f },
825
{ -2.2f, 0.333f },
826
};
827
828
for (int i = 0; i < Config::CUSTOM_BUTTON_COUNT; i++) {
829
float y_offset = (float)(i / 10) * 0.08333f;
830
831
int combo_key_X = halfW + bottom_key_spacing * scale * customButtonPositions[i % 10].x;
832
int combo_key_Y = yres * (y_offset + customButtonPositions[i % 10].y);
833
834
initTouchPos(g_Config.touchCustom[i], combo_key_X, combo_key_Y);
835
}
836
}
837
838
UI::ViewGroup *CreatePadLayout(float xres, float yres, bool *pause, bool showPauseButton, ControlMapper* controllMapper) {
839
using namespace UI;
840
841
AnchorLayout *root = new AnchorLayout(new LayoutParams(FILL_PARENT, FILL_PARENT));
842
if (!g_Config.bShowTouchControls) {
843
return root;
844
}
845
846
struct ButtonOffset {
847
float x;
848
float y;
849
};
850
auto buttonLayoutParams = [=](const ConfigTouchPos &touch, ButtonOffset off = { 0, 0 }) {
851
return new AnchorLayoutParams(touch.x * xres + off.x, touch.y * yres + off.y, NONE, NONE, true);
852
};
853
854
// Space between the PSP buttons (traingle, circle, square and cross)
855
const float actionButtonSpacing = g_Config.fActionButtonSpacing * baseActionButtonSpacing;
856
// Position of the circle button (the PSP circle button). It is the farthest to the right.
857
ButtonOffset circleOffset{ actionButtonSpacing, 0.0f };
858
ButtonOffset crossOffset{ 0.0f, actionButtonSpacing };
859
ButtonOffset triangleOffset{ 0.0f, -actionButtonSpacing };
860
ButtonOffset squareOffset{ -actionButtonSpacing, 0.0f };
861
862
const int halfW = xres / 2;
863
864
const ImageID roundImage = g_Config.iTouchButtonStyle ? ImageID("I_ROUND_LINE") : ImageID("I_ROUND");
865
const ImageID rectImage = g_Config.iTouchButtonStyle ? ImageID("I_RECT_LINE") : ImageID("I_RECT");
866
const ImageID shoulderImage = g_Config.iTouchButtonStyle ? ImageID("I_SHOULDER_LINE") : ImageID("I_SHOULDER");
867
const ImageID stickImage = g_Config.iTouchButtonStyle ? ImageID("I_STICK_LINE") : ImageID("I_STICK");
868
const ImageID stickBg = g_Config.iTouchButtonStyle ? ImageID("I_STICK_BG_LINE") : ImageID("I_STICK_BG");
869
870
auto addPSPButton = [=](int buttonBit, const char *key, ImageID bgImg, ImageID bgDownImg, ImageID img, const ConfigTouchPos &touch, ButtonOffset off = { 0, 0 }) -> PSPButton * {
871
if (touch.show) {
872
return root->Add(new PSPButton(buttonBit, key, bgImg, bgDownImg, img, touch.scale, buttonLayoutParams(touch, off)));
873
}
874
return nullptr;
875
};
876
auto addBoolButton = [=](bool *value, const char *key, ImageID bgImg, ImageID bgDownImg, ImageID img, const ConfigTouchPos &touch) -> BoolButton * {
877
if (touch.show) {
878
return root->Add(new BoolButton(value, key, bgImg, bgDownImg, img, touch.scale, buttonLayoutParams(touch)));
879
}
880
return nullptr;
881
};
882
auto addCustomButton = [=](const ConfigCustomButton& cfg, const char *key, const ConfigTouchPos &touch) -> CustomButton * {
883
using namespace CustomKeyData;
884
if (touch.show) {
885
_dbg_assert_(cfg.shape < ARRAY_SIZE(customKeyShapes));
886
_dbg_assert_(cfg.image < ARRAY_SIZE(customKeyImages));
887
888
// Note: cfg.shape and cfg.image are bounds-checked elsewhere.
889
auto aux = root->Add(new CustomButton(cfg.key, key, cfg.toggle, cfg.repeat, controllMapper,
890
g_Config.iTouchButtonStyle == 0 ? customKeyShapes[cfg.shape].i : customKeyShapes[cfg.shape].l, customKeyShapes[cfg.shape].i,
891
customKeyImages[cfg.image].i, touch.scale, customKeyShapes[cfg.shape].d, buttonLayoutParams(touch)));
892
aux->SetAngle(customKeyImages[cfg.image].r, customKeyShapes[cfg.shape].r);
893
aux->FlipImageH(customKeyShapes[cfg.shape].f);
894
return aux;
895
}
896
return nullptr;
897
};
898
899
if (showPauseButton) {
900
root->Add(new BoolButton(pause, "Pause button", roundImage, ImageID("I_ROUND"), ImageID("I_ARROW"), 1.0f, new AnchorLayoutParams(halfW, 20, NONE, NONE, true)))->SetAngle(90);
901
}
902
903
// touchActionButtonCenter.show will always be true, since that's the default.
904
if (g_Config.bShowTouchCircle)
905
addPSPButton(CTRL_CIRCLE, "Circle button", roundImage, ImageID("I_ROUND"), ImageID("I_CIRCLE"), g_Config.touchActionButtonCenter, circleOffset);
906
if (g_Config.bShowTouchCross)
907
addPSPButton(CTRL_CROSS, "Cross button", roundImage, ImageID("I_ROUND"), ImageID("I_CROSS"), g_Config.touchActionButtonCenter, crossOffset);
908
if (g_Config.bShowTouchTriangle)
909
addPSPButton(CTRL_TRIANGLE, "Triangle button", roundImage, ImageID("I_ROUND"), ImageID("I_TRIANGLE"), g_Config.touchActionButtonCenter, triangleOffset);
910
if (g_Config.bShowTouchSquare)
911
addPSPButton(CTRL_SQUARE, "Square button", roundImage, ImageID("I_ROUND"), ImageID("I_SQUARE"), g_Config.touchActionButtonCenter, squareOffset);
912
913
addPSPButton(CTRL_START, "Start button", rectImage, ImageID("I_RECT"), ImageID("I_START"), g_Config.touchStartKey);
914
addPSPButton(CTRL_SELECT, "Select button", rectImage, ImageID("I_RECT"), ImageID("I_SELECT"), g_Config.touchSelectKey);
915
916
BoolButton *fastForward = addBoolButton(&PSP_CoreParameter().fastForward, "Fast-forward button", rectImage, ImageID("I_RECT"), ImageID("I_ARROW"), g_Config.touchFastForwardKey);
917
if (fastForward) {
918
fastForward->SetAngle(180.0f);
919
fastForward->OnChange.Add([](UI::EventParams &e) {
920
if (e.a && coreState == CORE_STEPPING) {
921
Core_EnableStepping(false);
922
}
923
return UI::EVENT_DONE;
924
});
925
}
926
927
addPSPButton(CTRL_LTRIGGER, "Left shoulder button", shoulderImage, ImageID("I_SHOULDER"), ImageID("I_L"), g_Config.touchLKey);
928
PSPButton *rTrigger = addPSPButton(CTRL_RTRIGGER, "Right shoulder button", shoulderImage, ImageID("I_SHOULDER"), ImageID("I_R"), g_Config.touchRKey);
929
if (rTrigger)
930
rTrigger->FlipImageH(true);
931
932
if (g_Config.touchDpad.show) {
933
const ImageID dirImage = g_Config.iTouchButtonStyle ? ImageID("I_DIR_LINE") : ImageID("I_DIR");
934
root->Add(new PSPDpad(dirImage, "D-pad", ImageID("I_DIR"), ImageID("I_ARROW"), g_Config.touchDpad.scale, g_Config.fDpadSpacing, buttonLayoutParams(g_Config.touchDpad)));
935
}
936
937
if (g_Config.touchAnalogStick.show)
938
root->Add(new PSPStick(stickBg, "Left analog stick", stickImage, ImageID("I_STICK"), 0, g_Config.touchAnalogStick.scale, buttonLayoutParams(g_Config.touchAnalogStick)));
939
940
if (g_Config.touchRightAnalogStick.show) {
941
if (g_Config.bRightAnalogCustom)
942
root->Add(new PSPCustomStick(stickBg, "Right analog stick", stickImage, ImageID("I_STICK"), 1, g_Config.touchRightAnalogStick.scale, buttonLayoutParams(g_Config.touchRightAnalogStick)));
943
else
944
root->Add(new PSPStick(stickBg, "Right analog stick", stickImage, ImageID("I_STICK"), 1, g_Config.touchRightAnalogStick.scale, buttonLayoutParams(g_Config.touchRightAnalogStick)));
945
}
946
947
// Sanitize custom button images, while adding them.
948
for (int i = 0; i < Config::CUSTOM_BUTTON_COUNT; i++) {
949
if (g_Config.CustomButton[i].shape >= ARRAY_SIZE(CustomKeyData::customKeyShapes)) {
950
g_Config.CustomButton[i].shape = 0;
951
}
952
if (g_Config.CustomButton[i].image >= ARRAY_SIZE(CustomKeyData::customKeyImages)) {
953
g_Config.CustomButton[i].image = 0;
954
}
955
956
char temp[64];
957
snprintf(temp, sizeof(temp), "Custom %d button", i + 1);
958
addCustomButton(g_Config.CustomButton[i], temp, g_Config.touchCustom[i]);
959
}
960
961
if (g_Config.bGestureControlEnabled)
962
root->Add(new GestureGamepad(controllMapper));
963
964
return root;
965
}
966
967
bool GestureGamepad::Touch(const TouchInput &input) {
968
if (usedPointerMask & (1 << input.id)) {
969
if (input.id == dragPointerId_)
970
dragPointerId_ = -1;
971
return false;
972
}
973
974
if (input.flags & TOUCH_RELEASE_ALL) {
975
dragPointerId_ = -1;
976
return false;
977
}
978
979
if (input.flags & TOUCH_DOWN) {
980
if (dragPointerId_ == -1) {
981
dragPointerId_ = input.id;
982
lastX_ = input.x;
983
lastY_ = input.y;
984
downX_ = input.x;
985
downY_ = input.y;
986
const float now = time_now_d();
987
if (now - lastTapRelease_ < 0.3f && !haveDoubleTapped_) {
988
if (g_Config.iDoubleTapGesture != 0 )
989
controlMapper_->PSPKey(DEVICE_ID_TOUCH, GestureKey::keyList[g_Config.iDoubleTapGesture-1], KEY_DOWN);
990
haveDoubleTapped_ = true;
991
}
992
993
lastTouchDown_ = now;
994
}
995
}
996
if (input.flags & TOUCH_MOVE) {
997
if (input.id == dragPointerId_) {
998
deltaX_ += input.x - lastX_;
999
deltaY_ += input.y - lastY_;
1000
lastX_ = input.x;
1001
lastY_ = input.y;
1002
1003
if (g_Config.bAnalogGesture) {
1004
const float k = g_Config.fAnalogGestureSensibility * 0.02;
1005
float dx = (input.x - downX_)*g_display.dpi_scale_x * k;
1006
float dy = (input.y - downY_)*g_display.dpi_scale_y * k;
1007
dx = std::min(1.0f, std::max(-1.0f, dx));
1008
dy = std::min(1.0f, std::max(-1.0f, dy));
1009
__CtrlSetAnalogXY(0, dx, -dy);
1010
}
1011
}
1012
}
1013
if (input.flags & TOUCH_UP) {
1014
if (input.id == dragPointerId_) {
1015
dragPointerId_ = -1;
1016
if (time_now_d() - lastTouchDown_ < 0.3f)
1017
lastTapRelease_ = time_now_d();
1018
1019
if (haveDoubleTapped_) {
1020
if (g_Config.iDoubleTapGesture != 0)
1021
controlMapper_->PSPKey(DEVICE_ID_TOUCH, GestureKey::keyList[g_Config.iDoubleTapGesture-1], KEY_UP);
1022
haveDoubleTapped_ = false;
1023
}
1024
1025
if (g_Config.bAnalogGesture)
1026
__CtrlSetAnalogXY(0, 0, 0);
1027
}
1028
}
1029
return true;
1030
}
1031
1032
void GestureGamepad::Draw(UIContext &dc) {
1033
float opacity = g_Config.iTouchButtonOpacity / 100.0;
1034
if (opacity <= 0.0f)
1035
return;
1036
1037
uint32_t colorBg = colorAlpha(GetButtonColor(), opacity);
1038
1039
if (g_Config.bAnalogGesture && dragPointerId_ != -1) {
1040
dc.Draw()->DrawImage(ImageID("I_CIRCLE"), downX_, downY_, 0.7f, colorBg, ALIGN_CENTER);
1041
}
1042
}
1043
1044
void GestureGamepad::Update() {
1045
const float th = 1.0f;
1046
float dx = deltaX_ * g_display.dpi_scale_x * g_Config.fSwipeSensitivity;
1047
float dy = deltaY_ * g_display.dpi_scale_y * g_Config.fSwipeSensitivity;
1048
if (g_Config.iSwipeRight != 0) {
1049
if (dx > th) {
1050
controlMapper_->PSPKey(DEVICE_ID_TOUCH, GestureKey::keyList[g_Config.iSwipeRight-1], KEY_DOWN);
1051
swipeRightReleased_ = false;
1052
} else if (!swipeRightReleased_) {
1053
controlMapper_->PSPKey(DEVICE_ID_TOUCH, GestureKey::keyList[g_Config.iSwipeRight-1], KEY_UP);
1054
swipeRightReleased_ = true;
1055
}
1056
}
1057
if (g_Config.iSwipeLeft != 0) {
1058
if (dx < -th) {
1059
controlMapper_->PSPKey(DEVICE_ID_TOUCH, GestureKey::keyList[g_Config.iSwipeLeft-1], KEY_DOWN);
1060
swipeLeftReleased_ = false;
1061
} else if (!swipeLeftReleased_) {
1062
controlMapper_->PSPKey(DEVICE_ID_TOUCH, GestureKey::keyList[g_Config.iSwipeLeft-1], KEY_UP);
1063
swipeLeftReleased_ = true;
1064
}
1065
}
1066
if (g_Config.iSwipeUp != 0) {
1067
if (dy < -th) {
1068
controlMapper_->PSPKey(DEVICE_ID_TOUCH, GestureKey::keyList[g_Config.iSwipeUp-1], KEY_DOWN);
1069
swipeUpReleased_ = false;
1070
} else if (!swipeUpReleased_) {
1071
controlMapper_->PSPKey(DEVICE_ID_TOUCH, GestureKey::keyList[g_Config.iSwipeUp-1], KEY_UP);
1072
swipeUpReleased_ = true;
1073
}
1074
}
1075
if (g_Config.iSwipeDown != 0) {
1076
if (dy > th) {
1077
controlMapper_->PSPKey(DEVICE_ID_TOUCH, GestureKey::keyList[g_Config.iSwipeDown-1], KEY_DOWN);
1078
swipeDownReleased_ = false;
1079
} else if (!swipeDownReleased_) {
1080
controlMapper_->PSPKey(DEVICE_ID_TOUCH, GestureKey::keyList[g_Config.iSwipeDown-1], KEY_UP);
1081
swipeDownReleased_ = true;
1082
}
1083
}
1084
deltaX_ *= g_Config.fSwipeSmoothing;
1085
deltaY_ *= g_Config.fSwipeSmoothing;
1086
}
1087
1088