From 606673aefef303364166058f751ff31bb7271032 Mon Sep 17 00:00:00 2001 From: Filippo Scognamiglio Date: Sat, 7 Sep 2019 18:19:30 +0200 Subject: [PATCH 1/5] First implementation of touch inputs, currently attached to GameActivity. --- buildSrc/src/main/java/deps.kt | 2 + retrograde-app-tv/build.gradle.kts | 3 + .../app/feature/game/GameActivity.kt | 39 +++- .../src/main/res/values/keys.xml | 1 + .../src/main/res/values/strings.xml | 1 + retrograde-app-tv/src/main/res/xml/prefs.xml | 3 + retrograde-touchinput/build.gradle.kts | 22 ++ .../src/main/AndroidManifest.xml | 1 + .../swordfish/touchinput/data/ButtonEvent.kt | 3 + .../touchinput/data/EventsTransformers.kt | 45 ++++ .../com/swordfish/touchinput/data/PadEvent.kt | 3 + .../interfaces/ButtonEventsSource.kt | 8 + .../touchinput/pads/GameBoyAdvancePad.kt | 67 ++++++ .../swordfish/touchinput/pads/GameBoyPad.kt | 55 +++++ .../touchinput/pads/GamePadFactory.kt | 19 ++ .../swordfish/touchinput/pads/GamePadView.kt | 16 ++ .../touchinput/utils/ControllerUtils.kt | 5 + .../touchinput/views/ActionButtons.kt | 185 ++++++++++++++++ .../touchinput/views/DirectionPad.kt | 198 ++++++++++++++++++ .../touchinput/views/LargeSingleButton.kt | 16 ++ .../touchinput/views/SmallSingleButton.kt | 16 ++ .../touchinput/views/base/BaseSingleButton.kt | 39 ++++ .../src/main/res/drawable/action_normal.xml | 5 + .../src/main/res/drawable/action_pressed.xml | 5 + .../res/drawable/direction_down_normal.xml | 12 ++ .../res/drawable/direction_down_pressed.xml | 11 + .../res/drawable/direction_left_normal.xml | 12 ++ .../res/drawable/direction_left_pressed.xml | 11 + .../res/drawable/direction_right_normal.xml | 12 ++ .../res/drawable/direction_right_pressed.xml | 11 + .../main/res/drawable/direction_up_normal.xml | 12 ++ .../res/drawable/direction_up_pressed.xml | 11 + .../main/res/drawable/large_button_normal.xml | 5 + .../res/drawable/large_button_pressed.xml | 5 + .../res/drawable/large_button_selector.xml | 5 + .../main/res/drawable/small_button_normal.xml | 5 + .../res/drawable/small_button_pressed.xml | 5 + .../res/drawable/small_button_selector.xml | 5 + .../src/main/res/layout/layout_gb.xml | 44 ++++ .../src/main/res/layout/layout_gba.xml | 64 ++++++ .../src/main/res/values/colors.xml | 4 + .../src/main/res/values/default_styles.xml | 29 +++ .../src/main/res/values/dimen.xml | 21 ++ .../src/main/res/values/input_attrs.xml | 16 ++ .../src/main/res/values/strings.xml | 6 + settings.gradle.kts | 3 +- 46 files changed, 1062 insertions(+), 4 deletions(-) create mode 100644 retrograde-touchinput/build.gradle.kts create mode 100644 retrograde-touchinput/src/main/AndroidManifest.xml create mode 100644 retrograde-touchinput/src/main/java/com/swordfish/touchinput/data/ButtonEvent.kt create mode 100644 retrograde-touchinput/src/main/java/com/swordfish/touchinput/data/EventsTransformers.kt create mode 100644 retrograde-touchinput/src/main/java/com/swordfish/touchinput/data/PadEvent.kt create mode 100644 retrograde-touchinput/src/main/java/com/swordfish/touchinput/interfaces/ButtonEventsSource.kt create mode 100644 retrograde-touchinput/src/main/java/com/swordfish/touchinput/pads/GameBoyAdvancePad.kt create mode 100644 retrograde-touchinput/src/main/java/com/swordfish/touchinput/pads/GameBoyPad.kt create mode 100644 retrograde-touchinput/src/main/java/com/swordfish/touchinput/pads/GamePadFactory.kt create mode 100644 retrograde-touchinput/src/main/java/com/swordfish/touchinput/pads/GamePadView.kt create mode 100644 retrograde-touchinput/src/main/java/com/swordfish/touchinput/utils/ControllerUtils.kt create mode 100644 retrograde-touchinput/src/main/java/com/swordfish/touchinput/views/ActionButtons.kt create mode 100644 retrograde-touchinput/src/main/java/com/swordfish/touchinput/views/DirectionPad.kt create mode 100644 retrograde-touchinput/src/main/java/com/swordfish/touchinput/views/LargeSingleButton.kt create mode 100644 retrograde-touchinput/src/main/java/com/swordfish/touchinput/views/SmallSingleButton.kt create mode 100644 retrograde-touchinput/src/main/java/com/swordfish/touchinput/views/base/BaseSingleButton.kt create mode 100644 retrograde-touchinput/src/main/res/drawable/action_normal.xml create mode 100644 retrograde-touchinput/src/main/res/drawable/action_pressed.xml create mode 100644 retrograde-touchinput/src/main/res/drawable/direction_down_normal.xml create mode 100644 retrograde-touchinput/src/main/res/drawable/direction_down_pressed.xml create mode 100644 retrograde-touchinput/src/main/res/drawable/direction_left_normal.xml create mode 100644 retrograde-touchinput/src/main/res/drawable/direction_left_pressed.xml create mode 100644 retrograde-touchinput/src/main/res/drawable/direction_right_normal.xml create mode 100644 retrograde-touchinput/src/main/res/drawable/direction_right_pressed.xml create mode 100644 retrograde-touchinput/src/main/res/drawable/direction_up_normal.xml create mode 100644 retrograde-touchinput/src/main/res/drawable/direction_up_pressed.xml create mode 100644 retrograde-touchinput/src/main/res/drawable/large_button_normal.xml create mode 100644 retrograde-touchinput/src/main/res/drawable/large_button_pressed.xml create mode 100644 retrograde-touchinput/src/main/res/drawable/large_button_selector.xml create mode 100644 retrograde-touchinput/src/main/res/drawable/small_button_normal.xml create mode 100644 retrograde-touchinput/src/main/res/drawable/small_button_pressed.xml create mode 100644 retrograde-touchinput/src/main/res/drawable/small_button_selector.xml create mode 100644 retrograde-touchinput/src/main/res/layout/layout_gb.xml create mode 100644 retrograde-touchinput/src/main/res/layout/layout_gba.xml create mode 100644 retrograde-touchinput/src/main/res/values/colors.xml create mode 100644 retrograde-touchinput/src/main/res/values/default_styles.xml create mode 100644 retrograde-touchinput/src/main/res/values/dimen.xml create mode 100644 retrograde-touchinput/src/main/res/values/input_attrs.xml create mode 100644 retrograde-touchinput/src/main/res/values/strings.xml diff --git a/buildSrc/src/main/java/deps.kt b/buildSrc/src/main/java/deps.kt index 5cecd9d3..18856e86 100644 --- a/buildSrc/src/main/java/deps.kt +++ b/buildSrc/src/main/java/deps.kt @@ -57,11 +57,13 @@ object deps { } } object support { + const val supportCompat = "com.android.support:support-compat:${versions.support}" const val appCompatV7 = "com.android.support:appcompat-v7:${versions.support}" const val leanbackV17 = "com.android.support:leanback-v17:${versions.support}" const val paletteV7 = "com.android.support:palette-v7:${versions.support}" const val prefLeanbackV17 = "com.android.support:preference-leanback-v17:${versions.support}" const val recyclerViewV7 = "com.android.support:recyclerview-v7:${versions.support}" + const val constraintLayout = "com.android.support.constraint:constraint-layout:1.1.3" } const val bugsnagAndroid = "com.bugsnag:bugsnag-android:4.9.2" const val bugsnagAndroidNdk = "com.bugsnag:bugsnag-android-ndk:4.9.2" diff --git a/retrograde-app-tv/build.gradle.kts b/retrograde-app-tv/build.gradle.kts index 9adcdb4d..85f01c01 100644 --- a/retrograde-app-tv/build.gradle.kts +++ b/retrograde-app-tv/build.gradle.kts @@ -43,6 +43,9 @@ dependencies { implementation(project(":retrograde-storage-webdav")) implementation(project(":retrograde-storage-archiveorg")) + // TODO... This dependency will be gone when the separate mobile application is created. + implementation(project(":retrograde-touchinput")) + implementation(deps.libs.arch.paging) implementation(deps.libs.arch.room.runtime) implementation(deps.libs.arch.work.runtime) diff --git a/retrograde-app-tv/src/main/java/com/codebutler/retrograde/app/feature/game/GameActivity.kt b/retrograde-app-tv/src/main/java/com/codebutler/retrograde/app/feature/game/GameActivity.kt index 3daba93c..495ea48b 100644 --- a/retrograde-app-tv/src/main/java/com/codebutler/retrograde/app/feature/game/GameActivity.kt +++ b/retrograde-app-tv/src/main/java/com/codebutler/retrograde/app/feature/game/GameActivity.kt @@ -24,9 +24,7 @@ import android.content.Intent import android.graphics.Color import android.os.Bundle import android.preference.PreferenceManager -import android.view.KeyEvent -import android.view.MotionEvent -import android.view.View +import android.view.* import android.view.ViewGroup.LayoutParams.MATCH_PARENT import android.widget.FrameLayout import android.widget.ProgressBar @@ -48,6 +46,7 @@ import com.codebutler.retrograde.lib.util.subscribeBy import com.gojuno.koptional.None import com.gojuno.koptional.Some import com.gojuno.koptional.toOptional +import com.swordfish.touchinput.pads.GamePadFactory import com.uber.autodispose.android.lifecycle.scope import com.uber.autodispose.kotlin.autoDisposable import io.reactivex.android.schedulers.AndroidSchedulers @@ -73,12 +72,15 @@ class GameActivity : RetrogradeActivity() { private var game: Game? = null private var retroDroid: RetroDroid? = null + private var displayTouchInput: Boolean = false + override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_game) val prefs = PreferenceManager.getDefaultSharedPreferences(this) val enableOpengl = prefs.getBoolean(getString(R.string.pref_key_flags_opengl), false) + displayTouchInput = prefs.getBoolean(getString(R.string.pref_key_flags_touchinput), false) gameDisplay = if (enableOpengl) { GlGameDisplay(this) @@ -116,6 +118,33 @@ class GameActivity : RetrogradeActivity() { } } + private fun setupTouchInput(game: Game) { + val frameLayout = findViewById(R.id.game_layout) + + val gameView = when (game.systemId) { + in listOf("snes", "gba") -> GamePadFactory.getGamePadView(this, GamePadFactory.Layout.SNES) + in listOf("nes", "gb", "gbc") -> GamePadFactory.getGamePadView(this, GamePadFactory.Layout.NES) + else -> null + } + + if (gameView != null) { + frameLayout.addView(gameView) + + gameView.getEvents() + .doOnNext { + if (it.action == KeyEvent.ACTION_DOWN) { + performHapticFeedback(gameView) + } + }.autoDisposable(scope()) + .subscribe { gameInput.onKeyEvent(KeyEvent(it.action, it.keycode)) } + } + } + + private fun performHapticFeedback(view: View) { + val flags = HapticFeedbackConstants.FLAG_IGNORE_VIEW_SETTING or HapticFeedbackConstants.FLAG_IGNORE_GLOBAL_SETTING + view.performHapticFeedback(HapticFeedbackConstants.KEYBOARD_TAP, flags) + } + override fun onDestroy() { super.onDestroy() // This activity runs in its own process which should not live beyond the activity lifecycle. @@ -161,6 +190,10 @@ class GameActivity : RetrogradeActivity() { val retroDroid = RetroDroid(gameDisplay, GameAudio(), gameInput, this, data.coreFile) lifecycle.addObserver(retroDroid) + if (displayTouchInput) { + setupTouchInput(data.game) + } + retroDroid.gameUnloaded .map { optionalSaveData -> if (optionalSaveData is Some) { diff --git a/retrograde-app-tv/src/main/res/values/keys.xml b/retrograde-app-tv/src/main/res/values/keys.xml index fc562600..0aad48da 100644 --- a/retrograde-app-tv/src/main/res/values/keys.xml +++ b/retrograde-app-tv/src/main/res/values/keys.xml @@ -5,6 +5,7 @@ flags flags.debug_logging flags.opengl_rendering + flags.enable_touchinputs sources licenses version diff --git a/retrograde-app-tv/src/main/res/values/strings.xml b/retrograde-app-tv/src/main/res/values/strings.xml index 2500b68c..ed6c7ded 100644 --- a/retrograde-app-tv/src/main/res/values/strings.xml +++ b/retrograde-app-tv/src/main/res/values/strings.xml @@ -19,6 +19,7 @@ Retro gaming for Android TV Welcome to Retrograde OpenGL Rendering + Display Touch Inputs Play Recently Played Remove from Favorites diff --git a/retrograde-app-tv/src/main/res/xml/prefs.xml b/retrograde-app-tv/src/main/res/xml/prefs.xml index 10ff078e..6062dbc5 100644 --- a/retrograde-app-tv/src/main/res/xml/prefs.xml +++ b/retrograde-app-tv/src/main/res/xml/prefs.xml @@ -18,6 +18,9 @@ + diff --git a/retrograde-touchinput/src/main/java/com/swordfish/touchinput/data/ButtonEvent.kt b/retrograde-touchinput/src/main/java/com/swordfish/touchinput/data/ButtonEvent.kt new file mode 100644 index 00000000..3a78712f --- /dev/null +++ b/retrograde-touchinput/src/main/java/com/swordfish/touchinput/data/ButtonEvent.kt @@ -0,0 +1,3 @@ +package com.swordfish.touchinput.data + +data class ButtonEvent(val action: Int, val index: Int) \ No newline at end of file diff --git a/retrograde-touchinput/src/main/java/com/swordfish/touchinput/data/EventsTransformers.kt b/retrograde-touchinput/src/main/java/com/swordfish/touchinput/data/EventsTransformers.kt new file mode 100644 index 00000000..4c1e8990 --- /dev/null +++ b/retrograde-touchinput/src/main/java/com/swordfish/touchinput/data/EventsTransformers.kt @@ -0,0 +1,45 @@ +package com.swordfish.touchinput.data + +import android.view.KeyEvent +import com.swordfish.touchinput.utils.observableOf +import com.swordfish.touchinput.views.DirectionPad +import io.reactivex.Observable +import io.reactivex.ObservableTransformer +import java.security.InvalidParameterException + +internal object EventsTransformers { + fun actionButtonsMap(vararg keycodes: Int): ObservableTransformer { + return ObservableTransformer { upstream -> + upstream.map { PadEvent(it.action, keycodes[it.index]) } + } + } + + fun singleButtonMap(keycode: Int): ObservableTransformer { + return ObservableTransformer { upstream -> + upstream.map { PadEvent(it.action, keycode) } + } + } + + + fun directionPadMap(): ObservableTransformer { + return ObservableTransformer { upstream -> + upstream.flatMap { buttonEvent -> + mapDirectionToKey(buttonEvent.index).map { PadEvent(buttonEvent.action, it) } + } + } + } + + private fun mapDirectionToKey(index: Int): Observable { + return when (index) { + DirectionPad.BUTTON_LEFT -> observableOf(KeyEvent.KEYCODE_DPAD_LEFT) + DirectionPad.BUTTON_RIGHT -> observableOf(KeyEvent.KEYCODE_DPAD_RIGHT) + DirectionPad.BUTTON_UP -> observableOf(KeyEvent.KEYCODE_DPAD_UP) + DirectionPad.BUTTON_DOWN -> observableOf(KeyEvent.KEYCODE_DPAD_DOWN) + DirectionPad.BUTTON_UP_LEFT -> observableOf(KeyEvent.KEYCODE_DPAD_LEFT, KeyEvent.KEYCODE_DPAD_UP) + DirectionPad.BUTTON_UP_RIGHT -> observableOf(KeyEvent.KEYCODE_DPAD_UP, KeyEvent.KEYCODE_DPAD_RIGHT) + DirectionPad.BUTTON_DOWN_LEFT -> observableOf(KeyEvent.KEYCODE_DPAD_DOWN, KeyEvent.KEYCODE_DPAD_LEFT) + DirectionPad.BUTTON_DOWN_RIGHT -> observableOf(KeyEvent.KEYCODE_DPAD_DOWN, KeyEvent.KEYCODE_DPAD_RIGHT) + else -> throw InvalidParameterException("Invalid direction event with index: $index") + } + } +} \ No newline at end of file diff --git a/retrograde-touchinput/src/main/java/com/swordfish/touchinput/data/PadEvent.kt b/retrograde-touchinput/src/main/java/com/swordfish/touchinput/data/PadEvent.kt new file mode 100644 index 00000000..5904330d --- /dev/null +++ b/retrograde-touchinput/src/main/java/com/swordfish/touchinput/data/PadEvent.kt @@ -0,0 +1,3 @@ +package com.swordfish.touchinput.data + +data class PadEvent(val action: Int, val keycode: Int) diff --git a/retrograde-touchinput/src/main/java/com/swordfish/touchinput/interfaces/ButtonEventsSource.kt b/retrograde-touchinput/src/main/java/com/swordfish/touchinput/interfaces/ButtonEventsSource.kt new file mode 100644 index 00000000..c5bacf0e --- /dev/null +++ b/retrograde-touchinput/src/main/java/com/swordfish/touchinput/interfaces/ButtonEventsSource.kt @@ -0,0 +1,8 @@ +package com.swordfish.touchinput.interfaces + +import com.swordfish.touchinput.data.ButtonEvent +import io.reactivex.Observable + +interface ButtonEventsSource { + fun getEvents(): Observable +} \ No newline at end of file diff --git a/retrograde-touchinput/src/main/java/com/swordfish/touchinput/pads/GameBoyAdvancePad.kt b/retrograde-touchinput/src/main/java/com/swordfish/touchinput/pads/GameBoyAdvancePad.kt new file mode 100644 index 00000000..c3eaee88 --- /dev/null +++ b/retrograde-touchinput/src/main/java/com/swordfish/touchinput/pads/GameBoyAdvancePad.kt @@ -0,0 +1,67 @@ +package com.swordfish.touchinput.pads + +import android.content.Context +import android.util.AttributeSet +import android.view.KeyEvent +import com.swordfish.touchinput.controller.R +import com.swordfish.touchinput.data.EventsTransformers +import com.swordfish.touchinput.data.PadEvent +import com.swordfish.touchinput.views.ActionButtons +import com.swordfish.touchinput.views.DirectionPad +import com.swordfish.touchinput.views.LargeSingleButton +import com.swordfish.touchinput.views.SmallSingleButton +import io.reactivex.Observable + +class GameBoyAdvancePad @JvmOverloads constructor( + context: Context, + attrs: AttributeSet? = null, + defStyleAttr: Int = 0) : GamePadView(context, attrs, defStyleAttr) { + + init { + inflate(context, R.layout.layout_gba, this) + } + + override fun getEvents(): Observable { + return Observable.merge(listOf( + getStartEvent(), + getSelectEvent(), + getDirectionEvents(), + getActionEvents(), + getR1Events(), + getL1Events())) + } + + fun getStartEvent(): Observable { + return findViewById(R.id.gba_start) + .getEvents() + .compose(EventsTransformers.singleButtonMap(KeyEvent.KEYCODE_BUTTON_START)) + } + + fun getSelectEvent(): Observable { + return findViewById(R.id.gba_select) + .getEvents() + .compose(EventsTransformers.singleButtonMap(KeyEvent.KEYCODE_BUTTON_SELECT)) + } + + fun getActionEvents(): Observable { + return findViewById(R.id.gba_actions) + .getEvents() + .compose(EventsTransformers.actionButtonsMap(KeyEvent.KEYCODE_B, KeyEvent.KEYCODE_A)) + + } + + fun getDirectionEvents(): Observable { + return findViewById(R.id.gba_direction).getEvents() + .compose(EventsTransformers.directionPadMap()) + } + + fun getL1Events(): Observable { + return findViewById(R.id.gba_l1).getEvents() + .compose(EventsTransformers.singleButtonMap(KeyEvent.KEYCODE_BUTTON_L1)) + } + + fun getR1Events(): Observable { + return findViewById(R.id.gba_r1).getEvents() + .compose(EventsTransformers.singleButtonMap(KeyEvent.KEYCODE_BUTTON_R1)) + } +} diff --git a/retrograde-touchinput/src/main/java/com/swordfish/touchinput/pads/GameBoyPad.kt b/retrograde-touchinput/src/main/java/com/swordfish/touchinput/pads/GameBoyPad.kt new file mode 100644 index 00000000..a6cd1b64 --- /dev/null +++ b/retrograde-touchinput/src/main/java/com/swordfish/touchinput/pads/GameBoyPad.kt @@ -0,0 +1,55 @@ +package com.swordfish.touchinput.pads + +import android.content.Context +import android.util.AttributeSet +import android.view.KeyEvent +import com.swordfish.touchinput.controller.R +import com.swordfish.touchinput.data.EventsTransformers +import com.swordfish.touchinput.data.PadEvent +import com.swordfish.touchinput.views.ActionButtons +import com.swordfish.touchinput.views.DirectionPad +import com.swordfish.touchinput.views.base.BaseSingleButton +import io.reactivex.Observable + +class GameBoyPad @JvmOverloads constructor( + context: Context, + attrs: AttributeSet? = null, + defStyleAttr: Int = 0) : GamePadView(context, attrs, defStyleAttr) { + + init { + inflate(context, R.layout.layout_gb, this) + } + + override fun getEvents(): Observable { + return Observable.merge( + getStartEvent(), + getSelectEvent(), + getDirectionEvents(), + getActionEvents() + ) + } + + fun getStartEvent(): Observable { + return findViewById(R.id.gb_start) + .getEvents() + .compose(EventsTransformers.singleButtonMap(KeyEvent.KEYCODE_BUTTON_START)) + } + + fun getSelectEvent(): Observable { + return findViewById(R.id.gb_select) + .getEvents() + .compose(EventsTransformers.singleButtonMap(KeyEvent.KEYCODE_BUTTON_SELECT)) + } + + fun getActionEvents(): Observable { + return findViewById(R.id.gb_actions) + .getEvents() + .compose(EventsTransformers.actionButtonsMap(KeyEvent.KEYCODE_A, KeyEvent.KEYCODE_B)) + + } + + fun getDirectionEvents(): Observable { + return findViewById(R.id.gb_direction).getEvents() + .compose(EventsTransformers.directionPadMap()) + } +} diff --git a/retrograde-touchinput/src/main/java/com/swordfish/touchinput/pads/GamePadFactory.kt b/retrograde-touchinput/src/main/java/com/swordfish/touchinput/pads/GamePadFactory.kt new file mode 100644 index 00000000..7fb64d66 --- /dev/null +++ b/retrograde-touchinput/src/main/java/com/swordfish/touchinput/pads/GamePadFactory.kt @@ -0,0 +1,19 @@ +package com.swordfish.touchinput.pads + +import android.content.Context + +class GamePadFactory { + enum class Layout { + NES, + SNES + } + + companion object { + fun getGamePadView(context: Context, layout: Layout): GamePadView { + return when (layout) { + Layout.NES -> GameBoyPad(context) + Layout.SNES -> GameBoyAdvancePad(context) + } + } + } +} diff --git a/retrograde-touchinput/src/main/java/com/swordfish/touchinput/pads/GamePadView.kt b/retrograde-touchinput/src/main/java/com/swordfish/touchinput/pads/GamePadView.kt new file mode 100644 index 00000000..709f1321 --- /dev/null +++ b/retrograde-touchinput/src/main/java/com/swordfish/touchinput/pads/GamePadView.kt @@ -0,0 +1,16 @@ +package com.swordfish.touchinput.pads + +import android.content.Context +import android.util.AttributeSet +import android.view.View +import android.widget.FrameLayout +import com.swordfish.touchinput.data.PadEvent +import io.reactivex.Observable + +abstract class GamePadView @JvmOverloads constructor( + context: Context, + attrs: AttributeSet? = null, + defStyleAttr: Int = 0) : FrameLayout(context, attrs, defStyleAttr) { + + abstract fun getEvents(): Observable +} diff --git a/retrograde-touchinput/src/main/java/com/swordfish/touchinput/utils/ControllerUtils.kt b/retrograde-touchinput/src/main/java/com/swordfish/touchinput/utils/ControllerUtils.kt new file mode 100644 index 00000000..a97721ec --- /dev/null +++ b/retrograde-touchinput/src/main/java/com/swordfish/touchinput/utils/ControllerUtils.kt @@ -0,0 +1,5 @@ +package com.swordfish.touchinput.utils + +import io.reactivex.Observable + +fun observableOf(vararg ts: T): Observable = Observable.fromArray(*ts) \ No newline at end of file diff --git a/retrograde-touchinput/src/main/java/com/swordfish/touchinput/views/ActionButtons.kt b/retrograde-touchinput/src/main/java/com/swordfish/touchinput/views/ActionButtons.kt new file mode 100644 index 00000000..34b0f8a5 --- /dev/null +++ b/retrograde-touchinput/src/main/java/com/swordfish/touchinput/views/ActionButtons.kt @@ -0,0 +1,185 @@ +package com.swordfish.touchinput.views + +import android.content.Context +import android.content.res.TypedArray +import android.graphics.Canvas +import android.graphics.Matrix +import android.graphics.drawable.Drawable +import android.support.v7.content.res.AppCompatResources +import android.util.AttributeSet +import android.view.KeyEvent +import android.view.MotionEvent +import android.view.View +import com.jakewharton.rxrelay2.PublishRelay +import com.swordfish.touchinput.controller.R +import com.swordfish.touchinput.data.ButtonEvent +import com.swordfish.touchinput.interfaces.ButtonEventsSource +import io.reactivex.Observable +import kotlin.math.abs +import kotlin.math.cos +import kotlin.math.floor +import kotlin.math.sin + +class ActionButtons @JvmOverloads constructor( + context: Context, + attrs: AttributeSet? = null, + defStyleAttr: Int = 0) : View(context, attrs, defStyleAttr), ButtonEventsSource { + + private val events: PublishRelay = PublishRelay.create() + + private var spacing: Float = 0.1f + private var rows: Int = 2 + private var cols: Int = 2 + private var rotateButtons: Float = 0.0f + private var supportsMultipleInputs: Boolean = false + + private var notRotatedWidth: Float = 0f + private var notRotatedHeight: Float = 0f + private var xPadding: Float = 0f + private var yPadding: Float = 0f + private var buttonSize: Float = 0f + private var totalButtonSize: Float = 0f + + private val buttonsPressed = mutableSetOf() + + private var pressedDrawable: Drawable? + private var normalDrawable: Drawable? + + private val touchRotationMatrix = Matrix() + + init { + pressedDrawable = retrieveDrawable(R.drawable.action_pressed) + normalDrawable = retrieveDrawable(R.drawable.action_normal) + + context.theme.obtainStyledAttributes(attrs, R.styleable.ActionButtons, defStyleAttr, 0)?.let { + initializeFromAttributes(it) + } + } + + override fun getEvents(): Observable = events + + private fun initializeFromAttributes(a: TypedArray) { + supportsMultipleInputs = a.getBoolean(R.styleable.ActionButtons_multipleInputs, false) + rows = a.getInt(R.styleable.ActionButtons_rows, 2) + cols = a.getInt(R.styleable.ActionButtons_cols, 2) + spacing = a.getFloat(R.styleable.ActionButtons_spacing, 0.1f) + rotateButtons = a.getFloat(R.styleable.ActionButtons_rotateButtons, 45.0f) + } + + override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) { + buttonSize = resources.getDimension(R.dimen.size_action_button_item) + totalButtonSize = buttonSize + buttonSize * spacing + + notRotatedWidth = totalButtonSize * cols + notRotatedHeight = totalButtonSize * rows + + val radians = Math.toRadians(rotateButtons.toDouble()) + val rotatedWidth = (abs(notRotatedWidth * sin(radians)) + abs(notRotatedHeight * cos(radians))).toFloat() + val rotatedHeight = (abs(notRotatedWidth * cos(radians)) + abs(notRotatedHeight * sin(radians))).toFloat() + + val width = getSize(MeasureSpec.getMode(widthMeasureSpec), MeasureSpec.getSize(widthMeasureSpec), rotatedWidth.toInt()) + val height = getSize(MeasureSpec.getMode(heightMeasureSpec), MeasureSpec.getSize(heightMeasureSpec), rotatedHeight.toInt()) + + xPadding = abs(width - notRotatedWidth) / 2f + yPadding = abs(height - notRotatedHeight) / 2f + + setMeasuredDimension(width, height) + } + + private fun getSize(widthMode: Int, widthSize: Int, expectedSize: Int): Int { + return when (widthMode) { + MeasureSpec.EXACTLY -> widthSize + else -> minOf(expectedSize, widthSize) + } + } + + override fun onLayout(changed: Boolean, left: Int, top: Int, right: Int, bottom: Int) { + super.onLayout(changed, left, top, right, bottom) + touchRotationMatrix.reset() + touchRotationMatrix.setRotate(-rotateButtons, width / 2f, height / 2f) + } + + override fun onDraw(canvas: Canvas) { + super.onDraw(canvas) + + canvas.save() + canvas.rotate(rotateButtons, width / 2f, height / 2f) + + for (row in 0 until rows) { + for (col in 0 until cols) { + val index = toIndex(row, col) + + val drawable = if (index in buttonsPressed) { pressedDrawable } else { normalDrawable } + + drawable?.let { + val height = drawable.intrinsicHeight + val width = drawable.intrinsicWidth + val left = (xPadding + col * totalButtonSize).toInt() + val top = (yPadding + row * totalButtonSize).toInt() + + drawable.setBounds(left, top, left + width, top + height) + drawable.draw(canvas) + } + } + } + + canvas.restore() + } + + override fun onTouchEvent(event: MotionEvent): Boolean { + when (event.actionMasked) { + MotionEvent.ACTION_DOWN, MotionEvent.ACTION_POINTER_DOWN, MotionEvent.ACTION_MOVE -> { + handleTouchEvent(event.x, event.y) + return true + } + MotionEvent.ACTION_UP -> { + allKeysReleased() + invalidate() + return true + } + } + + return super.onTouchEvent(event) + } + + private fun handleTouchEvent(originalX: Float, originalY: Float) { + val point = floatArrayOf(originalX, originalY) + + touchRotationMatrix.mapPoints(point) + val x = (point[0] - xPadding) + val y = (point[1] - yPadding) + + val isXInRange = x in (0f..notRotatedWidth) + val isYInRange = y in (0f..notRotatedHeight) + + if (isXInRange && isYInRange) { + val col = floor(x / totalButtonSize).toInt() + val row = floor(y / totalButtonSize).toInt() + val index = toIndex(row, col) + + if (buttonsPressed.contains(index).not()) { + if (supportsMultipleInputs.not()) { + allKeysReleased() + } + onKeyPressed(index) + } + postInvalidate() + } + } + + private fun toIndex(row: Int, col: Int) = row * cols + col + + private fun onKeyPressed(index: Int) { + buttonsPressed.add(index) + events.accept(ButtonEvent(KeyEvent.ACTION_DOWN, index)) + } + + private fun allKeysReleased() { + buttonsPressed.map { events.accept(ButtonEvent(KeyEvent.ACTION_UP, it)) } + buttonsPressed.clear() + } + + private fun retrieveDrawable(drawableId: Int): Drawable? { + return AppCompatResources.getDrawable(context, drawableId) + } +} diff --git a/retrograde-touchinput/src/main/java/com/swordfish/touchinput/views/DirectionPad.kt b/retrograde-touchinput/src/main/java/com/swordfish/touchinput/views/DirectionPad.kt new file mode 100644 index 00000000..325171b8 --- /dev/null +++ b/retrograde-touchinput/src/main/java/com/swordfish/touchinput/views/DirectionPad.kt @@ -0,0 +1,198 @@ +package com.swordfish.touchinput.views + +import android.content.Context +import android.content.res.TypedArray +import android.graphics.Canvas +import android.graphics.Matrix +import android.graphics.drawable.Drawable +import android.support.v4.content.ContextCompat +import android.util.AttributeSet +import android.view.KeyEvent +import android.view.MotionEvent +import android.view.View +import com.jakewharton.rxrelay2.PublishRelay +import com.swordfish.touchinput.controller.R +import com.swordfish.touchinput.data.ButtonEvent +import com.swordfish.touchinput.interfaces.ButtonEventsSource +import io.reactivex.Observable +import kotlin.math.atan2 +import kotlin.math.cos +import kotlin.math.floor +import kotlin.math.sin + + +class DirectionPad @JvmOverloads constructor( + context: Context, + attrs: AttributeSet? = null, + defStyleAttr: Int = 0) : View(context, attrs, defStyleAttr), ButtonEventsSource { + + companion object { + + private const val BUTTON_COUNT = 8 + private const val ROTATE_BUTTONS = 22.5f + private const val SINGLE_BUTTON_ANGLE = 360f / BUTTON_COUNT + + const val BUTTON_RIGHT = 0 + const val BUTTON_DOWN_RIGHT = 1 + const val BUTTON_DOWN = 2 + const val BUTTON_DOWN_LEFT = 3 + const val BUTTON_LEFT = 4 + const val BUTTON_UP_LEFT = 5 + const val BUTTON_UP = 6 + const val BUTTON_UP_RIGHT = 7 + } + + private var deadZone: Float = 0f + private var buttonCenterDistance: Float = 0f + + private val touchRotationMatrix = Matrix() + private var radius: Int = 0 + + private val normalDrawables: Map = initNormalDrawables() + private val pressedDrawables: Map = initPressedDrawables() + + private val events: PublishRelay = PublishRelay.create() + + private val buttonsPressed = mutableSetOf() + + init { + context.theme.obtainStyledAttributes(attrs, R.styleable.DirectionPad, defStyleAttr, R.style.default_directionpad).let { + initializeFromAttributes(it) + } + } + + override fun getEvents(): Observable = events + + private fun initializeFromAttributes(a: TypedArray) { + deadZone = a.getFloat(R.styleable.DirectionPad_deadZone, 0f) + buttonCenterDistance = a.getFloat(R.styleable.DirectionPad_buttonCenterDistance, 0f) + } + + override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) { + val width = getSize(MeasureSpec.getMode(widthMeasureSpec), MeasureSpec.getSize(widthMeasureSpec)) + val height = getSize(MeasureSpec.getMode(heightMeasureSpec), MeasureSpec.getSize(heightMeasureSpec)) + + val diameter = minOf(width, height) + setMeasuredDimension(diameter, diameter) + radius = diameter / 2 + } + + private fun getSize(widthMode: Int, widthSize: Int): Int { + return when (widthMode) { + MeasureSpec.EXACTLY -> widthSize + else -> minOf(resources.getDimension(R.dimen.size_dial).toInt(), widthSize) + } + } + + override fun onLayout(changed: Boolean, left: Int, top: Int, right: Int, bottom: Int) { + super.onLayout(changed, left, top, right, bottom) + + touchRotationMatrix.reset() + touchRotationMatrix.setRotate(ROTATE_BUTTONS) + } + + override fun onDraw(canvas: Canvas) { + super.onDraw(canvas) + val pressedButtons = convertDiagonals(buttonsPressed) + + for (i in 0..BUTTON_COUNT) { + val cAngle = SINGLE_BUTTON_ANGLE * i + + val isPressed = i in pressedButtons + + getStateDrawable(i, isPressed)?.let { + val height = it.intrinsicHeight + val width = it.intrinsicWidth + val angle = Math.toRadians((cAngle - ROTATE_BUTTONS + SINGLE_BUTTON_ANGLE / 2f).toDouble()) + val left = (radius * buttonCenterDistance * cos(angle) + radius).toInt() - width / 2 + val top = (radius * buttonCenterDistance * sin(angle) + radius).toInt() - height / 2 + + it.setBounds(left, top, left + width, top + height) + it.draw(canvas) + } + } + } + + override fun onTouchEvent(event: MotionEvent): Boolean { + when (event.actionMasked) { + MotionEvent.ACTION_DOWN, MotionEvent.ACTION_POINTER_DOWN, MotionEvent.ACTION_MOVE -> { + handleTouchEvent(event.x - radius, event.y - radius) + return true + } + MotionEvent.ACTION_UP -> { + allKeysReleased() + invalidate() + return true + } + } + + return super.onTouchEvent(event) + } + + private fun handleTouchEvent(originalX: Float, originalY: Float) { + val point = floatArrayOf(originalX, originalY) + + if (isOutsideDeadzone(point[0], point[1])) { + touchRotationMatrix.mapPoints(point) + val x = point[0] + val y = point[1] + + val angle = (atan2(y, x) * 180 / Math.PI + 360f) % 360f + val index = floor(angle / SINGLE_BUTTON_ANGLE).toInt() + + if (buttonsPressed.contains(index).not()) { + allKeysReleased() + onKeyPressed(index) + } + + postInvalidate() + } + } + + private fun onKeyPressed(index: Int) { + buttonsPressed.add(index) + events.accept(ButtonEvent(KeyEvent.ACTION_DOWN, index)) + } + + private fun allKeysReleased() { + buttonsPressed.map { events.accept(ButtonEvent(KeyEvent.ACTION_UP, it)) } + buttonsPressed.clear() + } + + private fun isOutsideDeadzone(x: Float, y: Float): Boolean { + return x * x + y * y > radius * deadZone * radius * deadZone + } + + private fun getStateDrawable(buttonIndex: Int, isPressed: Boolean): Drawable? { + val drawables = if (isPressed) { pressedDrawables } else { normalDrawables } + return drawables[buttonIndex] + } + + private fun initNormalDrawables(): Map { + return mapOf( + BUTTON_RIGHT to ContextCompat.getDrawable(context, R.drawable.direction_right_normal), + BUTTON_UP to ContextCompat.getDrawable(context, R.drawable.direction_up_normal), + BUTTON_LEFT to ContextCompat.getDrawable(context, R.drawable.direction_left_normal), + BUTTON_DOWN to ContextCompat.getDrawable(context, R.drawable.direction_down_normal) + ) + } + + private fun initPressedDrawables(): Map { + return mapOf( + BUTTON_RIGHT to ContextCompat.getDrawable(context, R.drawable.direction_right_pressed), + BUTTON_UP to ContextCompat.getDrawable(context, R.drawable.direction_up_pressed), + BUTTON_LEFT to ContextCompat.getDrawable(context, R.drawable.direction_left_pressed), + BUTTON_DOWN to ContextCompat.getDrawable(context, R.drawable.direction_down_pressed) + ) + } + + private fun convertDiagonals(buttonPressed: Set): Set { + return when { + BUTTON_DOWN_RIGHT in buttonPressed -> buttonPressed union setOf(BUTTON_DOWN, BUTTON_RIGHT) + BUTTON_DOWN_LEFT in buttonPressed -> buttonPressed union setOf(BUTTON_DOWN, BUTTON_LEFT) + BUTTON_UP_LEFT in buttonPressed -> buttonPressed union setOf(BUTTON_UP, BUTTON_LEFT) + BUTTON_UP_RIGHT in buttonPressed -> buttonPressed union setOf(BUTTON_UP, BUTTON_RIGHT) + else -> buttonPressed + } + } +} diff --git a/retrograde-touchinput/src/main/java/com/swordfish/touchinput/views/LargeSingleButton.kt b/retrograde-touchinput/src/main/java/com/swordfish/touchinput/views/LargeSingleButton.kt new file mode 100644 index 00000000..f38fec06 --- /dev/null +++ b/retrograde-touchinput/src/main/java/com/swordfish/touchinput/views/LargeSingleButton.kt @@ -0,0 +1,16 @@ +package com.swordfish.touchinput.views + +import android.content.Context +import android.util.AttributeSet +import com.swordfish.touchinput.controller.R +import com.swordfish.touchinput.views.base.BaseSingleButton + +class LargeSingleButton @JvmOverloads constructor( + context: Context, + attrs: AttributeSet? = null, + defStyleAttr: Int = 0) : BaseSingleButton(context, attrs, defStyleAttr) { + + init { + setBackgroundResource(R.drawable.large_button_selector) + } +} \ No newline at end of file diff --git a/retrograde-touchinput/src/main/java/com/swordfish/touchinput/views/SmallSingleButton.kt b/retrograde-touchinput/src/main/java/com/swordfish/touchinput/views/SmallSingleButton.kt new file mode 100644 index 00000000..a8946174 --- /dev/null +++ b/retrograde-touchinput/src/main/java/com/swordfish/touchinput/views/SmallSingleButton.kt @@ -0,0 +1,16 @@ +package com.swordfish.touchinput.views + +import android.content.Context +import android.util.AttributeSet +import com.swordfish.touchinput.controller.R +import com.swordfish.touchinput.views.base.BaseSingleButton + +class SmallSingleButton @JvmOverloads constructor( + context: Context, + attrs: AttributeSet? = null, + defStyleAttr: Int = 0) : BaseSingleButton(context, attrs, defStyleAttr) { + + init { + setBackgroundResource(R.drawable.small_button_selector) + } +} \ No newline at end of file diff --git a/retrograde-touchinput/src/main/java/com/swordfish/touchinput/views/base/BaseSingleButton.kt b/retrograde-touchinput/src/main/java/com/swordfish/touchinput/views/base/BaseSingleButton.kt new file mode 100644 index 00000000..afe3ee06 --- /dev/null +++ b/retrograde-touchinput/src/main/java/com/swordfish/touchinput/views/base/BaseSingleButton.kt @@ -0,0 +1,39 @@ +package com.swordfish.touchinput.views.base + +import android.content.Context +import android.util.AttributeSet +import android.view.KeyEvent +import android.view.MotionEvent +import android.widget.Button +import com.jakewharton.rxrelay2.PublishRelay +import com.swordfish.touchinput.data.ButtonEvent +import com.swordfish.touchinput.interfaces.ButtonEventsSource +import io.reactivex.Observable + + +abstract class BaseSingleButton @JvmOverloads constructor( + context: Context, + attrs: AttributeSet? = null, + defStyleAttr: Int = 0) : Button(context, attrs, defStyleAttr), ButtonEventsSource { + + private val events: PublishRelay = PublishRelay.create() + + init { + setOnTouchListener { _, event -> handleTouchEvent(event); true } + } + + private fun handleTouchEvent(event: MotionEvent) { + when (event.actionMasked) { + MotionEvent.ACTION_DOWN -> { + isPressed = true + events.accept(ButtonEvent(KeyEvent.ACTION_DOWN, 0)) + } + MotionEvent.ACTION_UP -> { + isPressed = false + events.accept(ButtonEvent(KeyEvent.ACTION_UP, 0)) + } + } + } + + override fun getEvents(): Observable = events +} diff --git a/retrograde-touchinput/src/main/res/drawable/action_normal.xml b/retrograde-touchinput/src/main/res/drawable/action_normal.xml new file mode 100644 index 00000000..e9b43746 --- /dev/null +++ b/retrograde-touchinput/src/main/res/drawable/action_normal.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/retrograde-touchinput/src/main/res/drawable/action_pressed.xml b/retrograde-touchinput/src/main/res/drawable/action_pressed.xml new file mode 100644 index 00000000..cd0a1de3 --- /dev/null +++ b/retrograde-touchinput/src/main/res/drawable/action_pressed.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/retrograde-touchinput/src/main/res/drawable/direction_down_normal.xml b/retrograde-touchinput/src/main/res/drawable/direction_down_normal.xml new file mode 100644 index 00000000..92382f1b --- /dev/null +++ b/retrograde-touchinput/src/main/res/drawable/direction_down_normal.xml @@ -0,0 +1,12 @@ + + + + + \ No newline at end of file diff --git a/retrograde-touchinput/src/main/res/drawable/direction_down_pressed.xml b/retrograde-touchinput/src/main/res/drawable/direction_down_pressed.xml new file mode 100644 index 00000000..3fe971d2 --- /dev/null +++ b/retrograde-touchinput/src/main/res/drawable/direction_down_pressed.xml @@ -0,0 +1,11 @@ + + + + + \ No newline at end of file diff --git a/retrograde-touchinput/src/main/res/drawable/direction_left_normal.xml b/retrograde-touchinput/src/main/res/drawable/direction_left_normal.xml new file mode 100644 index 00000000..422e4155 --- /dev/null +++ b/retrograde-touchinput/src/main/res/drawable/direction_left_normal.xml @@ -0,0 +1,12 @@ + + + + + \ No newline at end of file diff --git a/retrograde-touchinput/src/main/res/drawable/direction_left_pressed.xml b/retrograde-touchinput/src/main/res/drawable/direction_left_pressed.xml new file mode 100644 index 00000000..1126be75 --- /dev/null +++ b/retrograde-touchinput/src/main/res/drawable/direction_left_pressed.xml @@ -0,0 +1,11 @@ + + + + + \ No newline at end of file diff --git a/retrograde-touchinput/src/main/res/drawable/direction_right_normal.xml b/retrograde-touchinput/src/main/res/drawable/direction_right_normal.xml new file mode 100644 index 00000000..921d3e5c --- /dev/null +++ b/retrograde-touchinput/src/main/res/drawable/direction_right_normal.xml @@ -0,0 +1,12 @@ + + + + + \ No newline at end of file diff --git a/retrograde-touchinput/src/main/res/drawable/direction_right_pressed.xml b/retrograde-touchinput/src/main/res/drawable/direction_right_pressed.xml new file mode 100644 index 00000000..10b24cb5 --- /dev/null +++ b/retrograde-touchinput/src/main/res/drawable/direction_right_pressed.xml @@ -0,0 +1,11 @@ + + + + + \ No newline at end of file diff --git a/retrograde-touchinput/src/main/res/drawable/direction_up_normal.xml b/retrograde-touchinput/src/main/res/drawable/direction_up_normal.xml new file mode 100644 index 00000000..9875aba1 --- /dev/null +++ b/retrograde-touchinput/src/main/res/drawable/direction_up_normal.xml @@ -0,0 +1,12 @@ + + + + + \ No newline at end of file diff --git a/retrograde-touchinput/src/main/res/drawable/direction_up_pressed.xml b/retrograde-touchinput/src/main/res/drawable/direction_up_pressed.xml new file mode 100644 index 00000000..b8d7d049 --- /dev/null +++ b/retrograde-touchinput/src/main/res/drawable/direction_up_pressed.xml @@ -0,0 +1,11 @@ + + + + + \ No newline at end of file diff --git a/retrograde-touchinput/src/main/res/drawable/large_button_normal.xml b/retrograde-touchinput/src/main/res/drawable/large_button_normal.xml new file mode 100644 index 00000000..14d12ec2 --- /dev/null +++ b/retrograde-touchinput/src/main/res/drawable/large_button_normal.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/retrograde-touchinput/src/main/res/drawable/large_button_pressed.xml b/retrograde-touchinput/src/main/res/drawable/large_button_pressed.xml new file mode 100644 index 00000000..9b6038ca --- /dev/null +++ b/retrograde-touchinput/src/main/res/drawable/large_button_pressed.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/retrograde-touchinput/src/main/res/drawable/large_button_selector.xml b/retrograde-touchinput/src/main/res/drawable/large_button_selector.xml new file mode 100644 index 00000000..3f36b6fe --- /dev/null +++ b/retrograde-touchinput/src/main/res/drawable/large_button_selector.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/retrograde-touchinput/src/main/res/drawable/small_button_normal.xml b/retrograde-touchinput/src/main/res/drawable/small_button_normal.xml new file mode 100644 index 00000000..cd268e78 --- /dev/null +++ b/retrograde-touchinput/src/main/res/drawable/small_button_normal.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/retrograde-touchinput/src/main/res/drawable/small_button_pressed.xml b/retrograde-touchinput/src/main/res/drawable/small_button_pressed.xml new file mode 100644 index 00000000..07d9670f --- /dev/null +++ b/retrograde-touchinput/src/main/res/drawable/small_button_pressed.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/retrograde-touchinput/src/main/res/drawable/small_button_selector.xml b/retrograde-touchinput/src/main/res/drawable/small_button_selector.xml new file mode 100644 index 00000000..9d62d823 --- /dev/null +++ b/retrograde-touchinput/src/main/res/drawable/small_button_selector.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/retrograde-touchinput/src/main/res/layout/layout_gb.xml b/retrograde-touchinput/src/main/res/layout/layout_gb.xml new file mode 100644 index 00000000..cd716a3e --- /dev/null +++ b/retrograde-touchinput/src/main/res/layout/layout_gb.xml @@ -0,0 +1,44 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/retrograde-touchinput/src/main/res/layout/layout_gba.xml b/retrograde-touchinput/src/main/res/layout/layout_gba.xml new file mode 100644 index 00000000..65acb0ef --- /dev/null +++ b/retrograde-touchinput/src/main/res/layout/layout_gba.xml @@ -0,0 +1,64 @@ + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/retrograde-touchinput/src/main/res/values/colors.xml b/retrograde-touchinput/src/main/res/values/colors.xml new file mode 100644 index 00000000..1740b8ac --- /dev/null +++ b/retrograde-touchinput/src/main/res/values/colors.xml @@ -0,0 +1,4 @@ + + + #7fff + \ No newline at end of file diff --git a/retrograde-touchinput/src/main/res/values/default_styles.xml b/retrograde-touchinput/src/main/res/values/default_styles.xml new file mode 100644 index 00000000..3f3f0c7e --- /dev/null +++ b/retrograde-touchinput/src/main/res/values/default_styles.xml @@ -0,0 +1,29 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/retrograde-touchinput/src/main/res/values/dimen.xml b/retrograde-touchinput/src/main/res/values/dimen.xml new file mode 100644 index 00000000..be14876f --- /dev/null +++ b/retrograde-touchinput/src/main/res/values/dimen.xml @@ -0,0 +1,21 @@ + + + 160dp + 50dp + + 55dp + + 25dp + 50dp + + 40dp + 80dp + + 3dp + + 8dp + 16dp + + 2 + 30 + \ No newline at end of file diff --git a/retrograde-touchinput/src/main/res/values/input_attrs.xml b/retrograde-touchinput/src/main/res/values/input_attrs.xml new file mode 100644 index 00000000..3b128687 --- /dev/null +++ b/retrograde-touchinput/src/main/res/values/input_attrs.xml @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/retrograde-touchinput/src/main/res/values/strings.xml b/retrograde-touchinput/src/main/res/values/strings.xml new file mode 100644 index 00000000..8f48227e --- /dev/null +++ b/retrograde-touchinput/src/main/res/values/strings.xml @@ -0,0 +1,6 @@ + + M15,29 m-2,-2 l-8,-8 l0,-14 a17,17 0 0,1 20,0 l0,14 l-8,8 a3,3 0 0,1 -4,0z + M15,1 m2,2 l8,8 l0,14 a17,17 0 0,1 -20,0 l0,-14 l8,-8 a3,3 0 0,1 4,0z + M1,15 m2,-2 l8,-8 l14,0 a17,17 0 0,1 0,20 l-14,0 l-8,-8 a3,3 0 0,1 0,-4z + M29,15 m-2,-2 l-8,-8 l-14,0 a17,17 0 0,0 0,20 l14,0 l8,-8 a3,3 0 0,0 0,-4z + diff --git a/settings.gradle.kts b/settings.gradle.kts index cf561244..c6c924d5 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -5,5 +5,6 @@ include( ":retrograde-storage-webdav", ":retrograde-storage-archiveorg", ":retrograde-app-shared", - ":retrograde-app-tv" + ":retrograde-app-tv", + ":retrograde-touchinput" ) From 6e7bd1dfca84c8c7dd5c2200fb90cd1193d5861f Mon Sep 17 00:00:00 2001 From: Filippo Scognamiglio Date: Sat, 7 Sep 2019 18:38:41 +0200 Subject: [PATCH 2/5] Add touch layout for Sega Genesis. --- .../app/feature/game/GameActivity.kt | 1 + .../touchinput/pads/GamePadFactory.kt | 4 +- .../swordfish/touchinput/pads/GenesisPad.kt | 48 +++++++++++++++++++ .../src/main/res/layout/layout_genesis.xml | 36 ++++++++++++++ 4 files changed, 88 insertions(+), 1 deletion(-) create mode 100644 retrograde-touchinput/src/main/java/com/swordfish/touchinput/pads/GenesisPad.kt create mode 100644 retrograde-touchinput/src/main/res/layout/layout_genesis.xml diff --git a/retrograde-app-tv/src/main/java/com/codebutler/retrograde/app/feature/game/GameActivity.kt b/retrograde-app-tv/src/main/java/com/codebutler/retrograde/app/feature/game/GameActivity.kt index 495ea48b..1f4cb23b 100644 --- a/retrograde-app-tv/src/main/java/com/codebutler/retrograde/app/feature/game/GameActivity.kt +++ b/retrograde-app-tv/src/main/java/com/codebutler/retrograde/app/feature/game/GameActivity.kt @@ -124,6 +124,7 @@ class GameActivity : RetrogradeActivity() { val gameView = when (game.systemId) { in listOf("snes", "gba") -> GamePadFactory.getGamePadView(this, GamePadFactory.Layout.SNES) in listOf("nes", "gb", "gbc") -> GamePadFactory.getGamePadView(this, GamePadFactory.Layout.NES) + in listOf("md") -> GamePadFactory.getGamePadView(this, GamePadFactory.Layout.GENESIS) else -> null } diff --git a/retrograde-touchinput/src/main/java/com/swordfish/touchinput/pads/GamePadFactory.kt b/retrograde-touchinput/src/main/java/com/swordfish/touchinput/pads/GamePadFactory.kt index 7fb64d66..2f40c771 100644 --- a/retrograde-touchinput/src/main/java/com/swordfish/touchinput/pads/GamePadFactory.kt +++ b/retrograde-touchinput/src/main/java/com/swordfish/touchinput/pads/GamePadFactory.kt @@ -5,7 +5,8 @@ import android.content.Context class GamePadFactory { enum class Layout { NES, - SNES + SNES, + GENESIS } companion object { @@ -13,6 +14,7 @@ class GamePadFactory { return when (layout) { Layout.NES -> GameBoyPad(context) Layout.SNES -> GameBoyAdvancePad(context) + Layout.GENESIS -> GenesisPad(context) } } } diff --git a/retrograde-touchinput/src/main/java/com/swordfish/touchinput/pads/GenesisPad.kt b/retrograde-touchinput/src/main/java/com/swordfish/touchinput/pads/GenesisPad.kt new file mode 100644 index 00000000..6aa2057c --- /dev/null +++ b/retrograde-touchinput/src/main/java/com/swordfish/touchinput/pads/GenesisPad.kt @@ -0,0 +1,48 @@ +package com.swordfish.touchinput.pads + +import android.content.Context +import android.util.AttributeSet +import android.view.KeyEvent +import com.swordfish.touchinput.controller.R +import com.swordfish.touchinput.data.EventsTransformers +import com.swordfish.touchinput.data.PadEvent +import com.swordfish.touchinput.views.ActionButtons +import com.swordfish.touchinput.views.DirectionPad +import com.swordfish.touchinput.views.base.BaseSingleButton +import io.reactivex.Observable + +class GenesisPad @JvmOverloads constructor( + context: Context, + attrs: AttributeSet? = null, + defStyleAttr: Int = 0) : GamePadView(context, attrs, defStyleAttr) { + + init { + inflate(context, R.layout.layout_genesis, this) + } + + override fun getEvents(): Observable { + return Observable.merge( + getStartEvent(), + getDirectionEvents(), + getActionEvents() + ) + } + + fun getStartEvent(): Observable { + return findViewById(R.id.genesis_start) + .getEvents() + .compose(EventsTransformers.singleButtonMap(KeyEvent.KEYCODE_BUTTON_START)) + } + + fun getActionEvents(): Observable { + return findViewById(R.id.genesis_actions) + .getEvents() + .compose(EventsTransformers.actionButtonsMap(KeyEvent.KEYCODE_A, KeyEvent.KEYCODE_B, KeyEvent.KEYCODE_C)) + + } + + fun getDirectionEvents(): Observable { + return findViewById(R.id.genesis_direction).getEvents() + .compose(EventsTransformers.directionPadMap()) + } +} diff --git a/retrograde-touchinput/src/main/res/layout/layout_genesis.xml b/retrograde-touchinput/src/main/res/layout/layout_genesis.xml new file mode 100644 index 00000000..1fc3e34a --- /dev/null +++ b/retrograde-touchinput/src/main/res/layout/layout_genesis.xml @@ -0,0 +1,36 @@ + + + + + + + + + \ No newline at end of file From 4078e5fb126639ceca142139cffec9ef958ef9d1 Mon Sep 17 00:00:00 2001 From: Filippo Scognamiglio Date: Sat, 7 Sep 2019 18:40:22 +0200 Subject: [PATCH 3/5] Fix layout issue in GameBoyPad. --- .../src/main/java/com/swordfish/touchinput/pads/GameBoyPad.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/retrograde-touchinput/src/main/java/com/swordfish/touchinput/pads/GameBoyPad.kt b/retrograde-touchinput/src/main/java/com/swordfish/touchinput/pads/GameBoyPad.kt index a6cd1b64..97297e63 100644 --- a/retrograde-touchinput/src/main/java/com/swordfish/touchinput/pads/GameBoyPad.kt +++ b/retrograde-touchinput/src/main/java/com/swordfish/touchinput/pads/GameBoyPad.kt @@ -44,7 +44,7 @@ class GameBoyPad @JvmOverloads constructor( fun getActionEvents(): Observable { return findViewById(R.id.gb_actions) .getEvents() - .compose(EventsTransformers.actionButtonsMap(KeyEvent.KEYCODE_A, KeyEvent.KEYCODE_B)) + .compose(EventsTransformers.actionButtonsMap(KeyEvent.KEYCODE_B, KeyEvent.KEYCODE_A)) } From 9d860b96d277a98291ee244235cdd16d742bf80f Mon Sep 17 00:00:00 2001 From: Filippo Scognamiglio Date: Sat, 7 Sep 2019 18:41:34 +0200 Subject: [PATCH 4/5] Refactor GamePadView into BaseGamePad. --- .../touchinput/pads/{GamePadView.kt => BaseGamePad.kt} | 2 +- .../java/com/swordfish/touchinput/pads/GameBoyAdvancePad.kt | 2 +- .../src/main/java/com/swordfish/touchinput/pads/GameBoyPad.kt | 2 +- .../main/java/com/swordfish/touchinput/pads/GamePadFactory.kt | 2 +- .../src/main/java/com/swordfish/touchinput/pads/GenesisPad.kt | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) rename retrograde-touchinput/src/main/java/com/swordfish/touchinput/pads/{GamePadView.kt => BaseGamePad.kt} (88%) diff --git a/retrograde-touchinput/src/main/java/com/swordfish/touchinput/pads/GamePadView.kt b/retrograde-touchinput/src/main/java/com/swordfish/touchinput/pads/BaseGamePad.kt similarity index 88% rename from retrograde-touchinput/src/main/java/com/swordfish/touchinput/pads/GamePadView.kt rename to retrograde-touchinput/src/main/java/com/swordfish/touchinput/pads/BaseGamePad.kt index 709f1321..f3623300 100644 --- a/retrograde-touchinput/src/main/java/com/swordfish/touchinput/pads/GamePadView.kt +++ b/retrograde-touchinput/src/main/java/com/swordfish/touchinput/pads/BaseGamePad.kt @@ -7,7 +7,7 @@ import android.widget.FrameLayout import com.swordfish.touchinput.data.PadEvent import io.reactivex.Observable -abstract class GamePadView @JvmOverloads constructor( +abstract class BaseGamePad @JvmOverloads constructor( context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0) : FrameLayout(context, attrs, defStyleAttr) { diff --git a/retrograde-touchinput/src/main/java/com/swordfish/touchinput/pads/GameBoyAdvancePad.kt b/retrograde-touchinput/src/main/java/com/swordfish/touchinput/pads/GameBoyAdvancePad.kt index c3eaee88..a4634782 100644 --- a/retrograde-touchinput/src/main/java/com/swordfish/touchinput/pads/GameBoyAdvancePad.kt +++ b/retrograde-touchinput/src/main/java/com/swordfish/touchinput/pads/GameBoyAdvancePad.kt @@ -15,7 +15,7 @@ import io.reactivex.Observable class GameBoyAdvancePad @JvmOverloads constructor( context: Context, attrs: AttributeSet? = null, - defStyleAttr: Int = 0) : GamePadView(context, attrs, defStyleAttr) { + defStyleAttr: Int = 0) : BaseGamePad(context, attrs, defStyleAttr) { init { inflate(context, R.layout.layout_gba, this) diff --git a/retrograde-touchinput/src/main/java/com/swordfish/touchinput/pads/GameBoyPad.kt b/retrograde-touchinput/src/main/java/com/swordfish/touchinput/pads/GameBoyPad.kt index 97297e63..d9e5febb 100644 --- a/retrograde-touchinput/src/main/java/com/swordfish/touchinput/pads/GameBoyPad.kt +++ b/retrograde-touchinput/src/main/java/com/swordfish/touchinput/pads/GameBoyPad.kt @@ -14,7 +14,7 @@ import io.reactivex.Observable class GameBoyPad @JvmOverloads constructor( context: Context, attrs: AttributeSet? = null, - defStyleAttr: Int = 0) : GamePadView(context, attrs, defStyleAttr) { + defStyleAttr: Int = 0) : BaseGamePad(context, attrs, defStyleAttr) { init { inflate(context, R.layout.layout_gb, this) diff --git a/retrograde-touchinput/src/main/java/com/swordfish/touchinput/pads/GamePadFactory.kt b/retrograde-touchinput/src/main/java/com/swordfish/touchinput/pads/GamePadFactory.kt index 2f40c771..a3fc9653 100644 --- a/retrograde-touchinput/src/main/java/com/swordfish/touchinput/pads/GamePadFactory.kt +++ b/retrograde-touchinput/src/main/java/com/swordfish/touchinput/pads/GamePadFactory.kt @@ -10,7 +10,7 @@ class GamePadFactory { } companion object { - fun getGamePadView(context: Context, layout: Layout): GamePadView { + fun getGamePadView(context: Context, layout: Layout): BaseGamePad { return when (layout) { Layout.NES -> GameBoyPad(context) Layout.SNES -> GameBoyAdvancePad(context) diff --git a/retrograde-touchinput/src/main/java/com/swordfish/touchinput/pads/GenesisPad.kt b/retrograde-touchinput/src/main/java/com/swordfish/touchinput/pads/GenesisPad.kt index 6aa2057c..1aa43619 100644 --- a/retrograde-touchinput/src/main/java/com/swordfish/touchinput/pads/GenesisPad.kt +++ b/retrograde-touchinput/src/main/java/com/swordfish/touchinput/pads/GenesisPad.kt @@ -14,7 +14,7 @@ import io.reactivex.Observable class GenesisPad @JvmOverloads constructor( context: Context, attrs: AttributeSet? = null, - defStyleAttr: Int = 0) : GamePadView(context, attrs, defStyleAttr) { + defStyleAttr: Int = 0) : BaseGamePad(context, attrs, defStyleAttr) { init { inflate(context, R.layout.layout_genesis, this) From 888d361e942dc9b9b1335c3b080b416b64ddf8fb Mon Sep 17 00:00:00 2001 From: Filippo Scognamiglio Date: Sun, 8 Sep 2019 09:57:47 +0200 Subject: [PATCH 5/5] Fix some klint issues. --- .../app/feature/game/GameActivity.kt | 5 ++- .../touchinput/data/EventsTransformers.kt | 3 +- .../swordfish/touchinput/pads/BaseGamePad.kt | 8 ++-- .../touchinput/pads/GameBoyAdvancePad.kt | 38 +++++++++---------- .../swordfish/touchinput/pads/GameBoyPad.kt | 30 +++++++-------- .../swordfish/touchinput/pads/GenesisPad.kt | 30 +++++++-------- .../touchinput/views/ActionButtons.kt | 5 ++- .../touchinput/views/DirectionPad.kt | 10 +++-- .../touchinput/views/LargeSingleButton.kt | 9 +++-- .../touchinput/views/SmallSingleButton.kt | 9 +++-- .../touchinput/views/base/BaseSingleButton.kt | 10 ++--- .../src/main/res/drawable/action_normal.xml | 6 +-- .../src/main/res/drawable/action_pressed.xml | 6 +-- .../res/drawable/direction_down_normal.xml | 18 ++++----- .../res/drawable/direction_down_pressed.xml | 16 ++++---- .../res/drawable/direction_left_normal.xml | 18 ++++----- .../res/drawable/direction_left_pressed.xml | 16 ++++---- .../res/drawable/direction_right_normal.xml | 18 ++++----- .../res/drawable/direction_right_pressed.xml | 16 ++++---- .../main/res/drawable/direction_up_normal.xml | 18 ++++----- .../res/drawable/direction_up_pressed.xml | 16 ++++---- .../main/res/drawable/large_button_normal.xml | 2 +- .../res/drawable/large_button_pressed.xml | 2 +- .../res/drawable/large_button_selector.xml | 2 +- .../main/res/drawable/small_button_normal.xml | 2 +- .../res/drawable/small_button_pressed.xml | 2 +- .../res/drawable/small_button_selector.xml | 2 +- .../src/main/res/layout/layout_gb.xml | 5 ++- .../src/main/res/layout/layout_gba.xml | 10 ++--- .../src/main/res/layout/layout_genesis.xml | 7 ++-- .../src/main/res/values/colors.xml | 2 +- .../src/main/res/values/default_styles.xml | 2 +- .../src/main/res/values/dimen.xml | 2 +- .../src/main/res/values/input_attrs.xml | 2 +- .../src/main/res/values/strings.xml | 1 + 35 files changed, 178 insertions(+), 170 deletions(-) diff --git a/retrograde-app-tv/src/main/java/com/codebutler/retrograde/app/feature/game/GameActivity.kt b/retrograde-app-tv/src/main/java/com/codebutler/retrograde/app/feature/game/GameActivity.kt index 1f4cb23b..9dca0112 100644 --- a/retrograde-app-tv/src/main/java/com/codebutler/retrograde/app/feature/game/GameActivity.kt +++ b/retrograde-app-tv/src/main/java/com/codebutler/retrograde/app/feature/game/GameActivity.kt @@ -24,7 +24,10 @@ import android.content.Intent import android.graphics.Color import android.os.Bundle import android.preference.PreferenceManager -import android.view.* +import android.view.HapticFeedbackConstants +import android.view.KeyEvent +import android.view.MotionEvent +import android.view.View import android.view.ViewGroup.LayoutParams.MATCH_PARENT import android.widget.FrameLayout import android.widget.ProgressBar diff --git a/retrograde-touchinput/src/main/java/com/swordfish/touchinput/data/EventsTransformers.kt b/retrograde-touchinput/src/main/java/com/swordfish/touchinput/data/EventsTransformers.kt index 4c1e8990..5121fae6 100644 --- a/retrograde-touchinput/src/main/java/com/swordfish/touchinput/data/EventsTransformers.kt +++ b/retrograde-touchinput/src/main/java/com/swordfish/touchinput/data/EventsTransformers.kt @@ -20,7 +20,6 @@ internal object EventsTransformers { } } - fun directionPadMap(): ObservableTransformer { return ObservableTransformer { upstream -> upstream.flatMap { buttonEvent -> @@ -42,4 +41,4 @@ internal object EventsTransformers { else -> throw InvalidParameterException("Invalid direction event with index: $index") } } -} \ No newline at end of file +} diff --git a/retrograde-touchinput/src/main/java/com/swordfish/touchinput/pads/BaseGamePad.kt b/retrograde-touchinput/src/main/java/com/swordfish/touchinput/pads/BaseGamePad.kt index f3623300..cff5fa52 100644 --- a/retrograde-touchinput/src/main/java/com/swordfish/touchinput/pads/BaseGamePad.kt +++ b/retrograde-touchinput/src/main/java/com/swordfish/touchinput/pads/BaseGamePad.kt @@ -2,15 +2,15 @@ package com.swordfish.touchinput.pads import android.content.Context import android.util.AttributeSet -import android.view.View import android.widget.FrameLayout import com.swordfish.touchinput.data.PadEvent import io.reactivex.Observable abstract class BaseGamePad @JvmOverloads constructor( - context: Context, - attrs: AttributeSet? = null, - defStyleAttr: Int = 0) : FrameLayout(context, attrs, defStyleAttr) { + context: Context, + attrs: AttributeSet? = null, + defStyleAttr: Int = 0 +) : FrameLayout(context, attrs, defStyleAttr) { abstract fun getEvents(): Observable } diff --git a/retrograde-touchinput/src/main/java/com/swordfish/touchinput/pads/GameBoyAdvancePad.kt b/retrograde-touchinput/src/main/java/com/swordfish/touchinput/pads/GameBoyAdvancePad.kt index a4634782..b0df437a 100644 --- a/retrograde-touchinput/src/main/java/com/swordfish/touchinput/pads/GameBoyAdvancePad.kt +++ b/retrograde-touchinput/src/main/java/com/swordfish/touchinput/pads/GameBoyAdvancePad.kt @@ -13,9 +13,10 @@ import com.swordfish.touchinput.views.SmallSingleButton import io.reactivex.Observable class GameBoyAdvancePad @JvmOverloads constructor( - context: Context, - attrs: AttributeSet? = null, - defStyleAttr: Int = 0) : BaseGamePad(context, attrs, defStyleAttr) { + context: Context, + attrs: AttributeSet? = null, + defStyleAttr: Int = 0 +) : BaseGamePad(context, attrs, defStyleAttr) { init { inflate(context, R.layout.layout_gba, this) @@ -31,37 +32,36 @@ class GameBoyAdvancePad @JvmOverloads constructor( getL1Events())) } - fun getStartEvent(): Observable { + private fun getStartEvent(): Observable { return findViewById(R.id.gba_start) - .getEvents() - .compose(EventsTransformers.singleButtonMap(KeyEvent.KEYCODE_BUTTON_START)) + .getEvents() + .compose(EventsTransformers.singleButtonMap(KeyEvent.KEYCODE_BUTTON_START)) } - fun getSelectEvent(): Observable { + private fun getSelectEvent(): Observable { return findViewById(R.id.gba_select) - .getEvents() - .compose(EventsTransformers.singleButtonMap(KeyEvent.KEYCODE_BUTTON_SELECT)) + .getEvents() + .compose(EventsTransformers.singleButtonMap(KeyEvent.KEYCODE_BUTTON_SELECT)) } - fun getActionEvents(): Observable { + private fun getActionEvents(): Observable { return findViewById(R.id.gba_actions) - .getEvents() - .compose(EventsTransformers.actionButtonsMap(KeyEvent.KEYCODE_B, KeyEvent.KEYCODE_A)) - + .getEvents() + .compose(EventsTransformers.actionButtonsMap(KeyEvent.KEYCODE_B, KeyEvent.KEYCODE_A)) } - fun getDirectionEvents(): Observable { + private fun getDirectionEvents(): Observable { return findViewById(R.id.gba_direction).getEvents() - .compose(EventsTransformers.directionPadMap()) + .compose(EventsTransformers.directionPadMap()) } - fun getL1Events(): Observable { + private fun getL1Events(): Observable { return findViewById(R.id.gba_l1).getEvents() - .compose(EventsTransformers.singleButtonMap(KeyEvent.KEYCODE_BUTTON_L1)) + .compose(EventsTransformers.singleButtonMap(KeyEvent.KEYCODE_BUTTON_L1)) } - fun getR1Events(): Observable { + private fun getR1Events(): Observable { return findViewById(R.id.gba_r1).getEvents() - .compose(EventsTransformers.singleButtonMap(KeyEvent.KEYCODE_BUTTON_R1)) + .compose(EventsTransformers.singleButtonMap(KeyEvent.KEYCODE_BUTTON_R1)) } } diff --git a/retrograde-touchinput/src/main/java/com/swordfish/touchinput/pads/GameBoyPad.kt b/retrograde-touchinput/src/main/java/com/swordfish/touchinput/pads/GameBoyPad.kt index d9e5febb..78f81737 100644 --- a/retrograde-touchinput/src/main/java/com/swordfish/touchinput/pads/GameBoyPad.kt +++ b/retrograde-touchinput/src/main/java/com/swordfish/touchinput/pads/GameBoyPad.kt @@ -12,9 +12,10 @@ import com.swordfish.touchinput.views.base.BaseSingleButton import io.reactivex.Observable class GameBoyPad @JvmOverloads constructor( - context: Context, - attrs: AttributeSet? = null, - defStyleAttr: Int = 0) : BaseGamePad(context, attrs, defStyleAttr) { + context: Context, + attrs: AttributeSet? = null, + defStyleAttr: Int = 0 +) : BaseGamePad(context, attrs, defStyleAttr) { init { inflate(context, R.layout.layout_gb, this) @@ -29,27 +30,26 @@ class GameBoyPad @JvmOverloads constructor( ) } - fun getStartEvent(): Observable { + private fun getStartEvent(): Observable { return findViewById(R.id.gb_start) - .getEvents() - .compose(EventsTransformers.singleButtonMap(KeyEvent.KEYCODE_BUTTON_START)) + .getEvents() + .compose(EventsTransformers.singleButtonMap(KeyEvent.KEYCODE_BUTTON_START)) } - fun getSelectEvent(): Observable { + private fun getSelectEvent(): Observable { return findViewById(R.id.gb_select) - .getEvents() - .compose(EventsTransformers.singleButtonMap(KeyEvent.KEYCODE_BUTTON_SELECT)) + .getEvents() + .compose(EventsTransformers.singleButtonMap(KeyEvent.KEYCODE_BUTTON_SELECT)) } - fun getActionEvents(): Observable { + private fun getActionEvents(): Observable { return findViewById(R.id.gb_actions) - .getEvents() - .compose(EventsTransformers.actionButtonsMap(KeyEvent.KEYCODE_B, KeyEvent.KEYCODE_A)) - + .getEvents() + .compose(EventsTransformers.actionButtonsMap(KeyEvent.KEYCODE_B, KeyEvent.KEYCODE_A)) } - fun getDirectionEvents(): Observable { + private fun getDirectionEvents(): Observable { return findViewById(R.id.gb_direction).getEvents() - .compose(EventsTransformers.directionPadMap()) + .compose(EventsTransformers.directionPadMap()) } } diff --git a/retrograde-touchinput/src/main/java/com/swordfish/touchinput/pads/GenesisPad.kt b/retrograde-touchinput/src/main/java/com/swordfish/touchinput/pads/GenesisPad.kt index 1aa43619..187e51bd 100644 --- a/retrograde-touchinput/src/main/java/com/swordfish/touchinput/pads/GenesisPad.kt +++ b/retrograde-touchinput/src/main/java/com/swordfish/touchinput/pads/GenesisPad.kt @@ -12,9 +12,10 @@ import com.swordfish.touchinput.views.base.BaseSingleButton import io.reactivex.Observable class GenesisPad @JvmOverloads constructor( - context: Context, - attrs: AttributeSet? = null, - defStyleAttr: Int = 0) : BaseGamePad(context, attrs, defStyleAttr) { + context: Context, + attrs: AttributeSet? = null, + defStyleAttr: Int = 0 +) : BaseGamePad(context, attrs, defStyleAttr) { init { inflate(context, R.layout.layout_genesis, this) @@ -22,27 +23,26 @@ class GenesisPad @JvmOverloads constructor( override fun getEvents(): Observable { return Observable.merge( - getStartEvent(), - getDirectionEvents(), - getActionEvents() + getStartEvent(), + getDirectionEvents(), + getActionEvents() ) } - fun getStartEvent(): Observable { + private fun getStartEvent(): Observable { return findViewById(R.id.genesis_start) - .getEvents() - .compose(EventsTransformers.singleButtonMap(KeyEvent.KEYCODE_BUTTON_START)) + .getEvents() + .compose(EventsTransformers.singleButtonMap(KeyEvent.KEYCODE_BUTTON_START)) } - fun getActionEvents(): Observable { + private fun getActionEvents(): Observable { return findViewById(R.id.genesis_actions) - .getEvents() - .compose(EventsTransformers.actionButtonsMap(KeyEvent.KEYCODE_A, KeyEvent.KEYCODE_B, KeyEvent.KEYCODE_C)) - + .getEvents() + .compose(EventsTransformers.actionButtonsMap(KeyEvent.KEYCODE_A, KeyEvent.KEYCODE_B, KeyEvent.KEYCODE_C)) } - fun getDirectionEvents(): Observable { + private fun getDirectionEvents(): Observable { return findViewById(R.id.genesis_direction).getEvents() - .compose(EventsTransformers.directionPadMap()) + .compose(EventsTransformers.directionPadMap()) } } diff --git a/retrograde-touchinput/src/main/java/com/swordfish/touchinput/views/ActionButtons.kt b/retrograde-touchinput/src/main/java/com/swordfish/touchinput/views/ActionButtons.kt index 34b0f8a5..06b7619a 100644 --- a/retrograde-touchinput/src/main/java/com/swordfish/touchinput/views/ActionButtons.kt +++ b/retrograde-touchinput/src/main/java/com/swordfish/touchinput/views/ActionButtons.kt @@ -1,5 +1,6 @@ package com.swordfish.touchinput.views +import android.annotation.SuppressLint import android.content.Context import android.content.res.TypedArray import android.graphics.Canvas @@ -23,7 +24,8 @@ import kotlin.math.sin class ActionButtons @JvmOverloads constructor( context: Context, attrs: AttributeSet? = null, - defStyleAttr: Int = 0) : View(context, attrs, defStyleAttr), ButtonEventsSource { + defStyleAttr: Int = 0 +) : View(context, attrs, defStyleAttr), ButtonEventsSource { private val events: PublishRelay = PublishRelay.create() @@ -126,6 +128,7 @@ class ActionButtons @JvmOverloads constructor( canvas.restore() } + @SuppressLint("ClickableViewAccessibility") override fun onTouchEvent(event: MotionEvent): Boolean { when (event.actionMasked) { MotionEvent.ACTION_DOWN, MotionEvent.ACTION_POINTER_DOWN, MotionEvent.ACTION_MOVE -> { diff --git a/retrograde-touchinput/src/main/java/com/swordfish/touchinput/views/DirectionPad.kt b/retrograde-touchinput/src/main/java/com/swordfish/touchinput/views/DirectionPad.kt index 325171b8..0af7a46b 100644 --- a/retrograde-touchinput/src/main/java/com/swordfish/touchinput/views/DirectionPad.kt +++ b/retrograde-touchinput/src/main/java/com/swordfish/touchinput/views/DirectionPad.kt @@ -1,5 +1,6 @@ package com.swordfish.touchinput.views +import android.annotation.SuppressLint import android.content.Context import android.content.res.TypedArray import android.graphics.Canvas @@ -20,11 +21,11 @@ import kotlin.math.cos import kotlin.math.floor import kotlin.math.sin - class DirectionPad @JvmOverloads constructor( - context: Context, - attrs: AttributeSet? = null, - defStyleAttr: Int = 0) : View(context, attrs, defStyleAttr), ButtonEventsSource { + context: Context, + attrs: AttributeSet? = null, + defStyleAttr: Int = 0 +) : View(context, attrs, defStyleAttr), ButtonEventsSource { companion object { @@ -113,6 +114,7 @@ class DirectionPad @JvmOverloads constructor( } } + @SuppressLint("ClickableViewAccessibility") override fun onTouchEvent(event: MotionEvent): Boolean { when (event.actionMasked) { MotionEvent.ACTION_DOWN, MotionEvent.ACTION_POINTER_DOWN, MotionEvent.ACTION_MOVE -> { diff --git a/retrograde-touchinput/src/main/java/com/swordfish/touchinput/views/LargeSingleButton.kt b/retrograde-touchinput/src/main/java/com/swordfish/touchinput/views/LargeSingleButton.kt index f38fec06..79e485a2 100644 --- a/retrograde-touchinput/src/main/java/com/swordfish/touchinput/views/LargeSingleButton.kt +++ b/retrograde-touchinput/src/main/java/com/swordfish/touchinput/views/LargeSingleButton.kt @@ -6,11 +6,12 @@ import com.swordfish.touchinput.controller.R import com.swordfish.touchinput.views.base.BaseSingleButton class LargeSingleButton @JvmOverloads constructor( - context: Context, - attrs: AttributeSet? = null, - defStyleAttr: Int = 0) : BaseSingleButton(context, attrs, defStyleAttr) { + context: Context, + attrs: AttributeSet? = null, + defStyleAttr: Int = 0 +) : BaseSingleButton(context, attrs, defStyleAttr) { init { setBackgroundResource(R.drawable.large_button_selector) } -} \ No newline at end of file +} diff --git a/retrograde-touchinput/src/main/java/com/swordfish/touchinput/views/SmallSingleButton.kt b/retrograde-touchinput/src/main/java/com/swordfish/touchinput/views/SmallSingleButton.kt index a8946174..5bce8e15 100644 --- a/retrograde-touchinput/src/main/java/com/swordfish/touchinput/views/SmallSingleButton.kt +++ b/retrograde-touchinput/src/main/java/com/swordfish/touchinput/views/SmallSingleButton.kt @@ -6,11 +6,12 @@ import com.swordfish.touchinput.controller.R import com.swordfish.touchinput.views.base.BaseSingleButton class SmallSingleButton @JvmOverloads constructor( - context: Context, - attrs: AttributeSet? = null, - defStyleAttr: Int = 0) : BaseSingleButton(context, attrs, defStyleAttr) { + context: Context, + attrs: AttributeSet? = null, + defStyleAttr: Int = 0 +) : BaseSingleButton(context, attrs, defStyleAttr) { init { setBackgroundResource(R.drawable.small_button_selector) } -} \ No newline at end of file +} diff --git a/retrograde-touchinput/src/main/java/com/swordfish/touchinput/views/base/BaseSingleButton.kt b/retrograde-touchinput/src/main/java/com/swordfish/touchinput/views/base/BaseSingleButton.kt index afe3ee06..4d474d5f 100644 --- a/retrograde-touchinput/src/main/java/com/swordfish/touchinput/views/base/BaseSingleButton.kt +++ b/retrograde-touchinput/src/main/java/com/swordfish/touchinput/views/base/BaseSingleButton.kt @@ -1,20 +1,20 @@ package com.swordfish.touchinput.views.base import android.content.Context +import android.support.v7.widget.AppCompatButton import android.util.AttributeSet import android.view.KeyEvent import android.view.MotionEvent -import android.widget.Button import com.jakewharton.rxrelay2.PublishRelay import com.swordfish.touchinput.data.ButtonEvent import com.swordfish.touchinput.interfaces.ButtonEventsSource import io.reactivex.Observable - abstract class BaseSingleButton @JvmOverloads constructor( - context: Context, - attrs: AttributeSet? = null, - defStyleAttr: Int = 0) : Button(context, attrs, defStyleAttr), ButtonEventsSource { + context: Context, + attrs: AttributeSet? = null, + defStyleAttr: Int = 0 +) : AppCompatButton(context, attrs, defStyleAttr), ButtonEventsSource { private val events: PublishRelay = PublishRelay.create() diff --git a/retrograde-touchinput/src/main/res/drawable/action_normal.xml b/retrograde-touchinput/src/main/res/drawable/action_normal.xml index e9b43746..d5dc0737 100644 --- a/retrograde-touchinput/src/main/res/drawable/action_normal.xml +++ b/retrograde-touchinput/src/main/res/drawable/action_normal.xml @@ -1,5 +1,5 @@ - - - \ No newline at end of file + + + diff --git a/retrograde-touchinput/src/main/res/drawable/action_pressed.xml b/retrograde-touchinput/src/main/res/drawable/action_pressed.xml index cd0a1de3..72373bab 100644 --- a/retrograde-touchinput/src/main/res/drawable/action_pressed.xml +++ b/retrograde-touchinput/src/main/res/drawable/action_pressed.xml @@ -1,5 +1,5 @@ - - - \ No newline at end of file + + + diff --git a/retrograde-touchinput/src/main/res/drawable/direction_down_normal.xml b/retrograde-touchinput/src/main/res/drawable/direction_down_normal.xml index 92382f1b..8b5405fc 100644 --- a/retrograde-touchinput/src/main/res/drawable/direction_down_normal.xml +++ b/retrograde-touchinput/src/main/res/drawable/direction_down_normal.xml @@ -1,12 +1,12 @@ + android:width="@dimen/size_direction_button_item" + android:height="@dimen/size_direction_button_item" + android:viewportHeight="@integer/item_viewportsize" + android:viewportWidth="@integer/item_viewportsize"> - - \ No newline at end of file + + diff --git a/retrograde-touchinput/src/main/res/drawable/direction_down_pressed.xml b/retrograde-touchinput/src/main/res/drawable/direction_down_pressed.xml index 3fe971d2..b5cc0ddc 100644 --- a/retrograde-touchinput/src/main/res/drawable/direction_down_pressed.xml +++ b/retrograde-touchinput/src/main/res/drawable/direction_down_pressed.xml @@ -1,11 +1,11 @@ + android:width="@dimen/size_direction_button_item" + android:height="@dimen/size_direction_button_item" + android:viewportHeight="@integer/item_viewportsize" + android:viewportWidth="@integer/item_viewportsize"> - - \ No newline at end of file + + diff --git a/retrograde-touchinput/src/main/res/drawable/direction_left_normal.xml b/retrograde-touchinput/src/main/res/drawable/direction_left_normal.xml index 422e4155..b9bc046a 100644 --- a/retrograde-touchinput/src/main/res/drawable/direction_left_normal.xml +++ b/retrograde-touchinput/src/main/res/drawable/direction_left_normal.xml @@ -1,12 +1,12 @@ + android:width="@dimen/size_direction_button_item" + android:height="@dimen/size_direction_button_item" + android:viewportHeight="@integer/item_viewportsize" + android:viewportWidth="@integer/item_viewportsize"> - - \ No newline at end of file + + diff --git a/retrograde-touchinput/src/main/res/drawable/direction_left_pressed.xml b/retrograde-touchinput/src/main/res/drawable/direction_left_pressed.xml index 1126be75..e7b1963d 100644 --- a/retrograde-touchinput/src/main/res/drawable/direction_left_pressed.xml +++ b/retrograde-touchinput/src/main/res/drawable/direction_left_pressed.xml @@ -1,11 +1,11 @@ + android:width="@dimen/size_direction_button_item" + android:height="@dimen/size_direction_button_item" + android:viewportHeight="@integer/item_viewportsize" + android:viewportWidth="@integer/item_viewportsize"> - - \ No newline at end of file + + diff --git a/retrograde-touchinput/src/main/res/drawable/direction_right_normal.xml b/retrograde-touchinput/src/main/res/drawable/direction_right_normal.xml index 921d3e5c..9017644e 100644 --- a/retrograde-touchinput/src/main/res/drawable/direction_right_normal.xml +++ b/retrograde-touchinput/src/main/res/drawable/direction_right_normal.xml @@ -1,12 +1,12 @@ + android:width="@dimen/size_direction_button_item" + android:height="@dimen/size_direction_button_item" + android:viewportHeight="@integer/item_viewportsize" + android:viewportWidth="@integer/item_viewportsize"> - - \ No newline at end of file + + diff --git a/retrograde-touchinput/src/main/res/drawable/direction_right_pressed.xml b/retrograde-touchinput/src/main/res/drawable/direction_right_pressed.xml index 10b24cb5..07cd6d37 100644 --- a/retrograde-touchinput/src/main/res/drawable/direction_right_pressed.xml +++ b/retrograde-touchinput/src/main/res/drawable/direction_right_pressed.xml @@ -1,11 +1,11 @@ + android:width="@dimen/size_direction_button_item" + android:height="@dimen/size_direction_button_item" + android:viewportHeight="@integer/item_viewportsize" + android:viewportWidth="@integer/item_viewportsize"> - - \ No newline at end of file + + diff --git a/retrograde-touchinput/src/main/res/drawable/direction_up_normal.xml b/retrograde-touchinput/src/main/res/drawable/direction_up_normal.xml index 9875aba1..87a6dc64 100644 --- a/retrograde-touchinput/src/main/res/drawable/direction_up_normal.xml +++ b/retrograde-touchinput/src/main/res/drawable/direction_up_normal.xml @@ -1,12 +1,12 @@ + android:width="@dimen/size_direction_button_item" + android:height="@dimen/size_direction_button_item" + android:viewportHeight="@integer/item_viewportsize" + android:viewportWidth="@integer/item_viewportsize"> - - \ No newline at end of file + + diff --git a/retrograde-touchinput/src/main/res/drawable/direction_up_pressed.xml b/retrograde-touchinput/src/main/res/drawable/direction_up_pressed.xml index b8d7d049..29673bfa 100644 --- a/retrograde-touchinput/src/main/res/drawable/direction_up_pressed.xml +++ b/retrograde-touchinput/src/main/res/drawable/direction_up_pressed.xml @@ -1,11 +1,11 @@ + android:width="@dimen/size_direction_button_item" + android:height="@dimen/size_direction_button_item" + android:viewportHeight="@integer/item_viewportsize" + android:viewportWidth="@integer/item_viewportsize"> - - \ No newline at end of file + + diff --git a/retrograde-touchinput/src/main/res/drawable/large_button_normal.xml b/retrograde-touchinput/src/main/res/drawable/large_button_normal.xml index 14d12ec2..7fef53eb 100644 --- a/retrograde-touchinput/src/main/res/drawable/large_button_normal.xml +++ b/retrograde-touchinput/src/main/res/drawable/large_button_normal.xml @@ -2,4 +2,4 @@ - \ No newline at end of file + diff --git a/retrograde-touchinput/src/main/res/drawable/large_button_pressed.xml b/retrograde-touchinput/src/main/res/drawable/large_button_pressed.xml index 9b6038ca..8e84185c 100644 --- a/retrograde-touchinput/src/main/res/drawable/large_button_pressed.xml +++ b/retrograde-touchinput/src/main/res/drawable/large_button_pressed.xml @@ -2,4 +2,4 @@ - \ No newline at end of file + diff --git a/retrograde-touchinput/src/main/res/drawable/large_button_selector.xml b/retrograde-touchinput/src/main/res/drawable/large_button_selector.xml index 3f36b6fe..17fd6d87 100644 --- a/retrograde-touchinput/src/main/res/drawable/large_button_selector.xml +++ b/retrograde-touchinput/src/main/res/drawable/large_button_selector.xml @@ -2,4 +2,4 @@ - \ No newline at end of file + diff --git a/retrograde-touchinput/src/main/res/drawable/small_button_normal.xml b/retrograde-touchinput/src/main/res/drawable/small_button_normal.xml index cd268e78..9b8c998c 100644 --- a/retrograde-touchinput/src/main/res/drawable/small_button_normal.xml +++ b/retrograde-touchinput/src/main/res/drawable/small_button_normal.xml @@ -2,4 +2,4 @@ - \ No newline at end of file + diff --git a/retrograde-touchinput/src/main/res/drawable/small_button_pressed.xml b/retrograde-touchinput/src/main/res/drawable/small_button_pressed.xml index 07d9670f..0526ba8a 100644 --- a/retrograde-touchinput/src/main/res/drawable/small_button_pressed.xml +++ b/retrograde-touchinput/src/main/res/drawable/small_button_pressed.xml @@ -2,4 +2,4 @@ - \ No newline at end of file + diff --git a/retrograde-touchinput/src/main/res/drawable/small_button_selector.xml b/retrograde-touchinput/src/main/res/drawable/small_button_selector.xml index 9d62d823..767c21d8 100644 --- a/retrograde-touchinput/src/main/res/drawable/small_button_selector.xml +++ b/retrograde-touchinput/src/main/res/drawable/small_button_selector.xml @@ -2,4 +2,4 @@ - \ No newline at end of file + diff --git a/retrograde-touchinput/src/main/res/layout/layout_gb.xml b/retrograde-touchinput/src/main/res/layout/layout_gb.xml index cd716a3e..932e7c65 100644 --- a/retrograde-touchinput/src/main/res/layout/layout_gb.xml +++ b/retrograde-touchinput/src/main/res/layout/layout_gb.xml @@ -29,7 +29,8 @@ android:layout_marginRight="16dp" android:layout_marginBottom="16dp" app:layout_constraintBottom_toBottomOf="parent" - app:layout_constraintEnd_toEndOf="parent" /> + app:layout_constraintEnd_toEndOf="parent" + tools:ignore="RtlHardcoded" /> - \ No newline at end of file + diff --git a/retrograde-touchinput/src/main/res/layout/layout_gba.xml b/retrograde-touchinput/src/main/res/layout/layout_gba.xml index 65acb0ef..4825c274 100644 --- a/retrograde-touchinput/src/main/res/layout/layout_gba.xml +++ b/retrograde-touchinput/src/main/res/layout/layout_gba.xml @@ -1,6 +1,7 @@ @@ -8,7 +9,6 @@ android:id="@+id/gba_r1" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:layout_marginEnd="16dp" android:layout_marginRight="16dp" android:layout_marginBottom="16dp" app:layout_constraintBottom_toTopOf="@+id/gba_actions" @@ -34,7 +34,6 @@ android:id="@+id/gba_l1" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:layout_marginStart="16dp" android:layout_marginLeft="16dp" android:layout_marginBottom="16dp" app:layout_constraintBottom_toTopOf="@+id/gba_direction" @@ -45,20 +44,19 @@ style="@style/default_action_2" android:layout_width="@dimen/size_dial" android:layout_height="@dimen/size_dial" - android:layout_marginEnd="16dp" android:layout_marginRight="16dp" android:layout_marginBottom="16dp" app:layout_constraintBottom_toBottomOf="parent" - app:layout_constraintEnd_toEndOf="parent" /> + app:layout_constraintEnd_toEndOf="parent" + tools:ignore="RtlHardcoded" /> - \ No newline at end of file + diff --git a/retrograde-touchinput/src/main/res/layout/layout_genesis.xml b/retrograde-touchinput/src/main/res/layout/layout_genesis.xml index 1fc3e34a..d3b5f540 100644 --- a/retrograde-touchinput/src/main/res/layout/layout_genesis.xml +++ b/retrograde-touchinput/src/main/res/layout/layout_genesis.xml @@ -17,7 +17,6 @@ style="@style/default_action_3" android:layout_width="@dimen/size_dial" android:layout_height="@dimen/size_dial" - android:layout_marginEnd="16dp" android:layout_marginRight="16dp" android:layout_marginBottom="16dp" app:layout_constraintBottom_toBottomOf="parent" @@ -27,10 +26,10 @@ android:id="@+id/genesis_direction" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:layout_marginStart="16dp" android:layout_marginLeft="16dp" android:layout_marginBottom="16dp" app:layout_constraintBottom_toBottomOf="parent" - app:layout_constraintStart_toStartOf="parent" /> + app:layout_constraintStart_toStartOf="parent" + tools:ignore="RtlHardcoded" /> - \ No newline at end of file + diff --git a/retrograde-touchinput/src/main/res/values/colors.xml b/retrograde-touchinput/src/main/res/values/colors.xml index 1740b8ac..eb93eb17 100644 --- a/retrograde-touchinput/src/main/res/values/colors.xml +++ b/retrograde-touchinput/src/main/res/values/colors.xml @@ -1,4 +1,4 @@ #7fff - \ No newline at end of file + diff --git a/retrograde-touchinput/src/main/res/values/default_styles.xml b/retrograde-touchinput/src/main/res/values/default_styles.xml index 3f3f0c7e..15d4f627 100644 --- a/retrograde-touchinput/src/main/res/values/default_styles.xml +++ b/retrograde-touchinput/src/main/res/values/default_styles.xml @@ -26,4 +26,4 @@ 0.3 0.45 - \ No newline at end of file + diff --git a/retrograde-touchinput/src/main/res/values/dimen.xml b/retrograde-touchinput/src/main/res/values/dimen.xml index be14876f..2640c0e2 100644 --- a/retrograde-touchinput/src/main/res/values/dimen.xml +++ b/retrograde-touchinput/src/main/res/values/dimen.xml @@ -18,4 +18,4 @@ 2 30 - \ No newline at end of file + diff --git a/retrograde-touchinput/src/main/res/values/input_attrs.xml b/retrograde-touchinput/src/main/res/values/input_attrs.xml index 3b128687..aa6147fb 100644 --- a/retrograde-touchinput/src/main/res/values/input_attrs.xml +++ b/retrograde-touchinput/src/main/res/values/input_attrs.xml @@ -13,4 +13,4 @@ - \ No newline at end of file + diff --git a/retrograde-touchinput/src/main/res/values/strings.xml b/retrograde-touchinput/src/main/res/values/strings.xml index 8f48227e..04330e08 100644 --- a/retrograde-touchinput/src/main/res/values/strings.xml +++ b/retrograde-touchinput/src/main/res/values/strings.xml @@ -4,3 +4,4 @@ M1,15 m2,-2 l8,-8 l14,0 a17,17 0 0,1 0,20 l-14,0 l-8,-8 a3,3 0 0,1 0,-4z M29,15 m-2,-2 l-8,-8 l-14,0 a17,17 0 0,0 0,20 l14,0 l8,-8 a3,3 0 0,0 0,-4z +