done context menu, and fix controllers in wsa

This commit is contained in:
2023-12-28 00:12:03 +03:00
parent 66d4c573db
commit 9a26865269
9 changed files with 238 additions and 202 deletions
@@ -5,38 +5,25 @@ import android.app.AlertDialog
import android.content.DialogInterface
import android.content.Intent
import android.content.pm.ActivityInfo
import android.graphics.BitmapFactory
import android.hardware.SensorManager
import android.hardware.input.InputManager
import android.media.AudioManager
import android.opengl.GLES20
import android.opengl.GLUtils
import android.os.Build
import android.os.Bundle
import android.os.PowerManager
import android.os.PowerManager.WakeLock
import android.util.DisplayMetrics
import android.util.Log
import android.view.InputDevice
import android.view.KeyEvent
import android.view.MotionEvent
import android.view.inputmethod.InputMethodManager
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.lifecycle.Lifecycle
import com.bda.controller.StateEvent
import com.ea.EAIO.EAIO
import com.ea.EAMIO.StorageDirectory
import com.ea.easp.EASPHandler
import com.ea.games.nfs13_na.BuildConfig
import com.ea.games.nfs13_na.R
import com.ea.nimble.ApplicationLifecycle
import com.megboyzz.actionForAllControllers
import com.megboyzz.androidKeyEventToBda
import com.megboyzz.androidMotionEventToBda
import com.megboyzz.createConnectEvent
import com.megboyzz.createDisconnectEvent
import com.megboyzz.registerControllerHandlers
import java.io.BufferedReader
import java.io.File
import java.io.FileReader
@@ -299,23 +286,20 @@ class GameActivity : ComponentActivity(), DrawFrameListener {
ApplicationLifecycle.onActivityResult(requestCode, resultCode, data, this)
}
override fun onBackPressed() {
//ApplicationLifecycle.onBackPressed()
}
public override fun onCreate(bundle: Bundle?) {
super.onCreate(bundle)
registerControllerHandlers(
MogaController.registerControllerHandlers(
context = baseContext,
onInputDeviceAdded = {
Log.i("Controller", "controller is connected!")
val event = createConnectEvent(it)
val event = MogaController.createConnectEvent(it)
MogaController.nativeOnStateEvent(event)
},
onInputDeviceRemoved = {
Log.i("Controller", "controller is disconnected!")
val event = createDisconnectEvent(it)
val event = MogaController.createDisconnectEvent(it)
MogaController.nativeOnStateEvent(event)
},
onInputDeviceChanged = {
@@ -393,7 +377,8 @@ class GameActivity : ComponentActivity(), DrawFrameListener {
override fun dispatchGenericMotionEvent(ev: MotionEvent?): Boolean {
Log.i("GameActivity", ev.toString())
MogaController.onMotionEvent(androidMotionEventToBda(ev!!))
if (MogaController.deviceIsController(ev?.deviceId!!))
MogaController.onMotionEvent(MogaController.androidMotionEventToBda(ev))
return super.dispatchGenericMotionEvent(ev)
}
@@ -401,7 +386,8 @@ class GameActivity : ComponentActivity(), DrawFrameListener {
@SuppressLint("RestrictedApi")
override fun dispatchKeyEvent(event: KeyEvent?): Boolean {
MogaController.onKeyEvent(androidKeyEventToBda(event!!))
if (MogaController.deviceIsController(event?.deviceId!!))
MogaController.onKeyEvent(MogaController.androidKeyEventToBda(event))
return super.dispatchKeyEvent(event)
}
@@ -409,8 +395,6 @@ class GameActivity : ComponentActivity(), DrawFrameListener {
override fun onDrawFrame(gl10: GL10) {
//InputDevice.getDeviceIds()
//InputDevice.getDevice(0).sources
Log.d(this.localClassName, "onDrawFrame state=$state")
var isStarted = false
when (state) {
@@ -522,8 +506,8 @@ class GameActivity : ComponentActivity(), DrawFrameListener {
gameGLSurfaceView.onResume()
ApplicationLifecycle.onActivityResume(this)
nativeOnResume()
actionForAllControllers {
val event = createConnectEvent(it)
MogaController.doForAllControllers {
val event = MogaController.createConnectEvent(it)
MogaController.nativeOnStateEvent(event)
}
}
@@ -1,5 +1,10 @@
package com.ea.ironmonkey
import android.content.Context
import android.hardware.input.InputManager
import android.util.Log
import android.view.InputDevice
import androidx.activity.ComponentActivity
import com.bda.controller.ControllerListener
import com.bda.controller.KeyEvent
import com.bda.controller.MotionEvent
@@ -19,4 +24,94 @@ object MogaController : ControllerListener {
override fun onStateEvent(stateEvent: StateEvent) {
nativeOnStateEvent(stateEvent)
}
fun doForAllControllers(
action: (Int) -> Unit
){
val deviceIds = InputDevice.getDeviceIds()
deviceIds.forEach {
if(deviceIsController(it)) action(it)
}
}
infix fun Int.isFlag(flag: Int) = this and flag == flag
fun deviceIsController(deviceId: Int): Boolean {
val inputDevice = InputDevice.getDevice(deviceId) ?: return false
Log.i("Controller", inputDevice.toString())
val b = (inputDevice.sources isFlag InputDevice.SOURCE_GAMEPAD) &&
(inputDevice.sources isFlag InputDevice.SOURCE_JOYSTICK)
Log.i("Controller", b.toString())
if(inputDevice.id == -1) return false
return b
}
fun registerControllerHandlers(
context: Context,
onInputDeviceAdded: (Int) -> Unit,
onInputDeviceRemoved: (Int) -> Unit,
onInputDeviceChanged: (Int) -> Unit = {},
){
val inputManager = context.getSystemService(ComponentActivity.INPUT_SERVICE) as InputManager
inputManager.registerInputDeviceListener(object : InputManager.InputDeviceListener {
var lastControllerId: Int = 0;
override fun onInputDeviceAdded(deviceId: Int) {
if(deviceIsController(deviceId)) {
lastControllerId = deviceId
onInputDeviceAdded(deviceId)
}
}
override fun onInputDeviceRemoved(deviceId: Int) {
if(deviceIsController(deviceId) || lastControllerId == deviceId) onInputDeviceRemoved(deviceId)
}
override fun onInputDeviceChanged(deviceId: Int) {
if(deviceIsController(deviceId)) onInputDeviceChanged(deviceId)
}
}, null)
}
fun createDisconnectEvent(deviceId: Int) = StateEvent(
System.currentTimeMillis(),
deviceId,
StateEvent.STATE_UNKNOWN,
StateEvent.ACTION_DISCONNECTED
)
fun createConnectEvent(deviceId: Int) = StateEvent(
System.currentTimeMillis(),
deviceId,
StateEvent.STATE_CONNECTION,
StateEvent.ACTION_CONNECTED
)
fun androidKeyEventToBda(keyEvent: android.view.KeyEvent) = KeyEvent(
keyEvent.eventTime,
keyEvent.deviceId,
keyEvent.keyCode,
keyEvent.action
)
fun androidMotionEventToBda(motionEvent: android.view.MotionEvent) = MotionEvent(
motionEvent.eventTime,
motionEvent.deviceId,
motionEvent.x,
motionEvent.y,
motionEvent.rawX,
motionEvent.rawY,
motionEvent.xPrecision,
motionEvent.yPrecision
)
}
-91
View File
@@ -1,91 +0,0 @@
package com.megboyzz
import android.content.Context
import android.hardware.input.InputManager
import android.view.InputDevice
import androidx.activity.ComponentActivity
import com.bda.controller.KeyEvent
import com.bda.controller.MotionEvent
import android.view.KeyEvent as androidKeyEvent
import android.view.MotionEvent as androidMotionEvent
import com.bda.controller.StateEvent
fun actionForAllControllers(
action: (Int) -> Unit
){
val deviceIds = InputDevice.getDeviceIds()
deviceIds.forEach {
if(deviceIsController(it)) action(it)
}
}
fun deviceIsController(deviceId: Int): Boolean {
val inputDevice = InputDevice.getDevice(deviceId) ?: return false
return (inputDevice.sources and InputDevice.SOURCE_GAMEPAD) == InputDevice.SOURCE_GAMEPAD ||
(inputDevice.sources and InputDevice.SOURCE_JOYSTICK) == InputDevice.SOURCE_JOYSTICK
}
fun Context.registerControllerHandlers(
onInputDeviceAdded: (Int) -> Unit,
onInputDeviceRemoved: (Int) -> Unit,
onInputDeviceChanged: (Int) -> Unit = {},
){
val inputManager = getSystemService(ComponentActivity.INPUT_SERVICE) as InputManager
inputManager.registerInputDeviceListener(object : InputManager.InputDeviceListener {
var lastControllerId: Int = 0;
override fun onInputDeviceAdded(deviceId: Int) {
if(deviceIsController(deviceId)) {
lastControllerId = deviceId
onInputDeviceAdded(deviceId)
}
}
override fun onInputDeviceRemoved(deviceId: Int) {
if(deviceIsController(deviceId) || lastControllerId == deviceId) onInputDeviceRemoved(deviceId)
}
override fun onInputDeviceChanged(deviceId: Int) {
if(deviceIsController(deviceId)) onInputDeviceChanged(deviceId)
}
}, null)
}
fun createDisconnectEvent(deviceId: Int) = StateEvent(
System.currentTimeMillis(),
deviceId,
StateEvent.STATE_UNKNOWN,
StateEvent.ACTION_DISCONNECTED
)
fun createConnectEvent(deviceId: Int) = StateEvent(
System.currentTimeMillis(),
deviceId,
StateEvent.STATE_CONNECTION,
StateEvent.ACTION_CONNECTED
)
fun androidKeyEventToBda(keyEvent: androidKeyEvent) = KeyEvent(
keyEvent.eventTime,
keyEvent.deviceId,
keyEvent.keyCode,
keyEvent.action
)
fun androidMotionEventToBda(motionEvent: androidMotionEvent) = MotionEvent(
motionEvent.eventTime,
motionEvent.deviceId,
motionEvent.x,
motionEvent.y,
motionEvent.rawX,
motionEvent.rawY,
motionEvent.xPrecision,
motionEvent.yPrecision
)
+5
View File
@@ -71,6 +71,11 @@ dependencies {
debugImplementation(libs.ui.tooling)
debugImplementation(libs.ui.test.manifest)
implementation(libs.voyager.navigator)
implementation(libs.voyager.bottomSheetNavigator)
implementation(libs.voyager.transitions)
implementation(libs.voyager.screenModel)
implementation(libs.dagger)
kapt(libs.dagger.compiler)
implementation(libs.room)
@@ -4,6 +4,7 @@ import android.content.Intent
import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import cafe.adriel.voyager.navigator.bottomSheet.BottomSheetNavigator
import com.megboyzz.devmenu.ui.components.MainScaffold
class MainActivity : ComponentActivity() {
@@ -30,6 +31,11 @@ class MainActivity : ComponentActivity() {
}
setContent {
BottomSheetNavigator {
}
MainScaffold(
onSettingsClick = { /*TODO*/ },
onSearchValueChanged = {},
@@ -0,0 +1,18 @@
package com.megboyzz.devmenu.ui.components
import androidx.compose.animation.core.tween
import androidx.compose.animation.expandIn
import androidx.compose.animation.shrinkOut
import androidx.compose.ui.Alignment
val enter = expandIn(
expandFrom = Alignment.CenterStart,
animationSpec = tween(250)
)
val exit = shrinkOut(
shrinkTowards = Alignment.CenterStart,
animationSpec = tween(250)
)
@@ -1,26 +1,20 @@
package com.megboyzz.devmenu.ui.components
import androidx.compose.animation.AnimatedVisibility
import androidx.compose.foundation.Image
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.BoxScope
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.ColumnScope
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.RowScope
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.wrapContentHeight
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.KeyboardArrowRight
import androidx.compose.material.icons.outlined.Star
import androidx.compose.material3.Button
import androidx.compose.material3.Divider
import androidx.compose.material3.Icon
import androidx.compose.material3.OutlinedTextField
import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
@@ -33,7 +27,6 @@ import androidx.compose.ui.draw.clip
import androidx.compose.ui.draw.shadow
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.painter.Painter
import androidx.compose.ui.graphics.vector.rememberVectorPainter
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import com.megboyzz.devmenu.R
@@ -68,7 +61,7 @@ fun CoreMenuPosition(
) {
Row(
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.spacedBy(16.dp),
horizontalArrangement = Arrangement.spacedBy(20.dp),
) {
Image(
painter = icon,
@@ -87,11 +80,11 @@ fun FsElementInContextMenu(
Row(
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.spacedBy(12.dp)
horizontalArrangement = Arrangement.spacedBy(20.dp)
) {
val modifier = Modifier
.size(32.dp)
.size(36.dp)
.clip(RoundedCornerShape(10.dp))
.shadow(elevation = 6.dp)
@@ -108,33 +101,52 @@ fun FileContextMenu(
name: String,
type: ElementType,
onRemoveElement: () -> Unit,
onUpdateType: (ElementType) -> Unit
onUpdateType: (ElementType) -> ElementType?
) {
var innerType by remember { mutableStateOf(type) }
var isMain by remember { mutableStateOf(true) }
CoreFileContextMenu {
Column(verticalArrangement = Arrangement.spacedBy(20.dp)) {
FsElementInContextMenu(name = name, type = type)
Divider()
if (isMain) {
AnimatedBoxForContextMenuContent(isVisible = isMain){
AnimatedBoxForContextMenuContent(isVisible = innerType == ElementType.isFile) {
ClickableMenuPosition(
name = "Заменить",
icon = R.drawable.star.asPainter(),
onClick = {
innerType = ElementType.isReplaced
onUpdateType(innerType)
innerType = onUpdateType(ElementType.isReplaced) ?: ElementType.isReplaced
}
)
ClickableMenuPosition(
name = "Скрыть для игры",
icon = R.drawable.hide.asPainter(),
onClick = {
innerType = ElementType.isHidden
innerType = onUpdateType(ElementType.isHidden) ?: ElementType.isHidden
}
)
}
AnimatedBoxForContextMenuContent(isVisible = innerType == ElementType.isHidden) {
ClickableMenuPosition(
name = "Показать игре",
icon = R.drawable.unhide.asPainter(),
onClick = {
innerType = onUpdateType(ElementType.isFile) ?: ElementType.isFile
}
)
}
AnimatedBoxForContextMenuContent(isVisible = innerType == ElementType.isReplaced) {
ClickableMenuPosition(
name = "Воостановить",
icon = R.drawable.star.asPainter(),
onClick = {
innerType = onUpdateType(ElementType.isFile) ?: ElementType.isFile
}
)
}
ClickableMenuPosition(
name = "Свойства",
icon = R.drawable.info.asPainter(),
@@ -145,7 +157,9 @@ fun FileContextMenu(
icon = R.drawable.trash.asPainter(),
onClick = { isMain = !isMain }
)
}else{
}
AnimatedBoxForContextMenuContent(isVisible = !isMain) {
ClickableMenuPosition(
name = "Удалить",
icon = R.drawable.trash.asPainter(),
@@ -158,6 +172,22 @@ fun FileContextMenu(
}
}
}
@Composable
fun AnimatedBoxForContextMenuContent(
isVisible: Boolean,
content: @Composable ColumnScope.() -> Unit
) {
AnimatedVisibility(
visible = isVisible,
enter = enter,
exit = exit
) {
Column(
verticalArrangement = Arrangement.spacedBy(12.dp),
content = content
)
}
}
@Composable
@@ -174,31 +204,6 @@ fun RemoveFileButtonsGroup(
}
}
@Preview
@Composable
fun TwoButtonsRow() {
Surface(
modifier = Modifier.fillMaxWidth()
) {
Row(
modifier = Modifier.fillMaxWidth(),
) {
Button(
onClick = { /* Действие для первой кнопки */ },
modifier = Modifier.weight(1f) // Каждая кнопка занимает равное количество места (50%)
) {
// Ваш текст и стиль для первой кнопки
}
Button(
onClick = { /* Действие для второй кнопки */ },
modifier = Modifier.weight(1f) // Каждая кнопка занимает равное количество места (50%)
) {
// Ваш текст и стиль для второй кнопки
}
}
}
}
@Composable
fun RemoveButton(
@@ -206,7 +211,6 @@ fun RemoveButton(
modifier: Modifier = Modifier,
onClick: () -> Unit
) {
Row() {
Button(
onClick = onClick,
shape = RoundedCornerShape(10.dp),
@@ -215,29 +219,38 @@ fun RemoveButton(
Text(text = text)
}
}
}
@Composable
fun CoreFileContextMenu(
content: @Composable BoxScope.() -> Unit
content: @Composable () -> Unit
) {
val shape = RoundedCornerShape(topStart = 10.dp, topEnd = 10.dp)
Box(
modifier = Modifier
.wrapContentHeight()
.fillMaxWidth()
//TODO отвязать от цвета
.background(Color.White)
.clip(RoundedCornerShape(10.dp)),
.clip(shape)
.background(Color.White),
contentAlignment = Alignment.TopCenter
) {
Image(
painter = R.drawable.clip.asPainter(),
contentDescription = null,
modifier = Modifier.padding(top = 8.dp)
)
Box(
modifier = Modifier.padding(
horizontal = 32.dp,
vertical = 24.dp
horizontal = 28.dp,
vertical = 32.dp
),
content = content
)
){
Column(verticalArrangement = Arrangement.spacedBy(20.dp)) {
content()
}
}
}
}
@@ -250,7 +263,7 @@ fun ClicablePreview() {
name = "my_file.txt",
type = ElementType.isFile,
onRemoveElement = {},
onUpdateType = {}
onUpdateType = {null}
)
}
+6
View File
@@ -15,6 +15,7 @@ org-jetbrains-kotlin-jvm = "1.9.0"
ksp = "1.9.21-1.0.15"
dagger = "2.46.1"
room = "2.6.1"
voyager = "1.0.0"
[libraries]
core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "core-ktx" }
@@ -40,6 +41,11 @@ room = { module = "androidx.room:room-runtime", version.ref = "room" }
room-compiler = { module = "androidx.room:room-compiler", version.ref = "room" }
room-ktx = { module = "androidx.room:room-ktx", version.ref = "room" }
voyager-navigator = { module = "cafe.adriel.voyager:voyager-navigator", version.ref = "voyager" }
voyager-screenModel = { module = "cafe.adriel.voyager:voyager-screenmodel", version.ref = "voyager" }
voyager-bottomSheetNavigator = { module = "cafe.adriel.voyager:voyager-bottom-sheet-navigator", version.ref = "voyager" }
voyager-transitions = { module = "cafe.adriel.voyager:voyager-transitions", version.ref = "voyager" }
[plugins]
androidApplication = { id = "com.android.application", version.ref = "agp" }
kotlinAndroid = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin" }