mirror of
https://git.sr.ht/~thestr4ng3r/chiaki
synced 2025-08-21 05:53:12 -07:00
Propagate Touchpad State through TouchControlsFragment on Android
This commit is contained in:
parent
5914ceec77
commit
fa44a3269c
4 changed files with 56 additions and 20 deletions
|
@ -24,6 +24,8 @@ import com.metallic.chiaki.lib.ConnectVideoProfile
|
|||
import com.metallic.chiaki.session.*
|
||||
import com.metallic.chiaki.touchcontrols.TouchControlsFragment
|
||||
import com.metallic.chiaki.touchcontrols.TouchpadOnlyFragment
|
||||
import io.reactivex.disposables.CompositeDisposable
|
||||
import io.reactivex.rxkotlin.addTo
|
||||
import kotlin.math.min
|
||||
|
||||
private sealed class DialogContents
|
||||
|
@ -113,18 +115,25 @@ class StreamActivity : AppCompatActivity(), View.OnSystemUiVisibilityChangeListe
|
|||
}
|
||||
}
|
||||
|
||||
private val controlsDisposable = CompositeDisposable()
|
||||
|
||||
override fun onAttachFragment(fragment: Fragment)
|
||||
{
|
||||
super.onAttachFragment(fragment)
|
||||
if(fragment is TouchControlsFragment)
|
||||
when(fragment)
|
||||
{
|
||||
fragment.controllerStateCallback = { viewModel.input.touchControllerState = it }
|
||||
fragment.onScreenControlsEnabled = viewModel.onScreenControlsEnabled
|
||||
}
|
||||
if(fragment is TouchpadOnlyFragment)
|
||||
{
|
||||
fragment.controllerStateCallback = { viewModel.input.touchControllerState = it }
|
||||
fragment.touchpadOnlyEnabled = viewModel.touchpadOnlyEnabled
|
||||
is TouchControlsFragment ->
|
||||
{
|
||||
fragment.controllerState
|
||||
.subscribe { viewModel.input.touchControllerState = it }
|
||||
.addTo(controlsDisposable)
|
||||
fragment.onScreenControlsEnabled = viewModel.onScreenControlsEnabled
|
||||
}
|
||||
is TouchpadOnlyFragment ->
|
||||
{
|
||||
fragment.controllerStateCallback = { viewModel.input.touchControllerState = it }
|
||||
fragment.touchpadOnlyEnabled = viewModel.touchpadOnlyEnabled
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -141,6 +150,12 @@ class StreamActivity : AppCompatActivity(), View.OnSystemUiVisibilityChangeListe
|
|||
viewModel.session.pause()
|
||||
}
|
||||
|
||||
override fun onDestroy()
|
||||
{
|
||||
super.onDestroy()
|
||||
controlsDisposable.dispose()
|
||||
}
|
||||
|
||||
private fun reconnect()
|
||||
{
|
||||
viewModel.session.shutdown()
|
||||
|
|
|
@ -11,19 +11,31 @@ import androidx.lifecycle.LiveData
|
|||
import androidx.lifecycle.Observer
|
||||
import com.metallic.chiaki.databinding.FragmentControlsBinding
|
||||
import com.metallic.chiaki.lib.ControllerState
|
||||
import io.reactivex.Observable
|
||||
import io.reactivex.Observable.combineLatest
|
||||
import io.reactivex.subjects.BehaviorSubject
|
||||
import io.reactivex.subjects.Subject
|
||||
|
||||
class TouchControlsFragment : Fragment()
|
||||
{
|
||||
private var controllerState = ControllerState()
|
||||
private var ownControllerState = ControllerState()
|
||||
private set(value)
|
||||
{
|
||||
val diff = field != value
|
||||
field = value
|
||||
if(diff)
|
||||
controllerStateCallback?.let { it(value) }
|
||||
ownControllerStateSubject.onNext(ownControllerState)
|
||||
}
|
||||
|
||||
var controllerStateCallback: ((ControllerState) -> Unit)? = null
|
||||
private val ownControllerStateSubject: Subject<ControllerState>
|
||||
= BehaviorSubject.create<ControllerState>().also { it.onNext(ownControllerState) }
|
||||
|
||||
// to delay attaching to the touchpadView until it's available
|
||||
private val controllerStateProxy: Subject<Observable<ControllerState>>
|
||||
= BehaviorSubject.create<Observable<ControllerState>>().also { it.onNext(ownControllerStateSubject) }
|
||||
val controllerState: Observable<ControllerState> get() =
|
||||
controllerStateProxy.flatMap { it }
|
||||
|
||||
var onScreenControlsEnabled: LiveData<Boolean>? = null
|
||||
|
||||
private var _binding: FragmentControlsBinding? = null
|
||||
|
@ -32,6 +44,9 @@ class TouchControlsFragment : Fragment()
|
|||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View =
|
||||
FragmentControlsBinding.inflate(inflater, container, false).let {
|
||||
_binding = it
|
||||
controllerStateProxy.onNext(
|
||||
combineLatest(ownControllerStateSubject, binding.touchpadView.controllerState) { a, b -> a or b }
|
||||
)
|
||||
it.root
|
||||
}
|
||||
|
||||
|
@ -52,19 +67,19 @@ class TouchControlsFragment : Fragment()
|
|||
binding.psButtonView.buttonPressedCallback = buttonStateChanged(ControllerState.BUTTON_PS)
|
||||
binding.touchpadButtonView.buttonPressedCallback = buttonStateChanged(ControllerState.BUTTON_TOUCHPAD)
|
||||
|
||||
binding.l2ButtonView.buttonPressedCallback = { controllerState = controllerState.copy().apply { l2State = if(it) 255U else 0U } }
|
||||
binding.r2ButtonView.buttonPressedCallback = { controllerState = controllerState.copy().apply { r2State = if(it) 255U else 0U } }
|
||||
binding.l2ButtonView.buttonPressedCallback = { ownControllerState = ownControllerState.copy().apply { l2State = if(it) 255U else 0U } }
|
||||
binding.r2ButtonView.buttonPressedCallback = { ownControllerState = ownControllerState.copy().apply { r2State = if(it) 255U else 0U } }
|
||||
|
||||
val quantizeStick = { f: Float ->
|
||||
(Short.MAX_VALUE * f).toInt().toShort()
|
||||
}
|
||||
|
||||
binding.leftAnalogStickView.stateChangedCallback = { controllerState = controllerState.copy().apply {
|
||||
binding.leftAnalogStickView.stateChangedCallback = { ownControllerState = ownControllerState.copy().apply {
|
||||
leftX = quantizeStick(it.x)
|
||||
leftY = quantizeStick(it.y)
|
||||
}}
|
||||
|
||||
binding.rightAnalogStickView.stateChangedCallback = { controllerState = controllerState.copy().apply {
|
||||
binding.rightAnalogStickView.stateChangedCallback = { ownControllerState = ownControllerState.copy().apply {
|
||||
rightX = quantizeStick(it.x)
|
||||
rightY = quantizeStick(it.y)
|
||||
}}
|
||||
|
@ -76,7 +91,7 @@ class TouchControlsFragment : Fragment()
|
|||
|
||||
private fun dpadStateChanged(direction: DPadView.Direction?)
|
||||
{
|
||||
controllerState = controllerState.copy().apply {
|
||||
ownControllerState = ownControllerState.copy().apply {
|
||||
buttons = ((buttons
|
||||
and ControllerState.BUTTON_DPAD_LEFT.inv()
|
||||
and ControllerState.BUTTON_DPAD_RIGHT.inv()
|
||||
|
@ -98,7 +113,7 @@ class TouchControlsFragment : Fragment()
|
|||
}
|
||||
|
||||
private fun buttonStateChanged(buttonMask: UInt) = { pressed: Boolean ->
|
||||
controllerState = controllerState.copy().apply {
|
||||
ownControllerState = ownControllerState.copy().apply {
|
||||
buttons =
|
||||
if(pressed)
|
||||
buttons or buttonMask
|
||||
|
|
|
@ -10,15 +10,20 @@ import android.view.MotionEvent
|
|||
import android.view.View
|
||||
import com.metallic.chiaki.R
|
||||
import com.metallic.chiaki.lib.ControllerState
|
||||
import io.reactivex.Observable
|
||||
import io.reactivex.subjects.BehaviorSubject
|
||||
import io.reactivex.subjects.Subject
|
||||
|
||||
class TouchpadView @JvmOverloads constructor(
|
||||
context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0
|
||||
) : View(context, attrs, defStyleAttr)
|
||||
{
|
||||
val state: ControllerState = ControllerState()
|
||||
private val state: ControllerState = ControllerState()
|
||||
private val pointerTouchIds = mutableMapOf<Int, UByte>()
|
||||
|
||||
var stateChangeCallback: ((ControllerState) -> Unit)? = null
|
||||
private val stateSubject: Subject<ControllerState>
|
||||
= BehaviorSubject.create<ControllerState>().also { it.onNext(state) }
|
||||
val controllerState: Observable<ControllerState> get() = stateSubject
|
||||
|
||||
private val drawable: Drawable?
|
||||
|
||||
|
@ -81,6 +86,6 @@ class TouchpadView @JvmOverloads constructor(
|
|||
|
||||
private fun triggerStateChanged()
|
||||
{
|
||||
stateChangeCallback?.let { it(state) }
|
||||
stateSubject.onNext(state)
|
||||
}
|
||||
}
|
|
@ -48,6 +48,7 @@
|
|||
/>
|
||||
|
||||
<com.metallic.chiaki.touchcontrols.TouchpadView
|
||||
android:id="@+id/touchpadView"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="0dp"
|
||||
app:drawable="@drawable/control_touchpad"
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue