summaryrefslogtreecommitdiff
path: root/src/android
diff options
context:
space:
mode:
authorGravatar PabloG022023-06-01 17:49:20 +0200
committerGravatar bunnei2023-06-03 00:06:07 -0700
commita7e0a0d5b10e1a2cd1ba46d7b3014d7b9997fea0 (patch)
tree993acc27cd976cf4c011d81d6eb1b71d7c640d2f /src/android
parentandroid: Don't crash the app when selecting a zip that causes a SecurityExcep... (diff)
downloadyuzu-a7e0a0d5b10e1a2cd1ba46d7b3014d7b9997fea0.tar.gz
yuzu-a7e0a0d5b10e1a2cd1ba46d7b3014d7b9997fea0.tar.xz
yuzu-a7e0a0d5b10e1a2cd1ba46d7b3014d7b9997fea0.zip
Save the position of buttons as a percentage
Diffstat (limited to 'src/android')
-rw-r--r--src/android/app/src/main/java/org/yuzu/yuzu_emu/overlay/InputOverlay.kt216
1 files changed, 136 insertions, 80 deletions
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/overlay/InputOverlay.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/overlay/InputOverlay.kt
index f0b0af9e5..bb20e5207 100644
--- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/overlay/InputOverlay.kt
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/overlay/InputOverlay.kt
@@ -9,6 +9,7 @@ import android.content.SharedPreferences
9import android.content.res.Configuration 9import android.content.res.Configuration
10import android.graphics.Bitmap 10import android.graphics.Bitmap
11import android.graphics.Canvas 11import android.graphics.Canvas
12import android.graphics.Point
12import android.graphics.Rect 13import android.graphics.Rect
13import android.graphics.drawable.Drawable 14import android.graphics.drawable.Drawable
14import android.graphics.drawable.VectorDrawable 15import android.graphics.drawable.VectorDrawable
@@ -343,10 +344,12 @@ class InputOverlay(context: Context, attrs: AttributeSet?) : SurfaceView(context
343 } 344 }
344 345
345 private fun addOverlayControls(orientation: String) { 346 private fun addOverlayControls(orientation: String) {
347 val windowSize = getSafeScreenSize(context)
346 if (preferences.getBoolean(Settings.PREF_BUTTON_TOGGLE_0, true)) { 348 if (preferences.getBoolean(Settings.PREF_BUTTON_TOGGLE_0, true)) {
347 overlayButtons.add( 349 overlayButtons.add(
348 initializeOverlayButton( 350 initializeOverlayButton(
349 context, 351 context,
352 windowSize,
350 R.drawable.facebutton_a, 353 R.drawable.facebutton_a,
351 R.drawable.facebutton_a_depressed, 354 R.drawable.facebutton_a_depressed,
352 ButtonType.BUTTON_A, 355 ButtonType.BUTTON_A,
@@ -358,6 +361,7 @@ class InputOverlay(context: Context, attrs: AttributeSet?) : SurfaceView(context
358 overlayButtons.add( 361 overlayButtons.add(
359 initializeOverlayButton( 362 initializeOverlayButton(
360 context, 363 context,
364 windowSize,
361 R.drawable.facebutton_b, 365 R.drawable.facebutton_b,
362 R.drawable.facebutton_b_depressed, 366 R.drawable.facebutton_b_depressed,
363 ButtonType.BUTTON_B, 367 ButtonType.BUTTON_B,
@@ -369,6 +373,7 @@ class InputOverlay(context: Context, attrs: AttributeSet?) : SurfaceView(context
369 overlayButtons.add( 373 overlayButtons.add(
370 initializeOverlayButton( 374 initializeOverlayButton(
371 context, 375 context,
376 windowSize,
372 R.drawable.facebutton_x, 377 R.drawable.facebutton_x,
373 R.drawable.facebutton_x_depressed, 378 R.drawable.facebutton_x_depressed,
374 ButtonType.BUTTON_X, 379 ButtonType.BUTTON_X,
@@ -380,6 +385,7 @@ class InputOverlay(context: Context, attrs: AttributeSet?) : SurfaceView(context
380 overlayButtons.add( 385 overlayButtons.add(
381 initializeOverlayButton( 386 initializeOverlayButton(
382 context, 387 context,
388 windowSize,
383 R.drawable.facebutton_y, 389 R.drawable.facebutton_y,
384 R.drawable.facebutton_y_depressed, 390 R.drawable.facebutton_y_depressed,
385 ButtonType.BUTTON_Y, 391 ButtonType.BUTTON_Y,
@@ -391,6 +397,7 @@ class InputOverlay(context: Context, attrs: AttributeSet?) : SurfaceView(context
391 overlayButtons.add( 397 overlayButtons.add(
392 initializeOverlayButton( 398 initializeOverlayButton(
393 context, 399 context,
400 windowSize,
394 R.drawable.l_shoulder, 401 R.drawable.l_shoulder,
395 R.drawable.l_shoulder_depressed, 402 R.drawable.l_shoulder_depressed,
396 ButtonType.TRIGGER_L, 403 ButtonType.TRIGGER_L,
@@ -402,6 +409,7 @@ class InputOverlay(context: Context, attrs: AttributeSet?) : SurfaceView(context
402 overlayButtons.add( 409 overlayButtons.add(
403 initializeOverlayButton( 410 initializeOverlayButton(
404 context, 411 context,
412 windowSize,
405 R.drawable.r_shoulder, 413 R.drawable.r_shoulder,
406 R.drawable.r_shoulder_depressed, 414 R.drawable.r_shoulder_depressed,
407 ButtonType.TRIGGER_R, 415 ButtonType.TRIGGER_R,
@@ -413,6 +421,7 @@ class InputOverlay(context: Context, attrs: AttributeSet?) : SurfaceView(context
413 overlayButtons.add( 421 overlayButtons.add(
414 initializeOverlayButton( 422 initializeOverlayButton(
415 context, 423 context,
424 windowSize,
416 R.drawable.zl_trigger, 425 R.drawable.zl_trigger,
417 R.drawable.zl_trigger_depressed, 426 R.drawable.zl_trigger_depressed,
418 ButtonType.TRIGGER_ZL, 427 ButtonType.TRIGGER_ZL,
@@ -424,6 +433,7 @@ class InputOverlay(context: Context, attrs: AttributeSet?) : SurfaceView(context
424 overlayButtons.add( 433 overlayButtons.add(
425 initializeOverlayButton( 434 initializeOverlayButton(
426 context, 435 context,
436 windowSize,
427 R.drawable.zr_trigger, 437 R.drawable.zr_trigger,
428 R.drawable.zr_trigger_depressed, 438 R.drawable.zr_trigger_depressed,
429 ButtonType.TRIGGER_ZR, 439 ButtonType.TRIGGER_ZR,
@@ -435,6 +445,7 @@ class InputOverlay(context: Context, attrs: AttributeSet?) : SurfaceView(context
435 overlayButtons.add( 445 overlayButtons.add(
436 initializeOverlayButton( 446 initializeOverlayButton(
437 context, 447 context,
448 windowSize,
438 R.drawable.facebutton_plus, 449 R.drawable.facebutton_plus,
439 R.drawable.facebutton_plus_depressed, 450 R.drawable.facebutton_plus_depressed,
440 ButtonType.BUTTON_PLUS, 451 ButtonType.BUTTON_PLUS,
@@ -446,6 +457,7 @@ class InputOverlay(context: Context, attrs: AttributeSet?) : SurfaceView(context
446 overlayButtons.add( 457 overlayButtons.add(
447 initializeOverlayButton( 458 initializeOverlayButton(
448 context, 459 context,
460 windowSize,
449 R.drawable.facebutton_minus, 461 R.drawable.facebutton_minus,
450 R.drawable.facebutton_minus_depressed, 462 R.drawable.facebutton_minus_depressed,
451 ButtonType.BUTTON_MINUS, 463 ButtonType.BUTTON_MINUS,
@@ -457,6 +469,7 @@ class InputOverlay(context: Context, attrs: AttributeSet?) : SurfaceView(context
457 overlayDpads.add( 469 overlayDpads.add(
458 initializeOverlayDpad( 470 initializeOverlayDpad(
459 context, 471 context,
472 windowSize,
460 R.drawable.dpad_standard, 473 R.drawable.dpad_standard,
461 R.drawable.dpad_standard_cardinal_depressed, 474 R.drawable.dpad_standard_cardinal_depressed,
462 R.drawable.dpad_standard_diagonal_depressed, 475 R.drawable.dpad_standard_diagonal_depressed,
@@ -468,6 +481,7 @@ class InputOverlay(context: Context, attrs: AttributeSet?) : SurfaceView(context
468 overlayJoysticks.add( 481 overlayJoysticks.add(
469 initializeOverlayJoystick( 482 initializeOverlayJoystick(
470 context, 483 context,
484 windowSize,
471 R.drawable.joystick_range, 485 R.drawable.joystick_range,
472 R.drawable.joystick, 486 R.drawable.joystick,
473 R.drawable.joystick_depressed, 487 R.drawable.joystick_depressed,
@@ -481,6 +495,7 @@ class InputOverlay(context: Context, attrs: AttributeSet?) : SurfaceView(context
481 overlayJoysticks.add( 495 overlayJoysticks.add(
482 initializeOverlayJoystick( 496 initializeOverlayJoystick(
483 context, 497 context,
498 windowSize,
484 R.drawable.joystick_range, 499 R.drawable.joystick_range,
485 R.drawable.joystick, 500 R.drawable.joystick,
486 R.drawable.joystick_depressed, 501 R.drawable.joystick_depressed,
@@ -494,6 +509,7 @@ class InputOverlay(context: Context, attrs: AttributeSet?) : SurfaceView(context
494 overlayButtons.add( 509 overlayButtons.add(
495 initializeOverlayButton( 510 initializeOverlayButton(
496 context, 511 context,
512 windowSize,
497 R.drawable.facebutton_home, 513 R.drawable.facebutton_home,
498 R.drawable.facebutton_home_depressed, 514 R.drawable.facebutton_home_depressed,
499 ButtonType.BUTTON_HOME, 515 ButtonType.BUTTON_HOME,
@@ -505,6 +521,7 @@ class InputOverlay(context: Context, attrs: AttributeSet?) : SurfaceView(context
505 overlayButtons.add( 521 overlayButtons.add(
506 initializeOverlayButton( 522 initializeOverlayButton(
507 context, 523 context,
524 windowSize,
508 R.drawable.facebutton_screenshot, 525 R.drawable.facebutton_screenshot,
509 R.drawable.facebutton_screenshot_depressed, 526 R.drawable.facebutton_screenshot_depressed,
510 ButtonType.BUTTON_CAPTURE, 527 ButtonType.BUTTON_CAPTURE,
@@ -530,9 +547,12 @@ class InputOverlay(context: Context, attrs: AttributeSet?) : SurfaceView(context
530 } 547 }
531 548
532 private fun saveControlPosition(sharedPrefsId: Int, x: Int, y: Int, orientation: String) { 549 private fun saveControlPosition(sharedPrefsId: Int, x: Int, y: Int, orientation: String) {
550 val windowSize = getSafeScreenSize(context)
551 val min = windowSize.first
552 val max = windowSize.second
533 PreferenceManager.getDefaultSharedPreferences(YuzuApplication.appContext).edit() 553 PreferenceManager.getDefaultSharedPreferences(YuzuApplication.appContext).edit()
534 .putFloat("$sharedPrefsId$orientation-X", x.toFloat()) 554 .putFloat("$sharedPrefsId$orientation-X", (x - min.x).toFloat() / max.x)
535 .putFloat("$sharedPrefsId$orientation-Y", y.toFloat()) 555 .putFloat("$sharedPrefsId$orientation-Y", (y - min.y).toFloat() / max.y)
536 .apply() 556 .apply()
537 } 557 }
538 558
@@ -557,170 +577,129 @@ class InputOverlay(context: Context, attrs: AttributeSet?) : SurfaceView(context
557 } 577 }
558 578
559 private fun defaultOverlayLandscape() { 579 private fun defaultOverlayLandscape() {
560 // Get screen size 580 // Each value represents the position of the button in relation to the screen size without insets.
561 val windowMetrics =
562 WindowMetricsCalculator.getOrCreate().computeCurrentWindowMetrics(context as Activity)
563 var maxY = windowMetrics.bounds.height().toFloat()
564 var maxX = windowMetrics.bounds.width().toFloat()
565 var minY = 0
566 var minX = 0
567
568 // If we have API access, calculate the safe area to draw the overlay
569 var cutoutLeft = 0
570 var cutoutBottom = 0
571 val insets = windowInsets.displayCutout
572 if (insets != null && Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
573 maxY =
574 if (insets.boundingRectTop.bottom != 0) insets.boundingRectTop.bottom.toFloat() else maxY
575 maxX =
576 if (insets.boundingRectRight.left != 0) insets.boundingRectRight.left.toFloat() else maxX
577 minX = insets.boundingRectLeft.right - insets.boundingRectLeft.left
578 minY = insets.boundingRectBottom.top - insets.boundingRectBottom.bottom
579
580 cutoutLeft = insets.boundingRectRight.right - insets.boundingRectRight.left
581 cutoutBottom = insets.boundingRectTop.top - insets.boundingRectTop.bottom
582 }
583
584 // This makes sure that if we have an inset on one side of the screen, we mirror it on
585 // the other side. Since removing space from one of the max values messes with the scale,
586 // we also have to account for it using our min values.
587 if (maxX.toInt() != windowMetrics.bounds.width()) minX += cutoutLeft
588 if (maxY.toInt() != windowMetrics.bounds.height()) minY += cutoutBottom
589 if (minX > 0 && maxX.toInt() == windowMetrics.bounds.width()) {
590 maxX -= (minX * 2)
591 } else if (minX > 0) {
592 maxX -= minX
593 }
594 if (minY > 0 && maxY.toInt() == windowMetrics.bounds.height()) {
595 maxY -= (minY * 2)
596 } else if (minY > 0) {
597 maxY -= minY
598 }
599
600 // Each value is a percent from max X/Y stored as an int. Have to bring that value down
601 // to a decimal before multiplying by MAX X/Y.
602 preferences.edit() 581 preferences.edit()
603 .putFloat( 582 .putFloat(
604 ButtonType.BUTTON_A.toString() + "-X", 583 ButtonType.BUTTON_A.toString() + "-X",
605 resources.getInteger(R.integer.SWITCH_BUTTON_A_X).toFloat() / 1000 * maxX + minX 584 resources.getInteger(R.integer.SWITCH_BUTTON_A_X).toFloat() / 1000
606 ) 585 )
607 .putFloat( 586 .putFloat(
608 ButtonType.BUTTON_A.toString() + "-Y", 587 ButtonType.BUTTON_A.toString() + "-Y",
609 resources.getInteger(R.integer.SWITCH_BUTTON_A_Y).toFloat() / 1000 * maxY + minY 588 resources.getInteger(R.integer.SWITCH_BUTTON_A_Y).toFloat() / 1000
610 ) 589 )
611 .putFloat( 590 .putFloat(
612 ButtonType.BUTTON_B.toString() + "-X", 591 ButtonType.BUTTON_B.toString() + "-X",
613 resources.getInteger(R.integer.SWITCH_BUTTON_B_X).toFloat() / 1000 * maxX + minX 592 resources.getInteger(R.integer.SWITCH_BUTTON_B_X).toFloat() / 1000
614 ) 593 )
615 .putFloat( 594 .putFloat(
616 ButtonType.BUTTON_B.toString() + "-Y", 595 ButtonType.BUTTON_B.toString() + "-Y",
617 resources.getInteger(R.integer.SWITCH_BUTTON_B_Y).toFloat() / 1000 * maxY + minY 596 resources.getInteger(R.integer.SWITCH_BUTTON_B_Y).toFloat() / 1000
618 ) 597 )
619 .putFloat( 598 .putFloat(
620 ButtonType.BUTTON_X.toString() + "-X", 599 ButtonType.BUTTON_X.toString() + "-X",
621 resources.getInteger(R.integer.SWITCH_BUTTON_X_X).toFloat() / 1000 * maxX + minX 600 resources.getInteger(R.integer.SWITCH_BUTTON_X_X).toFloat() / 1000
622 ) 601 )
623 .putFloat( 602 .putFloat(
624 ButtonType.BUTTON_X.toString() + "-Y", 603 ButtonType.BUTTON_X.toString() + "-Y",
625 resources.getInteger(R.integer.SWITCH_BUTTON_X_Y).toFloat() / 1000 * maxY + minY 604 resources.getInteger(R.integer.SWITCH_BUTTON_X_Y).toFloat() / 1000
626 ) 605 )
627 .putFloat( 606 .putFloat(
628 ButtonType.BUTTON_Y.toString() + "-X", 607 ButtonType.BUTTON_Y.toString() + "-X",
629 resources.getInteger(R.integer.SWITCH_BUTTON_Y_X).toFloat() / 1000 * maxX + minX 608 resources.getInteger(R.integer.SWITCH_BUTTON_Y_X).toFloat() / 1000
630 ) 609 )
631 .putFloat( 610 .putFloat(
632 ButtonType.BUTTON_Y.toString() + "-Y", 611 ButtonType.BUTTON_Y.toString() + "-Y",
633 resources.getInteger(R.integer.SWITCH_BUTTON_Y_Y).toFloat() / 1000 * maxY + minY 612 resources.getInteger(R.integer.SWITCH_BUTTON_Y_Y).toFloat() / 1000
634 ) 613 )
635 .putFloat( 614 .putFloat(
636 ButtonType.TRIGGER_ZL.toString() + "-X", 615 ButtonType.TRIGGER_ZL.toString() + "-X",
637 resources.getInteger(R.integer.SWITCH_TRIGGER_ZL_X).toFloat() / 1000 * maxX + minX 616 resources.getInteger(R.integer.SWITCH_TRIGGER_ZL_X).toFloat() / 1000
638 ) 617 )
639 .putFloat( 618 .putFloat(
640 ButtonType.TRIGGER_ZL.toString() + "-Y", 619 ButtonType.TRIGGER_ZL.toString() + "-Y",
641 resources.getInteger(R.integer.SWITCH_TRIGGER_ZL_Y).toFloat() / 1000 * maxY + minY 620 resources.getInteger(R.integer.SWITCH_TRIGGER_ZL_Y).toFloat() / 1000
642 ) 621 )
643 .putFloat( 622 .putFloat(
644 ButtonType.TRIGGER_ZR.toString() + "-X", 623 ButtonType.TRIGGER_ZR.toString() + "-X",
645 resources.getInteger(R.integer.SWITCH_TRIGGER_ZR_X).toFloat() / 1000 * maxX + minX 624 resources.getInteger(R.integer.SWITCH_TRIGGER_ZR_X).toFloat() / 1000
646 ) 625 )
647 .putFloat( 626 .putFloat(
648 ButtonType.TRIGGER_ZR.toString() + "-Y", 627 ButtonType.TRIGGER_ZR.toString() + "-Y",
649 resources.getInteger(R.integer.SWITCH_TRIGGER_ZR_Y).toFloat() / 1000 * maxY + minY 628 resources.getInteger(R.integer.SWITCH_TRIGGER_ZR_Y).toFloat() / 1000
650 ) 629 )
651 .putFloat( 630 .putFloat(
652 ButtonType.DPAD_UP.toString() + "-X", 631 ButtonType.DPAD_UP.toString() + "-X",
653 resources.getInteger(R.integer.SWITCH_BUTTON_DPAD_X).toFloat() / 1000 * maxX + minX 632 resources.getInteger(R.integer.SWITCH_BUTTON_DPAD_X).toFloat() / 1000
654 ) 633 )
655 .putFloat( 634 .putFloat(
656 ButtonType.DPAD_UP.toString() + "-Y", 635 ButtonType.DPAD_UP.toString() + "-Y",
657 resources.getInteger(R.integer.SWITCH_BUTTON_DPAD_Y).toFloat() / 1000 * maxY + minY 636 resources.getInteger(R.integer.SWITCH_BUTTON_DPAD_Y).toFloat() / 1000
658 ) 637 )
659 .putFloat( 638 .putFloat(
660 ButtonType.TRIGGER_L.toString() + "-X", 639 ButtonType.TRIGGER_L.toString() + "-X",
661 resources.getInteger(R.integer.SWITCH_TRIGGER_L_X).toFloat() / 1000 * maxX + minX 640 resources.getInteger(R.integer.SWITCH_TRIGGER_L_X).toFloat() / 1000
662 ) 641 )
663 .putFloat( 642 .putFloat(
664 ButtonType.TRIGGER_L.toString() + "-Y", 643 ButtonType.TRIGGER_L.toString() + "-Y",
665 resources.getInteger(R.integer.SWITCH_TRIGGER_L_Y).toFloat() / 1000 * maxY + minY 644 resources.getInteger(R.integer.SWITCH_TRIGGER_L_Y).toFloat() / 1000
666 ) 645 )
667 .putFloat( 646 .putFloat(
668 ButtonType.TRIGGER_R.toString() + "-X", 647 ButtonType.TRIGGER_R.toString() + "-X",
669 resources.getInteger(R.integer.SWITCH_TRIGGER_R_X).toFloat() / 1000 * maxX + minX 648 resources.getInteger(R.integer.SWITCH_TRIGGER_R_X).toFloat() / 1000
670 ) 649 )
671 .putFloat( 650 .putFloat(
672 ButtonType.TRIGGER_R.toString() + "-Y", 651 ButtonType.TRIGGER_R.toString() + "-Y",
673 resources.getInteger(R.integer.SWITCH_TRIGGER_R_Y).toFloat() / 1000 * maxY + minY 652 resources.getInteger(R.integer.SWITCH_TRIGGER_R_Y).toFloat() / 1000
674 ) 653 )
675 .putFloat( 654 .putFloat(
676 ButtonType.BUTTON_PLUS.toString() + "-X", 655 ButtonType.BUTTON_PLUS.toString() + "-X",
677 resources.getInteger(R.integer.SWITCH_BUTTON_PLUS_X).toFloat() / 1000 * maxX + minX 656 resources.getInteger(R.integer.SWITCH_BUTTON_PLUS_X).toFloat() / 1000
678 ) 657 )
679 .putFloat( 658 .putFloat(
680 ButtonType.BUTTON_PLUS.toString() + "-Y", 659 ButtonType.BUTTON_PLUS.toString() + "-Y",
681 resources.getInteger(R.integer.SWITCH_BUTTON_PLUS_Y).toFloat() / 1000 * maxY + minY 660 resources.getInteger(R.integer.SWITCH_BUTTON_PLUS_Y).toFloat() / 1000
682 ) 661 )
683 .putFloat( 662 .putFloat(
684 ButtonType.BUTTON_MINUS.toString() + "-X", 663 ButtonType.BUTTON_MINUS.toString() + "-X",
685 resources.getInteger(R.integer.SWITCH_BUTTON_MINUS_X).toFloat() / 1000 * maxX + minX 664 resources.getInteger(R.integer.SWITCH_BUTTON_MINUS_X).toFloat() / 1000
686 ) 665 )
687 .putFloat( 666 .putFloat(
688 ButtonType.BUTTON_MINUS.toString() + "-Y", 667 ButtonType.BUTTON_MINUS.toString() + "-Y",
689 resources.getInteger(R.integer.SWITCH_BUTTON_MINUS_Y).toFloat() / 1000 * maxY + minY 668 resources.getInteger(R.integer.SWITCH_BUTTON_MINUS_Y).toFloat() / 1000
690 ) 669 )
691 .putFloat( 670 .putFloat(
692 ButtonType.BUTTON_HOME.toString() + "-X", 671 ButtonType.BUTTON_HOME.toString() + "-X",
693 resources.getInteger(R.integer.SWITCH_BUTTON_HOME_X).toFloat() / 1000 * maxX + minX 672 resources.getInteger(R.integer.SWITCH_BUTTON_HOME_X).toFloat() / 1000
694 ) 673 )
695 .putFloat( 674 .putFloat(
696 ButtonType.BUTTON_HOME.toString() + "-Y", 675 ButtonType.BUTTON_HOME.toString() + "-Y",
697 resources.getInteger(R.integer.SWITCH_BUTTON_HOME_Y).toFloat() / 1000 * maxY + minY 676 resources.getInteger(R.integer.SWITCH_BUTTON_HOME_Y).toFloat() / 1000
698 ) 677 )
699 .putFloat( 678 .putFloat(
700 ButtonType.BUTTON_CAPTURE.toString() + "-X", 679 ButtonType.BUTTON_CAPTURE.toString() + "-X",
701 resources.getInteger(R.integer.SWITCH_BUTTON_CAPTURE_X) 680 resources.getInteger(R.integer.SWITCH_BUTTON_CAPTURE_X)
702 .toFloat() / 1000 * maxX + minX 681 .toFloat() / 1000
703 ) 682 )
704 .putFloat( 683 .putFloat(
705 ButtonType.BUTTON_CAPTURE.toString() + "-Y", 684 ButtonType.BUTTON_CAPTURE.toString() + "-Y",
706 resources.getInteger(R.integer.SWITCH_BUTTON_CAPTURE_Y) 685 resources.getInteger(R.integer.SWITCH_BUTTON_CAPTURE_Y)
707 .toFloat() / 1000 * maxY + minY 686 .toFloat() / 1000
708 ) 687 )
709 .putFloat( 688 .putFloat(
710 ButtonType.STICK_R.toString() + "-X", 689 ButtonType.STICK_R.toString() + "-X",
711 resources.getInteger(R.integer.SWITCH_STICK_R_X).toFloat() / 1000 * maxX + minX 690 resources.getInteger(R.integer.SWITCH_STICK_R_X).toFloat() / 1000
712 ) 691 )
713 .putFloat( 692 .putFloat(
714 ButtonType.STICK_R.toString() + "-Y", 693 ButtonType.STICK_R.toString() + "-Y",
715 resources.getInteger(R.integer.SWITCH_STICK_R_Y).toFloat() / 1000 * maxY + minY 694 resources.getInteger(R.integer.SWITCH_STICK_R_Y).toFloat() / 1000
716 ) 695 )
717 .putFloat( 696 .putFloat(
718 ButtonType.STICK_L.toString() + "-X", 697 ButtonType.STICK_L.toString() + "-X",
719 resources.getInteger(R.integer.SWITCH_STICK_L_X).toFloat() / 1000 * maxX + minX 698 resources.getInteger(R.integer.SWITCH_STICK_L_X).toFloat() / 1000
720 ) 699 )
721 .putFloat( 700 .putFloat(
722 ButtonType.STICK_L.toString() + "-Y", 701 ButtonType.STICK_L.toString() + "-Y",
723 resources.getInteger(R.integer.SWITCH_STICK_L_Y).toFloat() / 1000 * maxY + minY 702 resources.getInteger(R.integer.SWITCH_STICK_L_Y).toFloat() / 1000
724 ) 703 )
725 .apply() 704 .apply()
726 } 705 }
@@ -767,6 +746,59 @@ class InputOverlay(context: Context, attrs: AttributeSet?) : SurfaceView(context
767 } 746 }
768 747
769 /** 748 /**
749 * Gets the safe screen size for drawing the overlay
750 *
751 * @param context Context for getting the window metrics
752 * @return A pair of points, the first being the top left corner of the safe area,
753 * the second being the bottom right corner of the safe area
754 */
755 private fun getSafeScreenSize(context: Context): Pair<Point, Point> {
756 // Get screen size
757 val windowMetrics =
758 WindowMetricsCalculator.getOrCreate()
759 .computeCurrentWindowMetrics(context as Activity)
760 var maxY = windowMetrics.bounds.height().toFloat()
761 var maxX = windowMetrics.bounds.width().toFloat()
762 var minY = 0
763 var minX = 0
764
765 // If we have API access, calculate the safe area to draw the overlay
766 var cutoutLeft = 0
767 var cutoutBottom = 0
768 val insets = context.windowManager.currentWindowMetrics.windowInsets.displayCutout
769 if (insets != null && Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
770 maxY =
771 if (insets.boundingRectTop.bottom != 0) insets.boundingRectTop.bottom.toFloat() else maxY
772 maxX =
773 if (insets.boundingRectRight.left != 0) insets.boundingRectRight.left.toFloat() else maxX
774 minX = insets.boundingRectLeft.right - insets.boundingRectLeft.left
775 minY = insets.boundingRectBottom.top - insets.boundingRectBottom.bottom
776
777 cutoutLeft = insets.boundingRectRight.right - insets.boundingRectRight.left
778 cutoutBottom = insets.boundingRectTop.top - insets.boundingRectTop.bottom
779 }
780
781
782 // This makes sure that if we have an inset on one side of the screen, we mirror it on
783 // the other side. Since removing space from one of the max values messes with the scale,
784 // we also have to account for it using our min values.
785 if (maxX.toInt() != windowMetrics.bounds.width()) minX += cutoutLeft
786 if (maxY.toInt() != windowMetrics.bounds.height()) minY += cutoutBottom
787 if (minX > 0 && maxX.toInt() == windowMetrics.bounds.width()) {
788 maxX -= (minX * 2)
789 } else if (minX > 0) {
790 maxX -= minX
791 }
792 if (minY > 0 && maxY.toInt() == windowMetrics.bounds.height()) {
793 maxY -= (minY * 2)
794 } else if (minY > 0) {
795 maxY -= minY
796 }
797
798 return Pair(Point(minX, minY), Point(maxX.toInt(), maxY.toInt()))
799 }
800
801 /**
770 * Initializes an InputOverlayDrawableButton, given by resId, with all of the 802 * Initializes an InputOverlayDrawableButton, given by resId, with all of the
771 * parameters set for it to be properly shown on the InputOverlay. 803 * parameters set for it to be properly shown on the InputOverlay.
772 * 804 *
@@ -795,6 +827,7 @@ class InputOverlay(context: Context, attrs: AttributeSet?) : SurfaceView(context
795 * for Android to call the onDraw method. 827 * for Android to call the onDraw method.
796 * 828 *
797 * @param context The current [Context]. 829 * @param context The current [Context].
830 * @param windowSize The size of the window to draw the overlay on.
798 * @param defaultResId The resource ID of the [Drawable] to get the [Bitmap] of (Default State). 831 * @param defaultResId The resource ID of the [Drawable] to get the [Bitmap] of (Default State).
799 * @param pressedResId The resource ID of the [Drawable] to get the [Bitmap] of (Pressed State). 832 * @param pressedResId The resource ID of the [Drawable] to get the [Bitmap] of (Pressed State).
800 * @param buttonId Identifier for determining what type of button the initialized InputOverlayDrawableButton represents. 833 * @param buttonId Identifier for determining what type of button the initialized InputOverlayDrawableButton represents.
@@ -802,6 +835,7 @@ class InputOverlay(context: Context, attrs: AttributeSet?) : SurfaceView(context
802 */ 835 */
803 private fun initializeOverlayButton( 836 private fun initializeOverlayButton(
804 context: Context, 837 context: Context,
838 windowSize: Pair<Point, Point>,
805 defaultResId: Int, 839 defaultResId: Int,
806 pressedResId: Int, 840 pressedResId: Int,
807 buttonId: Int, 841 buttonId: Int,
@@ -836,12 +870,18 @@ class InputOverlay(context: Context, attrs: AttributeSet?) : SurfaceView(context
836 val overlayDrawable = 870 val overlayDrawable =
837 InputOverlayDrawableButton(res, defaultStateBitmap, pressedStateBitmap, buttonId) 871 InputOverlayDrawableButton(res, defaultStateBitmap, pressedStateBitmap, buttonId)
838 872
873 // Get the minimum and maximum coordinates of the screen where the button can be placed.
874 val min = windowSize.first
875 val max = windowSize.second
876
839 // The X and Y coordinates of the InputOverlayDrawableButton on the InputOverlay. 877 // The X and Y coordinates of the InputOverlayDrawableButton on the InputOverlay.
840 // These were set in the input overlay configuration menu. 878 // These were set in the input overlay configuration menu.
841 val xKey = "$buttonId$orientation-X" 879 val xKey = "$buttonId$orientation-X"
842 val yKey = "$buttonId$orientation-Y" 880 val yKey = "$buttonId$orientation-Y"
843 val drawableX = sPrefs.getFloat(xKey, 0f).toInt() 881 val drawableXPercent = sPrefs.getFloat(xKey, 0f)
844 val drawableY = sPrefs.getFloat(yKey, 0f).toInt() 882 val drawableYPercent = sPrefs.getFloat(yKey, 0f)
883 val drawableX = (drawableXPercent * max.x + min.x).toInt()
884 val drawableY = (drawableYPercent * max.y + min.y).toInt()
845 val width = overlayDrawable.width 885 val width = overlayDrawable.width
846 val height = overlayDrawable.height 886 val height = overlayDrawable.height
847 887
@@ -866,6 +906,7 @@ class InputOverlay(context: Context, attrs: AttributeSet?) : SurfaceView(context
866 * Initializes an [InputOverlayDrawableDpad] 906 * Initializes an [InputOverlayDrawableDpad]
867 * 907 *
868 * @param context The current [Context]. 908 * @param context The current [Context].
909 * @param windowSize The size of the window to draw the overlay on.
869 * @param defaultResId The [Bitmap] resource ID of the default state. 910 * @param defaultResId The [Bitmap] resource ID of the default state.
870 * @param pressedOneDirectionResId The [Bitmap] resource ID of the pressed state in one direction. 911 * @param pressedOneDirectionResId The [Bitmap] resource ID of the pressed state in one direction.
871 * @param pressedTwoDirectionsResId The [Bitmap] resource ID of the pressed state in two directions. 912 * @param pressedTwoDirectionsResId The [Bitmap] resource ID of the pressed state in two directions.
@@ -873,6 +914,7 @@ class InputOverlay(context: Context, attrs: AttributeSet?) : SurfaceView(context
873 */ 914 */
874 private fun initializeOverlayDpad( 915 private fun initializeOverlayDpad(
875 context: Context, 916 context: Context,
917 windowSize: Pair<Point, Point>,
876 defaultResId: Int, 918 defaultResId: Int,
877 pressedOneDirectionResId: Int, 919 pressedOneDirectionResId: Int,
878 pressedTwoDirectionsResId: Int, 920 pressedTwoDirectionsResId: Int,
@@ -907,10 +949,16 @@ class InputOverlay(context: Context, attrs: AttributeSet?) : SurfaceView(context
907 ButtonType.DPAD_RIGHT 949 ButtonType.DPAD_RIGHT
908 ) 950 )
909 951
952 // Get the minimum and maximum coordinates of the screen where the button can be placed.
953 val min = windowSize.first
954 val max = windowSize.second
955
910 // The X and Y coordinates of the InputOverlayDrawableDpad on the InputOverlay. 956 // The X and Y coordinates of the InputOverlayDrawableDpad on the InputOverlay.
911 // These were set in the input overlay configuration menu. 957 // These were set in the input overlay configuration menu.
912 val drawableX = sPrefs.getFloat("${ButtonType.DPAD_UP}$orientation-X", 0f).toInt() 958 val drawableXPercent = sPrefs.getFloat("${ButtonType.DPAD_UP}$orientation-X", 0f)
913 val drawableY = sPrefs.getFloat("${ButtonType.DPAD_UP}$orientation-Y", 0f).toInt() 959 val drawableYPercent = sPrefs.getFloat("${ButtonType.DPAD_UP}$orientation-Y", 0f)
960 val drawableX = (drawableXPercent * max.x + min.x).toInt()
961 val drawableY = (drawableYPercent * max.y + min.y).toInt()
914 val width = overlayDrawable.width 962 val width = overlayDrawable.width
915 val height = overlayDrawable.height 963 val height = overlayDrawable.height
916 964
@@ -932,6 +980,7 @@ class InputOverlay(context: Context, attrs: AttributeSet?) : SurfaceView(context
932 * Initializes an [InputOverlayDrawableJoystick] 980 * Initializes an [InputOverlayDrawableJoystick]
933 * 981 *
934 * @param context The current [Context] 982 * @param context The current [Context]
983 * @param windowSize The size of the window to draw the overlay on.
935 * @param resOuter Resource ID for the outer image of the joystick (the static image that shows the circular bounds). 984 * @param resOuter Resource ID for the outer image of the joystick (the static image that shows the circular bounds).
936 * @param defaultResInner Resource ID for the default inner image of the joystick (the one you actually move around). 985 * @param defaultResInner Resource ID for the default inner image of the joystick (the one you actually move around).
937 * @param pressedResInner Resource ID for the pressed inner image of the joystick. 986 * @param pressedResInner Resource ID for the pressed inner image of the joystick.
@@ -941,6 +990,7 @@ class InputOverlay(context: Context, attrs: AttributeSet?) : SurfaceView(context
941 */ 990 */
942 private fun initializeOverlayJoystick( 991 private fun initializeOverlayJoystick(
943 context: Context, 992 context: Context,
993 windowSize: Pair<Point, Point>,
944 resOuter: Int, 994 resOuter: Int,
945 defaultResInner: Int, 995 defaultResInner: Int,
946 pressedResInner: Int, 996 pressedResInner: Int,
@@ -964,10 +1014,16 @@ class InputOverlay(context: Context, attrs: AttributeSet?) : SurfaceView(context
964 val bitmapInnerDefault = getBitmap(context, defaultResInner, 1.0f) 1014 val bitmapInnerDefault = getBitmap(context, defaultResInner, 1.0f)
965 val bitmapInnerPressed = getBitmap(context, pressedResInner, 1.0f) 1015 val bitmapInnerPressed = getBitmap(context, pressedResInner, 1.0f)
966 1016
1017 // Get the minimum and maximum coordinates of the screen where the button can be placed.
1018 val min = windowSize.first
1019 val max = windowSize.second
1020
967 // The X and Y coordinates of the InputOverlayDrawableButton on the InputOverlay. 1021 // The X and Y coordinates of the InputOverlayDrawableButton on the InputOverlay.
968 // These were set in the input overlay configuration menu. 1022 // These were set in the input overlay configuration menu.
969 val drawableX = sPrefs.getFloat("$button$orientation-X", 0f).toInt() 1023 val drawableXPercent = sPrefs.getFloat("$button$orientation-X", 0f)
970 val drawableY = sPrefs.getFloat("$button$orientation-Y", 0f).toInt() 1024 val drawableYPercent = sPrefs.getFloat("$button$orientation-Y", 0f)
1025 val drawableX = (drawableXPercent * max.x + min.x).toInt()
1026 val drawableY = (drawableYPercent * max.y + min.y).toInt()
971 val outerScale = 1.66f 1027 val outerScale = 1.66f
972 1028
973 // Now set the bounds for the InputOverlayDrawableJoystick. 1029 // Now set the bounds for the InputOverlayDrawableJoystick.