Send DPad Input to Session on Android

This commit is contained in:
Florian Märkl 2019-09-28 19:57:18 +02:00
commit 884333ed65
No known key found for this signature in database
GPG key ID: 125BC8A5A6A1E857
10 changed files with 152 additions and 56 deletions

View file

@ -258,12 +258,12 @@ JNIEXPORT void JNICALL Java_com_metallic_chiaki_lib_ChiakiNative_sessionCreate(J
jclass controller_state_class = E->FindClass(env, "com/metallic/chiaki/lib/ControllerState");
session->java_controller_state_buttons = E->GetFieldID(env, controller_state_class, "buttons", "I");
session->java_controller_state_l2_state = E->GetFieldID(env, controller_state_class, "l2_state", "B");
session->java_controller_state_r2_state = E->GetFieldID(env, controller_state_class, "r2_state", "B");
session->java_controller_state_left_x = E->GetFieldID(env, controller_state_class, "left_x", "S");
session->java_controller_state_left_y = E->GetFieldID(env, controller_state_class, "left_y", "S");
session->java_controller_state_right_x = E->GetFieldID(env, controller_state_class, "right_x", "S");
session->java_controller_state_right_y = E->GetFieldID(env, controller_state_class, "right_y", "S");
session->java_controller_state_l2_state = E->GetFieldID(env, controller_state_class, "l2State", "B");
session->java_controller_state_r2_state = E->GetFieldID(env, controller_state_class, "r2State", "B");
session->java_controller_state_left_x = E->GetFieldID(env, controller_state_class, "leftX", "S");
session->java_controller_state_left_y = E->GetFieldID(env, controller_state_class, "leftY", "S");
session->java_controller_state_right_x = E->GetFieldID(env, controller_state_class, "rightX", "S");
session->java_controller_state_right_y = E->GetFieldID(env, controller_state_class, "rightY", "S");
chiaki_session_set_event_cb(&session->session, android_chiaki_event_cb, session);
chiaki_session_set_video_sample_cb(&session->session, android_chiaki_video_decoder_video_sample, &session->video_decoder);

View file

@ -32,6 +32,7 @@ data class StreamStateCreateError(val error: SessionCreateError): StreamState()
data class StreamStateQuit(val reason: QuitReason, val reasonString: String?): StreamState()
data class StreamStateLoginPinRequest(val pinIncorrect: Boolean): StreamState()
@ExperimentalUnsignedTypes
class StreamSession(val connectInfo: ConnectInfo)
{
var session: Session? = null
@ -40,8 +41,8 @@ class StreamSession(val connectInfo: ConnectInfo)
private val _state = MutableLiveData<StreamState>(StreamStateIdle)
val state: LiveData<StreamState> get() = _state
@ExperimentalUnsignedTypes
private val controllerState = ControllerState()
private var touchControllerState = ControllerState()
var surfaceTexture: SurfaceTexture? = null
@ -147,8 +148,18 @@ class StreamSession(val connectInfo: ConnectInfo)
}
}
session?.setControllerState(controllerState)
sendControllerState()
return true
}
fun updateTouchControllerState(controllerState: ControllerState)
{
touchControllerState = controllerState
sendControllerState()
}
private fun sendControllerState()
{
session?.setControllerState(controllerState or touchControllerState)
}
}

View file

@ -1,10 +1,10 @@
package com.metallic.chiaki.lib
import android.os.Parcelable
import android.util.Log
import android.view.Surface
import kotlinx.android.parcel.Parcelize
import java.lang.Exception
import kotlin.math.abs
@Parcelize
data class ConnectVideoProfile(
@ -49,14 +49,17 @@ class ErrorCode(val value: Int)
var isSuccess = value == 0
}
data class ControllerState @ExperimentalUnsignedTypes constructor(
private fun maxAbs(a: Short, b: Short) = if(abs(a.toInt()) > abs(b.toInt())) a else b
@ExperimentalUnsignedTypes
data class ControllerState constructor(
var buttons: UInt = 0U,
var l2_state: UByte = 0U,
var r2_state: UByte = 0U,
var left_x: Short = 0,
var left_y: Short = 0,
var right_x: Short = 0,
var right_y: Short = 0
var l2State: UByte = 0U,
var r2State: UByte = 0U,
var leftX: Short = 0,
var leftY: Short = 0,
var rightX: Short = 0,
var rightY: Short = 0
){
companion object
{
@ -77,6 +80,16 @@ data class ControllerState @ExperimentalUnsignedTypes constructor(
val BUTTON_TOUCHPAD = (1 shl 14).toUInt()
val BUTTON_PS = (1 shl 15).toUInt()
}
infix fun or(o: ControllerState) = ControllerState(
buttons = buttons or o.buttons,
l2State = maxOf(l2State, o.l2State),
r2State = maxOf(r2State, o.r2State),
leftX = maxAbs(leftX, o.leftX),
leftY = maxAbs(leftY, o.leftY),
rightX = maxAbs(rightX, o.rightX),
rightY = maxAbs(rightY, o.rightY)
)
}
class QuitReason(val value: Int)

View file

@ -19,15 +19,17 @@ package com.metallic.chiaki.stream
import android.graphics.Matrix
import android.os.Bundle
import android.util.Log
import android.view.KeyEvent
import android.view.View
import androidx.appcompat.app.AppCompatActivity
import androidx.fragment.app.Fragment
import androidx.lifecycle.*
import com.metallic.chiaki.R
import com.metallic.chiaki.lib.ConnectInfo
import com.metallic.chiaki.touchcontrols.TouchControlsFragment
import kotlinx.android.synthetic.main.activity_stream.*
@ExperimentalUnsignedTypes
class StreamActivity : AppCompatActivity()
{
companion object
@ -40,7 +42,6 @@ class StreamActivity : AppCompatActivity()
override fun onCreate(savedInstanceState: Bundle?)
{
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_stream)
viewModel = ViewModelProviders.of(this)[StreamViewModel::class.java]
if(!viewModel.isInitialized)
@ -54,6 +55,8 @@ class StreamActivity : AppCompatActivity()
viewModel.init(connectInfo)
}
setContentView(R.layout.activity_stream)
viewModel.session.attachToTextureView(textureView)
viewModel.session.state.observe(this, Observer {
@ -65,6 +68,13 @@ class StreamActivity : AppCompatActivity()
}
}
@ExperimentalUnsignedTypes
override fun onAttachFragment(fragment: Fragment)
{
super.onAttachFragment(fragment)
(fragment as? TouchControlsFragment)?.controllerStateCallback = viewModel.session::updateTouchControllerState
}
override fun onResume()
{
super.onResume()

View file

@ -37,6 +37,8 @@ class DPadView @JvmOverloads constructor(
var state: Direction? = null
private set
var stateChangeCallback: ((Direction?) -> Unit)? = null
/**
* Radius (as a fraction of the entire DPad Radius)
* to be used as a deadzone in the center on move events
@ -69,7 +71,7 @@ class DPadView @JvmOverloads constructor(
drawable = dpadIdleDrawable
drawable?.setBounds(0, 0, width, height)
drawable?.alpha = 127
//drawable?.alpha = 127
drawable?.draw(canvas)
}
@ -106,7 +108,7 @@ class DPadView @JvmOverloads constructor(
{
state = newState
invalidate()
// TODO: callback
stateChangeCallback?.let { it(state) }
}
}

View file

@ -0,0 +1,70 @@
/*
* This file is part of Chiaki.
*
* Chiaki is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Chiaki is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Chiaki. If not, see <https://www.gnu.org/licenses/>.
*/
package com.metallic.chiaki.touchcontrols
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.Fragment
import com.metallic.chiaki.R
import com.metallic.chiaki.lib.ControllerState
import kotlinx.android.synthetic.main.fragment_controls.*
@ExperimentalUnsignedTypes
class TouchControlsFragment : Fragment()
{
var controllerState = ControllerState()
private set(value)
{
val diff = field != value
field = value
if(diff)
controllerStateCallback?.let { it(value) }
}
var controllerStateCallback: ((ControllerState) -> Unit)? = null
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View
= inflater.inflate(R.layout.fragment_controls, container, false)
override fun onViewCreated(view: View, savedInstanceState: Bundle?)
{
super.onViewCreated(view, savedInstanceState)
dpadView.stateChangeCallback = this::dpadStateChanged
}
private fun dpadStateChanged(direction: DPadView.Direction?)
{
controllerState = controllerState.copy().apply {
buttons = ((buttons
and ControllerState.BUTTON_DPAD_LEFT.inv()
and ControllerState.BUTTON_DPAD_RIGHT.inv()
and ControllerState.BUTTON_DPAD_UP.inv()
and ControllerState.BUTTON_DPAD_DOWN.inv())
or when(direction)
{
DPadView.Direction.UP -> ControllerState.BUTTON_DPAD_UP
DPadView.Direction.DOWN -> ControllerState.BUTTON_DPAD_DOWN
DPadView.Direction.LEFT -> ControllerState.BUTTON_DPAD_LEFT
DPadView.Direction.RIGHT -> ControllerState.BUTTON_DPAD_RIGHT
null -> 0U
})
}
}
}

View file

@ -51,20 +51,4 @@
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="@+id/morningEditText" />
<com.metallic.chiaki.touchcontrols.DPadView
android:layout_width="200dp"
android:layout_height="200dp"
android:layout_marginTop="32dp"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<com.metallic.chiaki.touchcontrols.DPadView
android:layout_width="100dp"
android:layout_height="100dp"
android:layout_marginBottom="32dp"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintBottom_toBottomOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>

View file

@ -17,24 +17,10 @@
android:layout_height="wrap_content"
app:layout_constraintBottom_toBottomOf="parent"/>
<com.metallic.chiaki.touchcontrols.ControlsBackgroundView
<fragment
android:id="@+id/controlsFragment"
android:name="com.metallic.chiaki.touchcontrols.TouchControlsFragment"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<com.metallic.chiaki.touchcontrols.DPadView
android:layout_width="100dp"
android:layout_height="100dp"
android:layout_marginLeft="32dp"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent" />
<com.metallic.chiaki.touchcontrols.DPadView
android:layout_width="100dp"
android:layout_height="100dp"
android:layout_marginRight="32dp"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>

View file

@ -0,0 +1,20 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:app="http://schemas.android.com/apk/res-auto">
<com.metallic.chiaki.touchcontrols.ControlsBackgroundView
android:layout_width="match_parent"
android:layout_height="match_parent" />
<com.metallic.chiaki.touchcontrols.DPadView
android:id="@+id/dpadView"
android:layout_width="130dp"
android:layout_height="130dp"
android:layout_marginLeft="32dp"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>

View file

@ -7,6 +7,6 @@
<color name="stream_text">@android:color/white</color>
<color name="stream_background">@android:color/black</color>
<color name="control_primary">@android:color/white</color>
<color name="control_pressed">#8888ff</color>
<color name="control_primary">#44ffffff</color>
<color name="control_pressed">#88ffffff</color>
</resources>