From c435b7f42d0b9deb8913cb03217013915a9ffef2 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Florian=20M=C3=A4rkl?=
Date: Tue, 19 Nov 2019 21:35:38 +0100
Subject: [PATCH 001/291] =?UTF-8?q?Fix=20Android=20=E3=81=AC=E3=82=8B?=
=?UTF-8?q?=E3=81=BD=20in=20Regist?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../java/com/metallic/chiaki/regist/RegistExecuteActivity.kt | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/android/app/src/main/java/com/metallic/chiaki/regist/RegistExecuteActivity.kt b/android/app/src/main/java/com/metallic/chiaki/regist/RegistExecuteActivity.kt
index 4136248..09a7070 100644
--- a/android/app/src/main/java/com/metallic/chiaki/regist/RegistExecuteActivity.kt
+++ b/android/app/src/main/java/com/metallic/chiaki/regist/RegistExecuteActivity.kt
@@ -59,8 +59,9 @@ class RegistExecuteActivity: AppCompatActivity()
logTextView.setHorizontallyScrolling(true)
logTextView.movementMethod = ScrollingMovementMethod()
viewModel.logText.observe(this, Observer {
+ val textLayout = logTextView.layout ?: return@Observer
logTextView.text = it
- val scrollY = logTextView.layout.getLineBottom(logTextView.lineCount - 1) - logTextView.height + logTextView.paddingTop + logTextView.paddingBottom
+ val scrollY = textLayout.getLineBottom(logTextView.lineCount - 1) - logTextView.height + logTextView.paddingTop + logTextView.paddingBottom
logTextView.scrollTo(0, max(scrollY, 0))
})
From 3f66b985d5b86d75e96b1e2aa2c3b6b7751ebc35 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Florian=20M=C3=A4rkl?=
Date: Tue, 19 Nov 2019 21:55:10 +0100
Subject: [PATCH 002/291] Switch to generic Qt 5.12 Path on AppVeyor
---
scripts/appveyor.sh | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/scripts/appveyor.sh b/scripts/appveyor.sh
index bec5c31..077884a 100755
--- a/scripts/appveyor.sh
+++ b/scripts/appveyor.sh
@@ -43,7 +43,7 @@ export PATH="$PWD/protoc/bin:$PATH" || exit 1
PYTHON="C:/Python37/python.exe"
"$PYTHON" -m pip install protobuf || exit 1
-QT_PATH="C:/Qt/5.12.4/msvc2017_64"
+QT_PATH="C:/Qt/5.12/msvc2017_64"
COPY_DLLS="$PWD/openssl-1.1/x64/bin/libcrypto-1_1-x64.dll $PWD/openssl-1.1/x64/bin/libssl-1_1-x64.dll $SDL_ROOT/lib/x64/SDL2.dll"
From babf275c5bf9dc504b016381f6096ba376ba25ed Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Florian=20M=C3=A4rkl?=
Date: Wed, 20 Nov 2019 16:12:52 +0100
Subject: [PATCH 003/291] Fix Ctrl recv after Sending Login PIN (Fix #104)
---
lib/src/ctrl.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/lib/src/ctrl.c b/lib/src/ctrl.c
index daeee37..3304344 100644
--- a/lib/src/ctrl.c
+++ b/lib/src/ctrl.c
@@ -217,6 +217,7 @@ static void *ctrl_thread_func(void *user)
ctrl->login_pin = NULL;
ctrl->login_pin_size = 0;
chiaki_stop_pipe_reset(&ctrl->notif_pipe);
+ continue;
}
else
{
From e368a82e8f162de1aebe71b624dcb015589ab540 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Florian=20M=C3=A4rkl?=
Date: Wed, 20 Nov 2019 16:23:23 +0100
Subject: [PATCH 004/291] Force utf-8 instead of ascii in psn-account-id.py
#103
---
scripts/psn-account-id.py | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/scripts/psn-account-id.py b/scripts/psn-account-id.py
index 5c50cb7..63c0af8 100755
--- a/scripts/psn-account-id.py
+++ b/scripts/psn-account-id.py
@@ -6,6 +6,11 @@ if sys.version_info < (3, 0, 0):
print("DO NOT use Python 2.\nEVER.\nhttps://pythonclock.org")
exit(1)
+if sys.stdout.encoding.lower() == "ascii":
+ import codecs
+ sys.stdout = codecs.getwriter('utf-8')(sys.stdout.buffer)
+ sys.stderr = codecs.getwriter('utf-8')(sys.stderr.buffer)
+
try:
import requests
except ImportError as e:
From 4f60ceb1d4c7dd3b23eea41295d523a7f8d794fd Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Florian=20M=C3=A4rkl?=
Date: Wed, 20 Nov 2019 17:28:54 +0100
Subject: [PATCH 005/291] Fix Regist Scrolling on Android harder
---
.../java/com/metallic/chiaki/regist/RegistExecuteActivity.kt | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/android/app/src/main/java/com/metallic/chiaki/regist/RegistExecuteActivity.kt b/android/app/src/main/java/com/metallic/chiaki/regist/RegistExecuteActivity.kt
index 09a7070..d339578 100644
--- a/android/app/src/main/java/com/metallic/chiaki/regist/RegistExecuteActivity.kt
+++ b/android/app/src/main/java/com/metallic/chiaki/regist/RegistExecuteActivity.kt
@@ -60,8 +60,11 @@ class RegistExecuteActivity: AppCompatActivity()
logTextView.movementMethod = ScrollingMovementMethod()
viewModel.logText.observe(this, Observer {
val textLayout = logTextView.layout ?: return@Observer
+ val lineCount = textLayout.lineCount
+ if(lineCount < 1)
+ return@Observer
logTextView.text = it
- val scrollY = textLayout.getLineBottom(logTextView.lineCount - 1) - logTextView.height + logTextView.paddingTop + logTextView.paddingBottom
+ val scrollY = textLayout.getLineBottom(lineCount - 1) - logTextView.height + logTextView.paddingTop + logTextView.paddingBottom
logTextView.scrollTo(0, max(scrollY, 0))
})
From a3ae9d4f74fa5d53ace9e9c6661caba6f45b0aed Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Florian=20M=C3=A4rkl?=
Date: Wed, 20 Nov 2019 17:55:46 +0100
Subject: [PATCH 006/291] Hide Mouse after Timeout in Qt GUI
---
gui/include/avopenglwidget.h | 9 +++++++++
gui/src/avopenglwidget.cpp | 25 +++++++++++++++++++++++++
gui/src/streamwindow.cpp | 6 ++----
3 files changed, 36 insertions(+), 4 deletions(-)
diff --git a/gui/include/avopenglwidget.h b/gui/include/avopenglwidget.h
index 9583b4d..6451d8f 100644
--- a/gui/include/avopenglwidget.h
+++ b/gui/include/avopenglwidget.h
@@ -59,6 +59,8 @@ class AVOpenGLWidget: public QOpenGLWidget
AVOpenGLFrameUploader *frame_uploader;
QThread *frame_uploader_thread;
+ QTimer *mouse_timer;
+
public:
static QSurfaceFormat CreateSurfaceFormat();
@@ -69,8 +71,15 @@ class AVOpenGLWidget: public QOpenGLWidget
AVOpenGLFrame *GetBackgroundFrame() { return &frames[1 - frame_fg]; }
protected:
+ void mouseMoveEvent(QMouseEvent *event) override;
+
void initializeGL() override;
void paintGL() override;
+
+ private slots:
+ void ResetMouseTimeout();
+ public slots:
+ void HideMouse();
};
#endif // CHIAKI_AVOPENGLWIDGET_H
diff --git a/gui/src/avopenglwidget.cpp b/gui/src/avopenglwidget.cpp
index 49f83c3..164836d 100644
--- a/gui/src/avopenglwidget.cpp
+++ b/gui/src/avopenglwidget.cpp
@@ -23,6 +23,9 @@
#include
#include
#include
+#include
+
+#define MOUSE_TIMEOUT_MS 1000
//#define DEBUG_OPENGL
@@ -96,6 +99,11 @@ AVOpenGLWidget::AVOpenGLWidget(VideoDecoder *decoder, QWidget *parent)
frame_uploader = nullptr;
frame_uploader_thread = nullptr;
frame_fg = 0;
+
+ setMouseTracking(true);
+ mouse_timer = new QTimer(this);
+ connect(mouse_timer, &QTimer::timeout, this, &AVOpenGLWidget::HideMouse);
+ ResetMouseTimeout();
}
AVOpenGLWidget::~AVOpenGLWidget()
@@ -110,6 +118,23 @@ AVOpenGLWidget::~AVOpenGLWidget()
delete frame_uploader_context;
}
+void AVOpenGLWidget::mouseMoveEvent(QMouseEvent *event)
+{
+ QOpenGLWidget::mouseMoveEvent(event);
+ ResetMouseTimeout();
+}
+
+void AVOpenGLWidget::ResetMouseTimeout()
+{
+ unsetCursor();
+ mouse_timer->start(MOUSE_TIMEOUT_MS);
+}
+
+void AVOpenGLWidget::HideMouse()
+{
+ setCursor(Qt::BlankCursor);
+}
+
void AVOpenGLWidget::SwapFrames()
{
QMutexLocker lock(&frames_mutex);
diff --git a/gui/src/streamwindow.cpp b/gui/src/streamwindow.cpp
index a993ebb..cfddbda 100644
--- a/gui/src/streamwindow.cpp
+++ b/gui/src/streamwindow.cpp
@@ -126,13 +126,11 @@ void StreamWindow::LoginPINRequested(bool incorrect)
void StreamWindow::ToggleFullscreen()
{
if(isFullScreen())
- {
- setCursor(Qt::ArrowCursor);
showNormal();
- }
else
{
- setCursor(Qt::BlankCursor);
showFullScreen();
+ if(av_widget)
+ av_widget->HideMouse();
}
}
From 60db918cd540be7a014e9d2db8b4d966c8e60738 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Florian=20M=C3=A4rkl?=
Date: Wed, 20 Nov 2019 17:57:36 +0100
Subject: [PATCH 007/291] Version 1.1.2
---
CMakeLists.txt | 2 +-
android/app/build.gradle | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 4e5926e..f4108ee 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -15,7 +15,7 @@ option(CHIAKI_CLI_ARGP_STANDALONE "Search for standalone argp lib for CLI" OFF)
set(CHIAKI_VERSION_MAJOR 1)
set(CHIAKI_VERSION_MINOR 1)
-set(CHIAKI_VERSION_PATCH 1)
+set(CHIAKI_VERSION_PATCH 2)
set(CHIAKI_VERSION ${CHIAKI_VERSION_MAJOR}.${CHIAKI_VERSION_MINOR}.${CHIAKI_VERSION_PATCH})
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake")
diff --git a/android/app/build.gradle b/android/app/build.gradle
index 6d7cbc4..20dfb6d 100644
--- a/android/app/build.gradle
+++ b/android/app/build.gradle
@@ -24,7 +24,7 @@ android {
applicationId "com.metallic.chiaki"
minSdkVersion 21
targetSdkVersion 29
- versionCode 2
+ versionCode 3
versionName chiakiVersion
externalNativeBuild {
cmake {
From efa495d79466dad029a58cd061a4b48463ff4ae1 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Florian=20M=C3=A4rkl?=
Date: Sat, 23 Nov 2019 18:50:30 +0100
Subject: [PATCH 008/291] Fix Icon Install Path (Fix #92)
---
gui/CMakeLists.txt | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/gui/CMakeLists.txt b/gui/CMakeLists.txt
index 98aa3a3..76aec59 100644
--- a/gui/CMakeLists.txt
+++ b/gui/CMakeLists.txt
@@ -106,4 +106,4 @@ install(TARGETS chiaki
RUNTIME DESTINATION bin
BUNDLE DESTINATION bin)
install(FILES chiaki.desktop DESTINATION share/applications)
-install(FILES chiaki.png DESTINATION share/icons/hicolor/512x512)
+install(FILES chiaki.png DESTINATION share/icons/hicolor/512x512/apps)
From d67d5fe5dc505fd63d20a860e53710775107d5c7 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Florian=20M=C3=A4rkl?=
Date: Sun, 24 Nov 2019 14:36:20 +0100
Subject: [PATCH 009/291] Update Android Deps
---
android/app/build.gradle | 4 ++--
android/build.gradle | 4 ++--
2 files changed, 4 insertions(+), 4 deletions(-)
diff --git a/android/app/build.gradle b/android/app/build.gradle
index 20dfb6d..1823daa 100644
--- a/android/app/build.gradle
+++ b/android/app/build.gradle
@@ -93,13 +93,13 @@ androidExtensions {
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
- implementation"org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
+ implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
implementation 'androidx.appcompat:appcompat:1.1.0'
implementation 'androidx.core:core-ktx:1.1.0'
implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
implementation 'androidx.recyclerview:recyclerview:1.0.0'
implementation 'androidx.preference:preference:1.1.0'
- implementation 'com.google.android.material:material:1.1.0-beta01'
+ implementation 'com.google.android.material:material:1.1.0-beta02'
implementation 'androidx.lifecycle:lifecycle-extensions:2.1.0'
implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.1.0'
implementation 'androidx.lifecycle:lifecycle-reactivestreams:2.1.0'
diff --git a/android/build.gradle b/android/build.gradle
index e3245e7..f4ed563 100644
--- a/android/build.gradle
+++ b/android/build.gradle
@@ -1,14 +1,14 @@
// Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript {
- ext.kotlin_version = '1.3.50'
+ ext.kotlin_version = '1.3.60'
repositories {
google()
jcenter()
}
dependencies {
- classpath 'com.android.tools.build:gradle:3.5.1'
+ classpath 'com.android.tools.build:gradle:3.5.2'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
From 3e2e12d00285ec813ca200c45ee35b3924994172 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Florian=20M=C3=A4rkl?=
Date: Sun, 24 Nov 2019 14:48:51 +0100
Subject: [PATCH 010/291] Adjust Android Analog Stick Dimensions
---
.../java/com/metallic/chiaki/touchcontrols/AnalogStickView.kt | 3 ++-
android/app/src/main/res/values/dimens.xml | 4 ++--
2 files changed, 4 insertions(+), 3 deletions(-)
diff --git a/android/app/src/main/java/com/metallic/chiaki/touchcontrols/AnalogStickView.kt b/android/app/src/main/java/com/metallic/chiaki/touchcontrols/AnalogStickView.kt
index 5767532..563463b 100644
--- a/android/app/src/main/java/com/metallic/chiaki/touchcontrols/AnalogStickView.kt
+++ b/android/app/src/main/java/com/metallic/chiaki/touchcontrols/AnalogStickView.kt
@@ -78,7 +78,8 @@ class AnalogStickView @JvmOverloads constructor(
val center = center
if(center != null)
{
- drawableBase?.setBounds((center.x - radius).toInt(), (center.y - radius).toInt(), (center.x + radius).toInt(), (center.y + radius).toInt())
+ val circleRadius = radius + handleRadius
+ drawableBase?.setBounds((center.x - circleRadius).toInt(), (center.y - circleRadius).toInt(), (center.x + circleRadius).toInt(), (center.y + circleRadius).toInt())
drawableBase?.draw(canvas)
val handleX = center.x + handlePosition.x * radius
diff --git a/android/app/src/main/res/values/dimens.xml b/android/app/src/main/res/values/dimens.xml
index e71e7d2..543f0f4 100644
--- a/android/app/src/main/res/values/dimens.xml
+++ b/android/app/src/main/res/values/dimens.xml
@@ -1,7 +1,7 @@
48dp
- 64dp
- 16dp
+ 48dp
+ 32dp48dp
\ No newline at end of file
From e3ea1e40b2d805d8dab5e3959ace5f9de304f873 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Florian=20M=C3=A4rkl?=
Date: Mon, 25 Nov 2019 19:56:24 +0100
Subject: [PATCH 011/291] Export Settings on Android
---
android/app/build.gradle | 2 +
android/app/proguard-rules.pro | 69 +++++++-
.../com/metallic/chiaki/common/MacAddress.kt | 17 ++
.../chiaki/common/SerializedSettings.kt | 149 ++++++++++++++++++
.../chiaki/settings/SettingsFragment.kt | 38 ++++-
.../app/src/main/res/drawable/ic_export.xml | 9 ++
.../app/src/main/res/drawable/ic_import.xml | 9 ++
android/app/src/main/res/values/strings.xml | 8 +
android/app/src/main/res/xml/filepaths.xml | 3 +
android/app/src/main/res/xml/preferences.xml | 16 ++
10 files changed, 316 insertions(+), 4 deletions(-)
create mode 100644 android/app/src/main/java/com/metallic/chiaki/common/SerializedSettings.kt
create mode 100644 android/app/src/main/res/drawable/ic_export.xml
create mode 100644 android/app/src/main/res/drawable/ic_import.xml
diff --git a/android/app/build.gradle b/android/app/build.gradle
index 1823daa..ae37d9a 100644
--- a/android/app/build.gradle
+++ b/android/app/build.gradle
@@ -111,4 +111,6 @@ dependencies {
kapt "androidx.room:room-compiler:$room_version"
implementation "androidx.room:room-ktx:$room_version"
implementation "androidx.room:room-rxjava2:$room_version"
+ implementation "com.squareup.moshi:moshi:1.9.2"
+ kapt "com.squareup.moshi:moshi-kotlin-codegen:1.9.2"
}
diff --git a/android/app/proguard-rules.pro b/android/app/proguard-rules.pro
index 8af7f58..ccbe180 100644
--- a/android/app/proguard-rules.pro
+++ b/android/app/proguard-rules.pro
@@ -21,4 +21,71 @@
#-renamesourcefileattribute SourceFile
-dontobfuscate
--keep class com.metallic.chiaki.** { *; }
\ No newline at end of file
+-keep class com.metallic.chiaki.** { *; }
+
+
+##########################################
+# Moshi
+##########################################
+
+# JSR 305 annotations are for embedding nullability information.
+-dontwarn javax.annotation.**
+
+-keepclasseswithmembers class * {
+ @com.squareup.moshi.* ;
+}
+
+-keep @com.squareup.moshi.JsonQualifier interface *
+
+# Enum field names are used by the integrated EnumJsonAdapter.
+# values() is synthesized by the Kotlin compiler and is used by EnumJsonAdapter indirectly
+# Annotate enums with @JsonClass(generateAdapter = false) to use them with Moshi.
+-keepclassmembers @com.squareup.moshi.JsonClass class * extends java.lang.Enum {
+ ;
+ **[] values();
+}
+
+# The name of @JsonClass types is used to look up the generated adapter.
+-keepnames @com.squareup.moshi.JsonClass class *
+
+# Retain generated target class's synthetic defaults constructor and keep DefaultConstructorMarker's
+# name. We will look this up reflectively to invoke the type's constructor.
+#
+# We can't _just_ keep the defaults constructor because Proguard/R8's spec doesn't allow wildcard
+# matching preceding parameters.
+-keepnames class kotlin.jvm.internal.DefaultConstructorMarker
+-keepclassmembers @com.squareup.moshi.JsonClass @kotlin.Metadata class * {
+ synthetic (...);
+}
+
+# Retain generated JsonAdapters if annotated type is retained.
+-if @com.squareup.moshi.JsonClass class *
+-keep class <1>JsonAdapter {
+ (...);
+ ;
+}
+-if @com.squareup.moshi.JsonClass class **$*
+-keep class <1>_<2>JsonAdapter {
+ (...);
+ ;
+}
+-if @com.squareup.moshi.JsonClass class **$*$*
+-keep class <1>_<2>_<3>JsonAdapter {
+ (...);
+ ;
+}
+-if @com.squareup.moshi.JsonClass class **$*$*$*
+-keep class <1>_<2>_<3>_<4>JsonAdapter {
+ (...);
+ ;
+}
+-if @com.squareup.moshi.JsonClass class **$*$*$*$*
+-keep class <1>_<2>_<3>_<4>_<5>JsonAdapter {
+ (...);
+ ;
+}
+-if @com.squareup.moshi.JsonClass class **$*$*$*$*$*
+-keep class <1>_<2>_<3>_<4>_<5>_<6>JsonAdapter {
+ (...);
+ ;
+}
diff --git a/android/app/src/main/java/com/metallic/chiaki/common/MacAddress.kt b/android/app/src/main/java/com/metallic/chiaki/common/MacAddress.kt
index a648c6b..2c8f8ed 100644
--- a/android/app/src/main/java/com/metallic/chiaki/common/MacAddress.kt
+++ b/android/app/src/main/java/com/metallic/chiaki/common/MacAddress.kt
@@ -17,6 +17,9 @@
package com.metallic.chiaki.common
+import com.squareup.moshi.FromJson
+import com.squareup.moshi.JsonDataException
+import com.squareup.moshi.ToJson
import java.nio.ByteBuffer
import java.nio.ByteOrder
@@ -38,6 +41,14 @@ class MacAddress(v: Long)
buf.getLong(0)
})
+ constructor(string: String) : this(
+ (Regex("([0-9A-Fa-f]{2})[:-]{5}([0-9A-Fa-f]{2})").matchEntire(string)
+ ?: throw IllegalArgumentException("Invalid MAC Address String"))
+ .groupValues
+ .subList(1, 7)
+ .map { it.toByte() }
+ .toByteArray())
+
val value: Long = v and 0xffffffffffff
override fun equals(other: Any?): Boolean =
@@ -56,4 +67,10 @@ class MacAddress(v: Long)
(value shr 0x20) and 0xff,
(value shr 0x28) and 0xff
)
+}
+
+class MacAddressJsonAdapter
+{
+ @ToJson fun toJson(macAddress: MacAddress) = macAddress.toString()
+ @FromJson fun fromJson(string: String) = try { MacAddress(string) } catch(e: IllegalArgumentException) { throw JsonDataException(e.message) }
}
\ No newline at end of file
diff --git a/android/app/src/main/java/com/metallic/chiaki/common/SerializedSettings.kt b/android/app/src/main/java/com/metallic/chiaki/common/SerializedSettings.kt
new file mode 100644
index 0000000..50d9e0e
--- /dev/null
+++ b/android/app/src/main/java/com/metallic/chiaki/common/SerializedSettings.kt
@@ -0,0 +1,149 @@
+/*
+ * 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 .
+ */
+
+package com.metallic.chiaki.common
+
+import android.app.Activity
+import android.content.ClipData
+import android.content.Intent
+import android.util.Base64
+import androidx.core.content.FileProvider
+import com.metallic.chiaki.R
+import com.squareup.moshi.*
+import io.reactivex.android.schedulers.AndroidSchedulers
+import io.reactivex.disposables.Disposable
+import io.reactivex.rxkotlin.Singles
+import io.reactivex.schedulers.Schedulers
+import okio.Buffer
+import java.io.File
+
+@JsonClass(generateAdapter = true)
+class SerializedRegisteredHost(
+ @Json(name = "ap_ssid") val apSsid: String?,
+ @Json(name = "ap_bssid") val apBssid: String?,
+ @Json(name = "ap_key") val apKey: String?,
+ @Json(name = "ap_name") val apName: String?,
+ @Json(name = "ps4_mac") val ps4Mac: MacAddress,
+ @Json(name = "ps4_nickname") val ps4Nickname: String?,
+ @Json(name = "rp_regist_key") val rpRegistKey: ByteArray,
+ @Json(name = "rp_key_type") val rpKeyType: Int,
+ @Json(name = "rp_key") val rpKey: ByteArray
+){
+ constructor(registeredHost: RegisteredHost) : this(
+ registeredHost.apSsid,
+ registeredHost.apBssid,
+ registeredHost.apKey,
+ registeredHost.apName,
+ registeredHost.ps4Mac,
+ registeredHost.ps4Nickname,
+ registeredHost.rpRegistKey,
+ registeredHost.rpKeyType,
+ registeredHost.rpKey
+ )
+}
+
+@JsonClass(generateAdapter = true)
+class SerializedManualHost(
+ @Json(name = "host") val host: String,
+ @Json(name = "ps4_mac") val ps4Mac: MacAddress?
+)
+
+@JsonClass(generateAdapter = true)
+data class SerializedSettings(
+ @Json(name = "registered_hosts") val registeredHosts: List,
+ @Json(name = "manual_hosts") val manualHosts: List
+)
+{
+ companion object
+ {
+ fun fromDatabase(db: AppDatabase) = Singles.zip(
+ db.registeredHostDao().getAll().firstOrError(),
+ db.manualHostDao().getAll().firstOrError()
+ ) { registeredHosts, manualHosts ->
+ SerializedSettings(
+ registeredHosts.map { SerializedRegisteredHost(it) },
+ manualHosts.map { manualHost ->
+ SerializedManualHost(
+ manualHost.host,
+ manualHost.registeredHost?.let { registeredHostId ->
+ registeredHosts.firstOrNull { it.id == registeredHostId }
+ }?.ps4Mac
+ )
+ })
+ }
+ }
+}
+
+private class ByteArrayJsonAdapter
+{
+ @ToJson fun toJson(byteArray: ByteArray) = Base64.encodeToString(byteArray, Base64.NO_WRAP)
+ @FromJson fun fromJson(string: String) = Base64.decode(string, Base64.DEFAULT)
+}
+
+private fun moshi() =
+ Moshi.Builder()
+ .add(MacAddressJsonAdapter())
+ .add(ByteArrayJsonAdapter())
+ .build()
+
+private const val KEY_FORMAT = "format"
+private const val FORMAT = "chiaki-settings"
+private const val KEY_VERSION = "version"
+private const val VERSION = "1"
+private const val KEY_SETTINGS = "settings"
+
+fun exportAllSettings(db: AppDatabase) = SerializedSettings.fromDatabase(db)
+ .subscribeOn(Schedulers.io())
+ .map {
+ val buffer = Buffer()
+ val writer = JsonWriter.of(buffer)
+ val adapter = moshi()
+ .adapter(SerializedSettings::class.java)
+ .serializeNulls()
+ writer.indent = " "
+ writer.
+ beginObject()
+ .name(KEY_FORMAT).value(FORMAT)
+ .name(KEY_VERSION).value(VERSION)
+ writer.name(KEY_SETTINGS)
+ adapter.toJson(writer, it)
+ writer.endObject()
+ buffer.readUtf8()
+ }
+
+fun exportAndShareAllSettings(db: AppDatabase, activity: Activity): Disposable
+{
+ val dir = File(activity.cacheDir, "export_settings")
+ dir.mkdirs()
+ val file = File(dir, "chiaki-settings.json")
+ return exportAllSettings(db)
+ .map {
+ file.writeText(it, Charsets.UTF_8)
+ file
+ }
+ .observeOn(AndroidSchedulers.mainThread())
+ .subscribe { it: File ->
+ val uri = FileProvider.getUriForFile(activity, fileProviderAuthority, file)
+ Intent(Intent.ACTION_SEND).also {
+ it.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
+ it.type = "application/json"
+ it.putExtra(Intent.EXTRA_STREAM, uri)
+ it.clipData = ClipData.newRawUri("", uri)
+ activity.startActivity(Intent.createChooser(it, activity.getString(R.string.action_share_log)))
+ }
+ }
+}
\ No newline at end of file
diff --git a/android/app/src/main/java/com/metallic/chiaki/settings/SettingsFragment.kt b/android/app/src/main/java/com/metallic/chiaki/settings/SettingsFragment.kt
index c3adf7b..44096f8 100644
--- a/android/app/src/main/java/com/metallic/chiaki/settings/SettingsFragment.kt
+++ b/android/app/src/main/java/com/metallic/chiaki/settings/SettingsFragment.kt
@@ -17,17 +17,24 @@
package com.metallic.chiaki.settings
+import android.content.ClipData
+import android.content.Intent
import android.content.res.Resources
import android.os.Bundle
import android.text.InputType
+import androidx.core.content.FileProvider
import androidx.lifecycle.Observer
import androidx.lifecycle.ViewModelProviders
import androidx.preference.*
import com.metallic.chiaki.R
-import com.metallic.chiaki.common.Preferences
+import com.metallic.chiaki.common.*
import com.metallic.chiaki.common.ext.toLiveData
import com.metallic.chiaki.common.ext.viewModelFactory
-import com.metallic.chiaki.common.getDatabase
+import io.reactivex.android.schedulers.AndroidSchedulers
+import io.reactivex.disposables.CompositeDisposable
+import io.reactivex.rxkotlin.addTo
+import io.reactivex.schedulers.Schedulers
+import java.io.File
class DataStore(val preferences: Preferences): PreferenceDataStore()
{
@@ -76,11 +83,15 @@ class DataStore(val preferences: Preferences): PreferenceDataStore()
class SettingsFragment: PreferenceFragmentCompat(), TitleFragment
{
+ private lateinit var viewModel: SettingsViewModel
+
+ private var disposable = CompositeDisposable()
+
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?)
{
val context = context ?: return
- val viewModel = ViewModelProviders
+ viewModel = ViewModelProviders
.of(this, viewModelFactory { SettingsViewModel(getDatabase(context), Preferences(context)) })
.get(SettingsViewModel::class.java)
@@ -118,7 +129,28 @@ class SettingsFragment: PreferenceFragmentCompat(), TitleFragment
viewModel.registeredHostsCount.observe(this, Observer {
registeredHostsPreference?.summary = getString(R.string.preferences_registered_hosts_summary, it)
})
+
+ preferenceScreen.findPreference(getString(R.string.preferences_export_settings_key))?.setOnPreferenceClickListener { exportSettings(); true }
+ preferenceScreen.findPreference(getString(R.string.preferences_import_settings_key))?.setOnPreferenceClickListener { importSettings(); true }
+ }
+
+ override fun onDestroy()
+ {
+ super.onDestroy()
+ disposable.dispose()
}
override fun getTitle(resources: Resources): String = resources.getString(R.string.title_settings)
+
+ private fun exportSettings()
+ {
+ val activity = activity ?: return
+ disposable.clear()
+ exportAndShareAllSettings(viewModel.database, activity).addTo(disposable)
+ }
+
+ private fun importSettings()
+ {
+
+ }
}
\ No newline at end of file
diff --git a/android/app/src/main/res/drawable/ic_export.xml b/android/app/src/main/res/drawable/ic_export.xml
new file mode 100644
index 0000000..f92f317
--- /dev/null
+++ b/android/app/src/main/res/drawable/ic_export.xml
@@ -0,0 +1,9 @@
+
+
+
diff --git a/android/app/src/main/res/drawable/ic_import.xml b/android/app/src/main/res/drawable/ic_import.xml
new file mode 100644
index 0000000..fceae15
--- /dev/null
+++ b/android/app/src/main/res/drawable/ic_import.xml
@@ -0,0 +1,9 @@
+
+
+
diff --git a/android/app/src/main/res/values/strings.xml b/android/app/src/main/res/values/strings.xml
index fb89b5c..51d0617 100644
--- a/android/app/src/main/res/values/strings.xml
+++ b/android/app/src/main/res/values/strings.xml
@@ -40,6 +40,7 @@
Please enter a valid 8-byte Account ID in Base64Please enter a valid %d-digit PINShare Log
+ Export SettingsRegist successful.Regist failed.The console with MAC %s has already been registered. Should the previous record be overwritten?
@@ -51,9 +52,14 @@
Register on first ConnectionGeneralStream
+ ExportRegistered ConsolesSession LogsCollected log files from previous sessions for debugging
+ Export Settings
+ Warning: These resulting file can contain your secret Remote Play keys! Do not share them.
+ Import Settings
+ Import Settings from JSONCurrently registered: %dResolutionFPS
@@ -83,6 +89,8 @@
discovery_enabledon_screen_controls_enabledlog_verbose
+ import_settings
+ export_settingsswap_cross_moonstream_resolutionstream_fps
diff --git a/android/app/src/main/res/xml/filepaths.xml b/android/app/src/main/res/xml/filepaths.xml
index f3315d2..038db8c 100644
--- a/android/app/src/main/res/xml/filepaths.xml
+++ b/android/app/src/main/res/xml/filepaths.xml
@@ -3,4 +3,7 @@
+
\ No newline at end of file
diff --git a/android/app/src/main/res/xml/preferences.xml b/android/app/src/main/res/xml/preferences.xml
index 02d091f..d656347 100644
--- a/android/app/src/main/res/xml/preferences.xml
+++ b/android/app/src/main/res/xml/preferences.xml
@@ -53,4 +53,20 @@
app:title="@string/preferences_bitrate_title"
app:icon="@drawable/ic_bitrate"/>
+
+
+
+
+
+
\ No newline at end of file
From 2aa297d203b34ef222dcf8868cd67224edecb46d Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Florian=20M=C3=A4rkl?=
Date: Mon, 25 Nov 2019 20:39:37 +0100
Subject: [PATCH 012/291] Prepare Importing Settings on Android
---
.../com/metallic/chiaki/common/MacAddress.kt | 4 +-
.../chiaki/common/SerializedSettings.kt | 66 +++++++++++++++++--
.../chiaki/settings/SettingsFragment.kt | 25 ++++++-
3 files changed, 85 insertions(+), 10 deletions(-)
diff --git a/android/app/src/main/java/com/metallic/chiaki/common/MacAddress.kt b/android/app/src/main/java/com/metallic/chiaki/common/MacAddress.kt
index 2c8f8ed..39cc934 100644
--- a/android/app/src/main/java/com/metallic/chiaki/common/MacAddress.kt
+++ b/android/app/src/main/java/com/metallic/chiaki/common/MacAddress.kt
@@ -42,11 +42,11 @@ class MacAddress(v: Long)
})
constructor(string: String) : this(
- (Regex("([0-9A-Fa-f]{2})[:-]{5}([0-9A-Fa-f]{2})").matchEntire(string)
+ (Regex("([0-9A-Fa-f]{2})[:-]([0-9A-Fa-f]{2})[:-]([0-9A-Fa-f]{2})[:-]([0-9A-Fa-f]{2})[:-]([0-9A-Fa-f]{2})[:-]([0-9A-Fa-f]{2})").matchEntire(string)
?: throw IllegalArgumentException("Invalid MAC Address String"))
.groupValues
.subList(1, 7)
- .map { it.toByte() }
+ .map { it.toUByte(16).toByte() }
.toByteArray())
val value: Long = v and 0xffffffffffff
diff --git a/android/app/src/main/java/com/metallic/chiaki/common/SerializedSettings.kt b/android/app/src/main/java/com/metallic/chiaki/common/SerializedSettings.kt
index 50d9e0e..e7d9098 100644
--- a/android/app/src/main/java/com/metallic/chiaki/common/SerializedSettings.kt
+++ b/android/app/src/main/java/com/metallic/chiaki/common/SerializedSettings.kt
@@ -20,7 +20,9 @@ package com.metallic.chiaki.common
import android.app.Activity
import android.content.ClipData
import android.content.Intent
+import android.net.Uri
import android.util.Base64
+import android.util.Log
import androidx.core.content.FileProvider
import com.metallic.chiaki.R
import com.squareup.moshi.*
@@ -29,7 +31,9 @@ import io.reactivex.disposables.Disposable
import io.reactivex.rxkotlin.Singles
import io.reactivex.schedulers.Schedulers
import okio.Buffer
+import okio.Okio
import java.io.File
+import java.io.IOException
@JsonClass(generateAdapter = true)
class SerializedRegisteredHost(
@@ -100,10 +104,14 @@ private fun moshi() =
.add(ByteArrayJsonAdapter())
.build()
+private fun Moshi.serializedSettingsAdapter() =
+ adapter(SerializedSettings::class.java)
+ .serializeNulls()
+
private const val KEY_FORMAT = "format"
private const val FORMAT = "chiaki-settings"
private const val KEY_VERSION = "version"
-private const val VERSION = "1"
+private const val VERSION = 1
private const val KEY_SETTINGS = "settings"
fun exportAllSettings(db: AppDatabase) = SerializedSettings.fromDatabase(db)
@@ -111,9 +119,7 @@ fun exportAllSettings(db: AppDatabase) = SerializedSettings.fromDatabase(db)
.map {
val buffer = Buffer()
val writer = JsonWriter.of(buffer)
- val adapter = moshi()
- .adapter(SerializedSettings::class.java)
- .serializeNulls()
+ val adapter = moshi().serializedSettingsAdapter()
writer.indent = " "
writer.
beginObject()
@@ -125,8 +131,9 @@ fun exportAllSettings(db: AppDatabase) = SerializedSettings.fromDatabase(db)
buffer.readUtf8()
}
-fun exportAndShareAllSettings(db: AppDatabase, activity: Activity): Disposable
+fun exportAndShareAllSettings(activity: Activity): Disposable
{
+ val db = getDatabase(activity)
val dir = File(activity.cacheDir, "export_settings")
dir.mkdirs()
val file = File(dir, "chiaki-settings.json")
@@ -146,4 +153,53 @@ fun exportAndShareAllSettings(db: AppDatabase, activity: Activity): Disposable
activity.startActivity(Intent.createChooser(it, activity.getString(R.string.action_share_log)))
}
}
+}
+
+fun importSettingsFromUri(activity: Activity, uri: Uri)
+{
+ try
+ {
+ val inputStream = activity.contentResolver.openInputStream(uri) ?: throw IOException()
+ val buffer = Okio.buffer(Okio.source(inputStream))
+ val reader = JsonReader.of(buffer)
+ val adapter = moshi().serializedSettingsAdapter()
+
+ var format: String? = null
+ var version: Int? = null
+ var settingsValue: Any? = null
+
+ reader.beginObject()
+ while(reader.hasNext())
+ {
+ when(reader.nextName())
+ {
+ KEY_FORMAT -> format = reader.nextString()
+ KEY_VERSION -> version = reader.nextInt()
+ KEY_SETTINGS -> settingsValue = reader.readJsonValue()
+ }
+ }
+ reader.endObject()
+
+ if(format == null || version == null || settingsValue == null)
+ throw IOException("Missing format, version or settings from JSON")
+ if(format != FORMAT)
+ throw IOException("Value of format is invalid")
+ if(version != VERSION) // Add migrations here when necessary
+ throw IOException("Value of version is invalid")
+
+ val settings = adapter.fromJsonValue(settingsValue)
+ Log.i("SerializedSettings", "would import: $settings")
+ // TODO: show dialog and import
+ }
+ catch(e: IOException)
+ {
+ // TODO
+ e.printStackTrace()
+ }
+ catch(e: JsonDataException)
+ {
+ // TODO
+ e.printStackTrace()
+ }
+
}
\ No newline at end of file
diff --git a/android/app/src/main/java/com/metallic/chiaki/settings/SettingsFragment.kt b/android/app/src/main/java/com/metallic/chiaki/settings/SettingsFragment.kt
index 44096f8..336c296 100644
--- a/android/app/src/main/java/com/metallic/chiaki/settings/SettingsFragment.kt
+++ b/android/app/src/main/java/com/metallic/chiaki/settings/SettingsFragment.kt
@@ -17,6 +17,7 @@
package com.metallic.chiaki.settings
+import android.app.Activity
import android.content.ClipData
import android.content.Intent
import android.content.res.Resources
@@ -83,7 +84,10 @@ class DataStore(val preferences: Preferences): PreferenceDataStore()
class SettingsFragment: PreferenceFragmentCompat(), TitleFragment
{
- private lateinit var viewModel: SettingsViewModel
+ companion object
+ {
+ private const val PICK_SETTINGS_JSON_REQUEST = 1
+ }
private var disposable = CompositeDisposable()
@@ -91,7 +95,7 @@ class SettingsFragment: PreferenceFragmentCompat(), TitleFragment
{
val context = context ?: return
- viewModel = ViewModelProviders
+ val viewModel = ViewModelProviders
.of(this, viewModelFactory { SettingsViewModel(getDatabase(context), Preferences(context)) })
.get(SettingsViewModel::class.java)
@@ -146,11 +150,26 @@ class SettingsFragment: PreferenceFragmentCompat(), TitleFragment
{
val activity = activity ?: return
disposable.clear()
- exportAndShareAllSettings(viewModel.database, activity).addTo(disposable)
+ exportAndShareAllSettings(activity).addTo(disposable)
}
private fun importSettings()
{
+ val intent = Intent(Intent.ACTION_OPEN_DOCUMENT).apply {
+ addCategory(Intent.CATEGORY_OPENABLE)
+ type = "application/json"
+ }
+ startActivityForResult(intent, PICK_SETTINGS_JSON_REQUEST)
+ }
+ override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?)
+ {
+ if(requestCode == PICK_SETTINGS_JSON_REQUEST && resultCode == Activity.RESULT_OK)
+ {
+ val activity = activity ?: return
+ data?.data?.also {
+ importSettingsFromUri(activity, it)
+ }
+ }
}
}
\ No newline at end of file
From 5ddf9ef3732391a68bc36f8a227e266c8544c765 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Florian=20M=C3=A4rkl?=
Date: Sat, 30 Nov 2019 20:25:05 +0100
Subject: [PATCH 013/291] Finish Settings Import on Android
---
.../com/metallic/chiaki/common/AppDatabase.kt | 1 +
.../chiaki/common/SerializedSettings.kt | 105 +++++++++++++++++-
.../chiaki/settings/SettingsFragment.kt | 7 +-
android/app/src/main/res/values/strings.xml | 6 +
android/build.gradle | 2 +-
5 files changed, 111 insertions(+), 10 deletions(-)
diff --git a/android/app/src/main/java/com/metallic/chiaki/common/AppDatabase.kt b/android/app/src/main/java/com/metallic/chiaki/common/AppDatabase.kt
index 165574b..64c1288 100644
--- a/android/app/src/main/java/com/metallic/chiaki/common/AppDatabase.kt
+++ b/android/app/src/main/java/com/metallic/chiaki/common/AppDatabase.kt
@@ -28,6 +28,7 @@ abstract class AppDatabase: RoomDatabase()
{
abstract fun registeredHostDao(): RegisteredHostDao
abstract fun manualHostDao(): ManualHostDao
+ abstract fun importDao(): ImportDao
}
private var database: AppDatabase? = null
diff --git a/android/app/src/main/java/com/metallic/chiaki/common/SerializedSettings.kt b/android/app/src/main/java/com/metallic/chiaki/common/SerializedSettings.kt
index e7d9098..174e620 100644
--- a/android/app/src/main/java/com/metallic/chiaki/common/SerializedSettings.kt
+++ b/android/app/src/main/java/com/metallic/chiaki/common/SerializedSettings.kt
@@ -24,11 +24,18 @@ import android.net.Uri
import android.util.Base64
import android.util.Log
import androidx.core.content.FileProvider
+import androidx.room.*
+import com.google.android.material.dialog.MaterialAlertDialogBuilder
import com.metallic.chiaki.R
import com.squareup.moshi.*
+import io.reactivex.Completable
+import io.reactivex.Flowable
+import io.reactivex.Single
import io.reactivex.android.schedulers.AndroidSchedulers
+import io.reactivex.disposables.CompositeDisposable
import io.reactivex.disposables.Disposable
import io.reactivex.rxkotlin.Singles
+import io.reactivex.rxkotlin.addTo
import io.reactivex.schedulers.Schedulers
import okio.Buffer
import okio.Okio
@@ -155,8 +162,17 @@ fun exportAndShareAllSettings(activity: Activity): Disposable
}
}
-fun importSettingsFromUri(activity: Activity, uri: Uri)
+fun importSettingsFromUri(activity: Activity, uri: Uri, disposable: CompositeDisposable)
{
+ fun loadFail(msg: String)
+ {
+ MaterialAlertDialogBuilder(activity)
+ .setMessage(activity.getString(R.string.alert_message_import_failed, msg))
+ .setPositiveButton(R.string.action_import_failed_ack) { _, _ -> }
+ .create()
+ .show()
+ }
+
try
{
val inputStream = activity.contentResolver.openInputStream(uri) ?: throw IOException()
@@ -187,19 +203,96 @@ fun importSettingsFromUri(activity: Activity, uri: Uri)
if(version != VERSION) // Add migrations here when necessary
throw IOException("Value of version is invalid")
- val settings = adapter.fromJsonValue(settingsValue)
+ val settings = adapter.fromJsonValue(settingsValue) ?: throw JsonDataException("Failed to parse Settings JSON")
Log.i("SerializedSettings", "would import: $settings")
- // TODO: show dialog and import
+
+ MaterialAlertDialogBuilder(activity)
+ .setMessage(activity.getString(R.string.alert_message_import,
+ settings.registeredHosts.let {
+ if(it.isEmpty())
+ "-"
+ else
+ it.joinToString(separator = "") { host -> "\n - ${host.ps4Nickname ?: "?"} / ${host.ps4Mac}" }
+ },
+ settings.manualHosts.let {
+ if(it.isEmpty())
+ "-"
+ else
+ it.joinToString(separator = "") { host -> "\n - ${host.host} / ${host.ps4Mac ?: "unregistered"}" }
+ }
+ ))
+ .setTitle(R.string.alert_title_import)
+ .setNegativeButton(R.string.action_import_cancel) { _, _ -> }
+ .setPositiveButton(R.string.action_import_import) { _, _ ->
+ getDatabase(activity).importDao()
+ .importCompletable(settings)
+ .subscribeOn(Schedulers.io())
+ .observeOn(AndroidSchedulers.mainThread())
+ .subscribe()
+ .addTo(disposable)
+ }
+ .create()
+ .show()
}
catch(e: IOException)
{
- // TODO
e.printStackTrace()
+ loadFail(e.message ?: "")
}
catch(e: JsonDataException)
{
- // TODO
e.printStackTrace()
+ loadFail(e.message ?: "")
}
+}
-}
\ No newline at end of file
+@Dao
+abstract class ImportDao
+{
+ @Insert
+ abstract fun insertRegisteredHosts(hosts: List)
+
+ @Insert
+ abstract fun insertManualHosts(hosts: List)
+
+ class IdWithMac(val id: Long, val mac: MacAddress)
+
+ @Query("SELECT id, ps4_mac AS mac FROM registered_host WHERE ps4_mac IN (:macs)")
+ abstract fun registeredHostsByMac(macs: List): List
+
+ @Transaction
+ fun import(settings: SerializedSettings)
+ {
+ insertRegisteredHosts(
+ settings.registeredHosts.map {
+ RegisteredHost(
+ apSsid = it.apSsid,
+ apBssid = it.apBssid,
+ apKey = it.apKey,
+ apName = it.apName,
+ ps4Mac = it.ps4Mac,
+ ps4Nickname = it.ps4Nickname,
+ rpRegistKey = it.rpRegistKey,
+ rpKeyType = it.rpKeyType,
+ rpKey = it.rpKey
+ )
+ })
+
+ val macs = settings.manualHosts.mapNotNull { it.ps4Mac }
+ val idMacs =
+ if(macs.isNotEmpty())
+ registeredHostsByMac(macs)
+ else
+ listOf()
+
+ insertManualHosts(
+ settings.manualHosts.map {
+ ManualHost(
+ host = it.host,
+ registeredHost = idMacs.firstOrNull { regHost -> regHost.mac == it.ps4Mac }?.id
+ )
+ })
+ }
+}
+
+private fun ImportDao.importCompletable(settings: SerializedSettings) = Completable.fromCallable { import(settings) }
diff --git a/android/app/src/main/java/com/metallic/chiaki/settings/SettingsFragment.kt b/android/app/src/main/java/com/metallic/chiaki/settings/SettingsFragment.kt
index 336c296..ee2cf57 100644
--- a/android/app/src/main/java/com/metallic/chiaki/settings/SettingsFragment.kt
+++ b/android/app/src/main/java/com/metallic/chiaki/settings/SettingsFragment.kt
@@ -90,6 +90,7 @@ class SettingsFragment: PreferenceFragmentCompat(), TitleFragment
}
private var disposable = CompositeDisposable()
+ private var exportDisposable = CompositeDisposable().also { it.addTo(disposable) }
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?)
{
@@ -149,8 +150,8 @@ class SettingsFragment: PreferenceFragmentCompat(), TitleFragment
private fun exportSettings()
{
val activity = activity ?: return
- disposable.clear()
- exportAndShareAllSettings(activity).addTo(disposable)
+ exportDisposable.clear()
+ exportAndShareAllSettings(activity).addTo(exportDisposable)
}
private fun importSettings()
@@ -168,7 +169,7 @@ class SettingsFragment: PreferenceFragmentCompat(), TitleFragment
{
val activity = activity ?: return
data?.data?.also {
- importSettingsFromUri(activity, it)
+ importSettingsFromUri(activity, it, disposable)
}
}
}
diff --git a/android/app/src/main/res/values/strings.xml b/android/app/src/main/res/values/strings.xml
index 51d0617..38739a8 100644
--- a/android/app/src/main/res/values/strings.xml
+++ b/android/app/src/main/res/values/strings.xml
@@ -46,6 +46,12 @@
The console with MAC %s has already been registered. Should the previous record be overwritten?OverwriteCancel
+ Import
+ Cancel
+ Import
+ Registered Hosts: %s\n\nManual Hosts: %s
+ Failed to import settings from file:\n%s
+ DismissManual Console EntrySaveRegistered Console
diff --git a/android/build.gradle b/android/build.gradle
index f4ed563..f672437 100644
--- a/android/build.gradle
+++ b/android/build.gradle
@@ -1,7 +1,7 @@
// Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript {
- ext.kotlin_version = '1.3.60'
+ ext.kotlin_version = '1.3.61'
repositories {
google()
jcenter()
From dc117246273bf43bae1f9862967bf7995e487e59 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Florian=20M=C3=A4rkl?=
Date: Sun, 1 Dec 2019 11:57:37 +0100
Subject: [PATCH 014/291] Make psn-account-id.py Script easier for Windows
---
scripts/psn-account-id.py | 73 ++++++++++++++++++++++++++-------------
1 file changed, 49 insertions(+), 24 deletions(-)
diff --git a/scripts/psn-account-id.py b/scripts/psn-account-id.py
index 63c0af8..590249d 100755
--- a/scripts/psn-account-id.py
+++ b/scripts/psn-account-id.py
@@ -3,20 +3,45 @@
import sys
if sys.version_info < (3, 0, 0):
- print("DO NOT use Python 2.\nEVER.\nhttps://pythonclock.org")
- exit(1)
+ print("DO NOT use Python 2.\nEVER.\nhttps://pythonclock.org")
+ exit(1)
+
+import platform
+oldexit = exit
+def exit(code):
+ if platform.system() == "Windows":
+ import atexit
+ input("Press Enter to exit.")
+ oldexit(code)
if sys.stdout.encoding.lower() == "ascii":
- import codecs
- sys.stdout = codecs.getwriter('utf-8')(sys.stdout.buffer)
- sys.stderr = codecs.getwriter('utf-8')(sys.stderr.buffer)
+ import codecs
+ sys.stdout = codecs.getwriter('utf-8')(sys.stdout.buffer)
+ sys.stderr = codecs.getwriter('utf-8')(sys.stderr.buffer)
try:
- import requests
+ import requests
except ImportError as e:
- print(e)
- print("\"requests\" is not available. Install it with pip whatever.")
- exit(1)
+ print(e)
+ if platform.system() == "Windows":
+ from distutils.util import strtobool
+ a = input("The requests module is not available. Should we try to install it automatically using pip? [y/n] ")
+ while True:
+ try:
+ a = strtobool(a)
+ break
+ except ValueError:
+ a = input("Please answer with y or n: ")
+ if a == 1:
+ import subprocess
+ subprocess.call([sys.executable, "-m", "pip", "install", "requests"])
+ else:
+ exit(1)
+ else:
+ print("\"requests\" is not available. Install it with pip or your distribution's package manager.")
+ exit(1)
+
+import requests
from urllib.parse import urlparse, parse_qs, quote, urljoin
import pprint
@@ -45,8 +70,8 @@ code_url_s = input("> ")
code_url = urlparse(code_url_s)
query = parse_qs(code_url.query)
if "code" not in query or len(query["code"]) == 0 or len(query["code"][0]) == 0:
- print("☠️ URL did not contain code parameter")
- exit(1)
+ print("☠️ URL did not contain code parameter")
+ exit(1)
code = query["code"][0]
print("🌏 Requesting OAuth Token")
@@ -55,38 +80,37 @@ api_auth = requests.auth.HTTPBasicAuth(CLIENT_ID, CLIENT_SECRET)
body = "grant_type=authorization_code&code={}&redirect_uri=https://remoteplay.dl.playstation.net/remoteplay/redirect&".format(code)
token_request = requests.post(TOKEN_URL,
- auth = api_auth,
- headers = { "Content-Type": "application/x-www-form-urlencoded" },
- data = body.encode("ascii"))
+ auth = api_auth,
+ headers = { "Content-Type": "application/x-www-form-urlencoded" },
+ data = body.encode("ascii"))
print("⚠️ WARNING: From this point on, output might contain sensitive information in some cases!")
if token_request.status_code != 200:
- print("☠️ Request failed with code {}:\n{}".format(token_request.status_code, token_request.text))
- exit(1)
+ print("☠️ Request failed with code {}:\n{}".format(token_request.status_code, token_request.text))
+ exit(1)
token_json = token_request.json()
if "access_token" not in token_json:
- print("☠️ \"access_token\" is missing in response JSON:\n{}".format(token_request.text))
- exit(1)
+ print("☠️ \"access_token\" is missing in response JSON:\n{}".format(token_request.text))
+ exit(1)
token = token_json["access_token"]
print("🌏 Requesting Account Info")
-account_request = requests.get(TOKEN_URL + "/" + quote(token),
- auth = api_auth)
+account_request = requests.get(TOKEN_URL + "/" + quote(token), auth = api_auth)
if account_request.status_code != 200:
- print("☠️ Request failed with code {}:\n{}".format(account_request.status_code, account_request.text))
- exit(1)
+ print("☠️ Request failed with code {}:\n{}".format(account_request.status_code, account_request.text))
+ exit(1)
account_info = account_request.json()
print("🥦 Received Account Info:")
pprint.pprint(account_info)
if "user_id" not in account_info:
- print("☠️ \"user_id\" is missing in response or not a string")
- exit(1)
+ print("☠️ \"user_id\" is missing in response or not a string")
+ exit(1)
user_id = int(account_info["user_id"])
user_id_base64 = base64.b64encode(user_id.to_bytes(8, "little")).decode()
@@ -94,4 +118,5 @@ user_id_base64 = base64.b64encode(user_id.to_bytes(8, "little")).decode()
print()
print("🍙 This is your AccountID:")
print(user_id_base64)
+exit(0)
From be824917b0eb4e392aaa46517b8b540be8e00a35 Mon Sep 17 00:00:00 2001
From: Lasath Fernando
Date: Sun, 1 Dec 2019 13:53:01 -0800
Subject: [PATCH 015/291] Add Pyramid/Box buttons to keybindings (#118)
---
README.md | 9 ++++++++-
gui/src/streamsession.cpp | 14 +++++++++++++-
2 files changed, 21 insertions(+), 2 deletions(-)
diff --git a/README.md b/README.md
index 563a873..01fc9a0 100644
--- a/README.md
+++ b/README.md
@@ -21,7 +21,14 @@ The following features however are yet to be implemented:
* H264 Error Concealment (FEC and active error recovery however are implemented)
* Touchpad support (Triggering the Touchpad Button is currently possible by pressing `T` on the keyboard)
* Rumble
-* Configurable Keybindings
+* Configurable Keybindings. Though, for the moment you can use the following:
+ * `⏎` -> Cross
+ * `⌫` -> Moon
+ * `\` or `X` -> Box
+ * `]` or `C` -> Pyramid
+ * `F` or `[` -> Share
+ * `⇦⇧⇩⇨` -> D-Pad
+ * `Esc` -> PS
## Installing
diff --git a/gui/src/streamsession.cpp b/gui/src/streamsession.cpp
index 8635b07..2b4eafa 100644
--- a/gui/src/streamsession.cpp
+++ b/gui/src/streamsession.cpp
@@ -164,6 +164,18 @@ void StreamSession::HandleKeyboardEvent(QKeyEvent *event)
case Qt::Key::Key_Backspace:
button_mask = CHIAKI_CONTROLLER_BUTTON_MOON;
break;
+ case Qt::Key::Key_Backslash:
+ case Qt::Key::Key_X:
+ button_mask = CHIAKI_CONTROLLER_BUTTON_BOX;
+ break;
+ case Qt::Key::Key_C:
+ case Qt::Key::Key_BracketRight:
+ button_mask = CHIAKI_CONTROLLER_BUTTON_PYRAMID;
+ break;
+ case Qt::Key::Key_F:
+ case Qt::Key::Key_BracketLeft:
+ button_mask = CHIAKI_CONTROLLER_BUTTON_SHARE;
+ break;
case Qt::Key::Key_Escape:
button_mask = CHIAKI_CONTROLLER_BUTTON_PS;
break;
@@ -384,4 +396,4 @@ static void EventCb(ChiakiEvent *event, void *user)
{
auto session = reinterpret_cast(user);
StreamSessionPrivate::Event(session, event);
-}
\ No newline at end of file
+}
From 385a382577882496c85982d163948851269fb812 Mon Sep 17 00:00:00 2001
From: FearlessSpiff
Date: Tue, 24 Dec 2019 13:12:38 +0100
Subject: [PATCH 016/291] Add Android Touchpad Only Control Option (#130)
---
.../com/metallic/chiaki/common/Preferences.kt | 5 ++
.../metallic/chiaki/stream/StreamActivity.kt | 19 +++++
.../metallic/chiaki/stream/StreamViewModel.kt | 9 +++
.../touchcontrols/TouchpadOnlyFragment.kt | 69 +++++++++++++++++++
.../src/main/res/layout/activity_stream.xml | 19 ++++-
.../res/layout/fragment_touchpad_only.xml | 27 ++++++++
android/app/src/main/res/values/strings.xml | 1 +
7 files changed, 148 insertions(+), 1 deletion(-)
create mode 100644 android/app/src/main/java/com/metallic/chiaki/touchcontrols/TouchpadOnlyFragment.kt
create mode 100644 android/app/src/main/res/layout/fragment_touchpad_only.xml
diff --git a/android/app/src/main/java/com/metallic/chiaki/common/Preferences.kt b/android/app/src/main/java/com/metallic/chiaki/common/Preferences.kt
index 17d8da4..780fec2 100644
--- a/android/app/src/main/java/com/metallic/chiaki/common/Preferences.kt
+++ b/android/app/src/main/java/com/metallic/chiaki/common/Preferences.kt
@@ -74,6 +74,11 @@ class Preferences(context: Context)
get() = sharedPreferences.getBoolean(onScreenControlsEnabledKey, true)
set(value) { sharedPreferences.edit().putBoolean(onScreenControlsEnabledKey, value).apply() }
+ val touchpadOnlyEnabledKey get() = resources.getString(R.string.preferences_touchpad_only_key)
+ var touchpadOnlyEnabled
+ get() = sharedPreferences.getBoolean(touchpadOnlyEnabledKey, false)
+ set(value) { sharedPreferences.edit().putBoolean(touchpadOnlyEnabledKey, value).apply() }
+
val logVerboseKey get() = resources.getString(R.string.preferences_log_verbose_key)
var logVerbose
get() = sharedPreferences.getBoolean(logVerboseKey, false)
diff --git a/android/app/src/main/java/com/metallic/chiaki/stream/StreamActivity.kt b/android/app/src/main/java/com/metallic/chiaki/stream/StreamActivity.kt
index 43dee24..eee3908 100644
--- a/android/app/src/main/java/com/metallic/chiaki/stream/StreamActivity.kt
+++ b/android/app/src/main/java/com/metallic/chiaki/stream/StreamActivity.kt
@@ -39,6 +39,7 @@ import com.metallic.chiaki.common.Preferences
import com.metallic.chiaki.common.ext.viewModelFactory
import com.metallic.chiaki.lib.ConnectInfo
import com.metallic.chiaki.session.*
+import com.metallic.chiaki.touchcontrols.TouchpadOnlyFragment
import com.metallic.chiaki.touchcontrols.TouchControlsFragment
import kotlinx.android.synthetic.main.activity_stream.*
@@ -79,12 +80,25 @@ class StreamActivity : AppCompatActivity(), View.OnSystemUiVisibilityChangeListe
viewModel.onScreenControlsEnabled.observe(this, Observer {
if(onScreenControlsSwitch.isChecked != it)
onScreenControlsSwitch.isChecked = it
+ if(onScreenControlsSwitch.isChecked)
+ touchpadOnlySwitch.isChecked = false
})
onScreenControlsSwitch.setOnCheckedChangeListener { _, isChecked ->
viewModel.setOnScreenControlsEnabled(isChecked)
showOverlay()
}
+ viewModel.touchpadOnlyEnabled.observe(this, Observer {
+ if(touchpadOnlySwitch.isChecked != it)
+ touchpadOnlySwitch.isChecked = it
+ if(touchpadOnlySwitch.isChecked)
+ onScreenControlsSwitch.isChecked = false
+ })
+ touchpadOnlySwitch.setOnCheckedChangeListener { _, isChecked ->
+ viewModel.setTouchpadOnlyEnabled(isChecked)
+ showOverlay()
+ }
+
viewModel.session.attachToTextureView(textureView)
viewModel.session.state.observe(this, Observer { this.stateChanged(it) })
textureView.addOnLayoutChangeListener { _, _, _, _, _, _, _, _, _ ->
@@ -100,6 +114,11 @@ class StreamActivity : AppCompatActivity(), View.OnSystemUiVisibilityChangeListe
fragment.controllerStateCallback = { viewModel.input.touchControllerState = it }
fragment.onScreenControlsEnabled = viewModel.onScreenControlsEnabled
}
+ if(fragment is TouchpadOnlyFragment)
+ {
+ fragment.controllerStateCallback = { viewModel.input.touchControllerState = it }
+ fragment.touchpadOnlyEnabled = viewModel.touchpadOnlyEnabled
+ }
}
override fun onResume()
diff --git a/android/app/src/main/java/com/metallic/chiaki/stream/StreamViewModel.kt b/android/app/src/main/java/com/metallic/chiaki/stream/StreamViewModel.kt
index 8f59f72..db95e0e 100644
--- a/android/app/src/main/java/com/metallic/chiaki/stream/StreamViewModel.kt
+++ b/android/app/src/main/java/com/metallic/chiaki/stream/StreamViewModel.kt
@@ -35,6 +35,9 @@ class StreamViewModel(val preferences: Preferences, val logManager: LogManager,
private var _onScreenControlsEnabled = MutableLiveData(preferences.onScreenControlsEnabled)
val onScreenControlsEnabled: LiveData get() = _onScreenControlsEnabled
+ private var _touchpadOnlyEnabled = MutableLiveData(preferences.touchpadOnlyEnabled)
+ val touchpadOnlyEnabled: LiveData get() = _touchpadOnlyEnabled
+
override fun onCleared()
{
super.onCleared()
@@ -46,4 +49,10 @@ class StreamViewModel(val preferences: Preferences, val logManager: LogManager,
preferences.onScreenControlsEnabled = enabled
_onScreenControlsEnabled.value = enabled
}
+
+ fun setTouchpadOnlyEnabled(enabled: Boolean)
+ {
+ preferences.touchpadOnlyEnabled = enabled
+ _touchpadOnlyEnabled.value = enabled
+ }
}
\ No newline at end of file
diff --git a/android/app/src/main/java/com/metallic/chiaki/touchcontrols/TouchpadOnlyFragment.kt b/android/app/src/main/java/com/metallic/chiaki/touchcontrols/TouchpadOnlyFragment.kt
new file mode 100644
index 0000000..54f2c8b
--- /dev/null
+++ b/android/app/src/main/java/com/metallic/chiaki/touchcontrols/TouchpadOnlyFragment.kt
@@ -0,0 +1,69 @@
+/*
+ * 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 .
+ */
+
+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 androidx.lifecycle.LiveData
+import androidx.lifecycle.Observer
+import com.metallic.chiaki.R
+import com.metallic.chiaki.lib.ControllerState
+import kotlinx.android.synthetic.main.fragment_controls.*
+
+class TouchpadOnlyFragment : Fragment()
+{
+ private var controllerState = ControllerState()
+ private set(value)
+ {
+ val diff = field != value
+ field = value
+ if(diff)
+ controllerStateCallback?.let { it(value) }
+ }
+
+ var controllerStateCallback: ((ControllerState) -> Unit)? = null
+ var touchpadOnlyEnabled: LiveData? = null
+
+ override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View
+ = inflater.inflate(R.layout.fragment_touchpad_only, container, false)
+
+ override fun onViewCreated(view: View, savedInstanceState: Bundle?)
+ {
+ super.onViewCreated(view, savedInstanceState)
+
+ touchpadButtonView.buttonPressedCallback = buttonStateChanged(ControllerState.BUTTON_TOUCHPAD)
+
+ touchpadOnlyEnabled?.observe(this, Observer {
+ view.visibility = if(it) View.VISIBLE else View.GONE
+ })
+ }
+
+ private fun buttonStateChanged(buttonMask: UInt) = { pressed: Boolean ->
+ controllerState = controllerState.copy().apply {
+ buttons =
+ if(pressed)
+ buttons or buttonMask
+ else
+ buttons and buttonMask.inv()
+
+ }
+ }
+}
\ No newline at end of file
diff --git a/android/app/src/main/res/layout/activity_stream.xml b/android/app/src/main/res/layout/activity_stream.xml
index 27a32d0..770c42c 100644
--- a/android/app/src/main/res/layout/activity_stream.xml
+++ b/android/app/src/main/res/layout/activity_stream.xml
@@ -23,12 +23,18 @@
android:layout_width="match_parent"
android:layout_height="match_parent"/>
+
+
@@ -52,6 +58,17 @@
android:layout_marginLeft="8dp"
android:textColor="@color/stream_text"/>
+
+
diff --git a/android/app/src/main/res/layout/fragment_touchpad_only.xml b/android/app/src/main/res/layout/fragment_touchpad_only.xml
new file mode 100644
index 0000000..a42b78a
--- /dev/null
+++ b/android/app/src/main/res/layout/fragment_touchpad_only.xml
@@ -0,0 +1,27 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/android/app/src/main/res/values/strings.xml b/android/app/src/main/res/values/strings.xml
index 38739a8..bbadf15 100644
--- a/android/app/src/main/res/values/strings.xml
+++ b/android/app/src/main/res/values/strings.xml
@@ -94,6 +94,7 @@
discovery_enabledon_screen_controls_enabled
+ touchpad_only_enabledlog_verboseimport_settingsexport_settings
From 20872e61f4c5aab6175d08067596ba358cf8ba53 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Florian=20M=C3=A4rkl?=
Date: Tue, 24 Dec 2019 13:30:59 +0100
Subject: [PATCH 017/291] Update FreeBSD deps
---
.builds/freebsd.yml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/.builds/freebsd.yml b/.builds/freebsd.yml
index efbc9c9..01b7fdd 100644
--- a/.builds/freebsd.yml
+++ b/.builds/freebsd.yml
@@ -7,7 +7,7 @@ sources:
packages:
- cmake
- protobuf
- - py36-protobuf
+ - py37-protobuf
- opus
- qt5-core
- qt5-qmake
From 861c0dbaa3b1326dc5bba358316e4c0d7c1ad3c1 Mon Sep 17 00:00:00 2001
From: Gabi Alb
Date: Wed, 15 Jan 2020 20:09:11 +0200
Subject: [PATCH 018/291] Fix H264 codec finding for libavcodec < 58.10.100
(#143)
---
gui/src/videodecoder.cpp | 3 +++
1 file changed, 3 insertions(+)
diff --git a/gui/src/videodecoder.cpp b/gui/src/videodecoder.cpp
index bd3f965..4937142 100644
--- a/gui/src/videodecoder.cpp
+++ b/gui/src/videodecoder.cpp
@@ -23,6 +23,9 @@
VideoDecoder::VideoDecoder(ChiakiLog *log) : log(log)
{
+ #if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(58, 10, 100)
+ avcodec_register_all();
+ #endif
codec = avcodec_find_decoder(AV_CODEC_ID_H264);
if(!codec)
throw VideoDecoderException("H264 Codec not available");
From d7372394a285b41fc7b60918b207ba885090f4a4 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Florian=20M=C3=A4rkl?=
Date: Wed, 15 Jan 2020 21:23:45 +0100
Subject: [PATCH 019/291] Enhance Dockerfile
---
scripts/Dockerfile | 79 +++++++++++++++++----------------------
scripts/Dockerfile.ubuntu | 57 ----------------------------
scripts/docker-run.sh | 13 +++++++
3 files changed, 48 insertions(+), 101 deletions(-)
delete mode 100644 scripts/Dockerfile.ubuntu
create mode 100755 scripts/docker-run.sh
diff --git a/scripts/Dockerfile b/scripts/Dockerfile
index 124a975..87bfbe9 100644
--- a/scripts/Dockerfile
+++ b/scripts/Dockerfile
@@ -1,52 +1,43 @@
-# Run chiaki in a container
-# xhost +"local:docker@"
-# docker run -v $HOME/chiaki:/home/ps4/.local/share/Chiaki \
-# -v /tmp/.X11-unix:/tmp/.X11-unix \
-# --net host \
-# -e DISPLAY=$DISPLAY \
-# --device /dev/snd \
-# --name chiaki
-# --rm \
-# strubbl_chiaki
-FROM alpine:3 AS builder
-LABEL maintainer="Strubbl "
+FROM utensils/opengl:19.0.8 AS builder
+LABEL maintainer="chiaki-docker@florianmaerkl.de"
WORKDIR /app
RUN echo "@testing http://dl-cdn.alpinelinux.org/alpine/edge/testing" >> /etc/apk/repositories \
- && apk update \
- && apk --no-cache add \
- build-base \
- cmake \
- ffmpeg-dev \
- git \
- openssl \
- opus-dev \
- protobuf \
- py3-protobuf@testing \
- qt5-qtbase \
- qt5-qtmultimedia-dev \
- qt5-qtsvg-dev \
- sdl2-dev \
- && git clone https://github.com/thestr4ng3r/chiaki.git /app \
- && git submodule update --init \
- && mkdir build \
- && cd build \
- && cmake .. \
- && make \
- && ./test/chiaki-unit \
- && rm -rf /var/cache/apk/*
+ && apk update \
+ && apk --no-cache add \
+ build-base \
+ cmake \
+ ffmpeg-dev \
+ git \
+ openssl \
+ opus-dev \
+ protobuf \
+# py3-protobuf@testing \ # Enable this when the OpenGL image updates alpine
+ qt5-qtbase \
+ qt5-qtmultimedia-dev \
+ qt5-qtsvg-dev \
+ sdl2-dev \
+ && pip3 install protobuf \
+ && git clone https://github.com/thestr4ng3r/chiaki.git /app \
+ && git submodule update --init \
+ && mkdir build \
+ && cd build \
+ && cmake .. \
+ && make \
+ && ./test/chiaki-unit \
+ && rm -rf /var/cache/apk/*
-FROM alpine:3
+FROM utensils/opengl:19.0.8
RUN apk update \
- && apk --no-cache add \
- ffmpeg \
- qt5-qtbase \
- qt5-qtmultimedia \
- qt5-qtsvg \
- sdl2 \
- && rm -rf /var/cache/apk/* \
- && addgroup ps4 && adduser -D -G ps4 ps4 \
- && chown -R ps4: /home/ps4
+ && apk --no-cache add \
+ ffmpeg \
+ qt5-qtbase \
+ qt5-qtmultimedia \
+ qt5-qtsvg \
+ sdl2 \
+ && rm -rf /var/cache/apk/* \
+ && addgroup ps4 && adduser -D -G ps4 ps4 \
+ && chown -R ps4: /home/ps4
WORKDIR /home/ps4
COPY --from=builder /app/build/gui/chiaki .
USER ps4
diff --git a/scripts/Dockerfile.ubuntu b/scripts/Dockerfile.ubuntu
deleted file mode 100644
index 9c862ee..0000000
--- a/scripts/Dockerfile.ubuntu
+++ /dev/null
@@ -1,57 +0,0 @@
-# Run chiaki in a container
-# docker run -v $HOME/chiaki:/home/ps4/.local/share/Chiaki \
-# -v /tmp/.X11-unix:/tmp/.X11-unix \
-# --net host \
-# -e DISPLAY=$DISPLAY \
-# --device /dev/snd \
-# --name chiaki
-# --rm \
-# strubbl_chiaki
-
-FROM ubuntu:19.04 AS builder
-LABEL maintainer="Strubbl "
-ENV DEBIAN_FRONTEND noninteractive
-WORKDIR /app
-RUN apt-get update \
- && apt-get install -y \
- build-essential \
- cmake \
- git \
- protobuf-compiler \
- libavcodec-dev \
- libavutil-dev \
- libopus-dev \
- libqt5svg5-dev \
- libsdl2-dev \
- libssl-dev \
- python3 \
- python3-distutils \
- python3-protobuf \
- qt5-default \
- qtmultimedia5-dev \
- && git clone https://github.com/thestr4ng3r/chiaki.git /app \
- && git submodule update --init \
- && mkdir build \
- && cd build \
- && cmake .. \
- && make
-
-FROM ubuntu:19.04
-ENV DEBIAN_FRONTEND noninteractive
-RUN apt-get update \
- && apt-get install -y \
- libavcodec58 \
- libavutil56 \
- libopus0 \
- libqt5multimedia5 \
- libqt5svg5 \
- libsdl2-2.0-0 \
- --no-install-recommends \
- && rm -rf /var/lib/apt/lists/* \
- && useradd -ms /bin/bash ps4
-WORKDIR /home/ps4
-USER ps4
-COPY --from=builder /app/build/gui/chiaki .
-VOLUME /home/ps4/.local/share/Chiaki
-ENTRYPOINT ["/home/ps4/chiaki"]
-
diff --git a/scripts/docker-run.sh b/scripts/docker-run.sh
new file mode 100755
index 0000000..55ee2ea
--- /dev/null
+++ b/scripts/docker-run.sh
@@ -0,0 +1,13 @@
+#!/bin/bash
+
+docker run \
+ -v $HOME/.local/share/Chiaki:/home/ps4/.local/share/Chiaki \
+ -v $HOME/.config/Chiaki:/home/ps4/.config/Chiaki \
+ -v /tmp/.X11-unix:/tmp/.X11-unix \
+ --net host \
+ -e DISPLAY=$DISPLAY \
+ --device /dev/snd \
+ --name chiaki \
+ --rm \
+ thestr4ng3r/chiaki
+
From 4b171378553d7a2a2fcda2d51a52ad891baf20af Mon Sep 17 00:00:00 2001
From: FearlessSpiff
Date: Sun, 26 Jan 2020 11:33:57 +0100
Subject: [PATCH 020/291] Add Stream Display Options: Normal, Zoom and Stretch
(#146)
---
.../metallic/chiaki/stream/StreamActivity.kt | 93 +++++++++++++++----
.../stream_material_button_icon_tint.xml | 5 +
.../main/res/drawable/ic_display_normal.xml | 9 ++
.../main/res/drawable/ic_display_stretch.xml | 9 ++
.../src/main/res/drawable/ic_display_zoom.xml | 13 +++
.../src/main/res/layout/activity_stream.xml | 41 +++++++-
6 files changed, 147 insertions(+), 23 deletions(-)
create mode 100644 android/app/src/main/res/color/stream_material_button_icon_tint.xml
create mode 100644 android/app/src/main/res/drawable/ic_display_normal.xml
create mode 100644 android/app/src/main/res/drawable/ic_display_stretch.xml
create mode 100644 android/app/src/main/res/drawable/ic_display_zoom.xml
diff --git a/android/app/src/main/java/com/metallic/chiaki/stream/StreamActivity.kt b/android/app/src/main/java/com/metallic/chiaki/stream/StreamActivity.kt
index eee3908..40be5f9 100644
--- a/android/app/src/main/java/com/metallic/chiaki/stream/StreamActivity.kt
+++ b/android/app/src/main/java/com/metallic/chiaki/stream/StreamActivity.kt
@@ -25,6 +25,7 @@ import android.os.Bundle
import android.os.Handler
import android.view.KeyEvent
import android.view.MotionEvent
+import android.view.TextureView
import android.view.View
import android.widget.EditText
import androidx.appcompat.app.AppCompatActivity
@@ -38,6 +39,7 @@ import com.metallic.chiaki.common.LogManager
import com.metallic.chiaki.common.Preferences
import com.metallic.chiaki.common.ext.viewModelFactory
import com.metallic.chiaki.lib.ConnectInfo
+import com.metallic.chiaki.lib.ConnectVideoProfile
import com.metallic.chiaki.session.*
import com.metallic.chiaki.touchcontrols.TouchpadOnlyFragment
import com.metallic.chiaki.touchcontrols.TouchControlsFragment
@@ -99,6 +101,17 @@ class StreamActivity : AppCompatActivity(), View.OnSystemUiVisibilityChangeListe
showOverlay()
}
+ displayModeToggle.addOnButtonCheckedListener {group, checkedId, _ ->
+ // following 'if' is a workaround until selectionRequired for MaterialButtonToggleGroup
+ // comes out of alpha.
+ // See https://stackoverflow.com/questions/56164004/required-single-selection-on-materialbuttontogglegroup
+ if (displayModeToggle.checkedButtonId == -1)
+ displayModeToggle.check(checkedId)
+
+ adjustTextureViewAspect()
+ showOverlay()
+ }
+
viewModel.session.attachToTextureView(textureView)
viewModel.session.state.observe(this, Observer { this.stateChanged(it) })
textureView.addOnLayoutChangeListener { _, _, _, _, _, _, _, _, _ ->
@@ -294,33 +307,73 @@ class StreamActivity : AppCompatActivity(), View.OnSystemUiVisibilityChangeListe
private fun adjustTextureViewAspect()
{
- val contentWidth = viewModel.session.connectInfo.videoProfile.width.toFloat()
- val contentHeight = viewModel.session.connectInfo.videoProfile.height.toFloat()
- val viewWidth = textureView.width.toFloat()
- val viewHeight = textureView.height.toFloat()
- val contentAspect = contentHeight / contentWidth
-
- val width: Float
- val height: Float
- if(viewHeight > viewWidth * contentAspect)
- {
- width = viewWidth
- height = viewWidth * contentAspect
- }
- else
- {
- width = viewHeight / contentAspect
- height = viewHeight
- }
+ val displayInfo = DisplayInfo(viewModel.session.connectInfo.videoProfile, textureView)
+ val resolution = displayInfo.computeResolutionFor(displayModeToggle.checkedButtonId)
Matrix().also {
textureView.getTransform(it)
- it.setScale(width / viewWidth, height / viewHeight)
- it.postTranslate((viewWidth - width) * 0.5f, (viewHeight - height) * 0.5f)
+ it.setScale(resolution.width / displayInfo.viewWidth, resolution.height / displayInfo.viewHeight)
+ it.postTranslate((displayInfo.viewWidth - resolution.width) * 0.5f, (displayInfo.viewHeight - resolution.height) * 0.5f)
textureView.setTransform(it)
}
}
override fun dispatchKeyEvent(event: KeyEvent) = viewModel.input.dispatchKeyEvent(event) || super.dispatchKeyEvent(event)
override fun onGenericMotionEvent(event: MotionEvent) = viewModel.input.onGenericMotionEvent(event) || super.onGenericMotionEvent(event)
+
}
+
+
+class DisplayInfo constructor(val videoProfile: ConnectVideoProfile, val textureView: TextureView)
+{
+ val contentWidth : Float get() = videoProfile.width.toFloat()
+ val contentHeight : Float get() = videoProfile.height.toFloat()
+ val viewWidth : Float get() = textureView.width.toFloat()
+ val viewHeight : Float get() = textureView.height.toFloat()
+ val contentAspect : Float get() = contentHeight / contentWidth
+
+ fun computeResolutionFor(displayModeButtonId: Int) : Resolution
+ {
+ when (displayModeButtonId)
+ {
+ R.id.display_mode_stretch_button -> return computeStrechedResolution()
+ R.id.display_mode_zoom_button -> return computeZoomedResolution()
+ else -> return computeNormalResolution()
+ }
+ }
+
+ private fun computeStrechedResolution(): Resolution
+ {
+ return Resolution(viewWidth, viewHeight)
+ }
+
+ private fun computeZoomedResolution(): Resolution
+ {
+ if (viewHeight > viewWidth * contentAspect)
+ {
+ val zoomFactor = viewHeight / contentHeight
+ return Resolution(contentWidth * zoomFactor, viewHeight)
+ }
+ else
+ {
+ val zoomFactor = viewWidth / contentWidth
+ return Resolution(viewWidth, contentHeight * zoomFactor)
+ }
+ }
+
+ private fun computeNormalResolution(): Resolution
+ {
+ if (viewHeight > viewWidth * contentAspect)
+ {
+ return Resolution(viewWidth, viewWidth * contentAspect)
+ }
+ else
+ {
+ return Resolution(viewHeight / contentAspect, viewHeight)
+ }
+ }
+
+}
+
+
+data class Resolution(val width: Float, val height: Float)
diff --git a/android/app/src/main/res/color/stream_material_button_icon_tint.xml b/android/app/src/main/res/color/stream_material_button_icon_tint.xml
new file mode 100644
index 0000000..fbfbf5c
--- /dev/null
+++ b/android/app/src/main/res/color/stream_material_button_icon_tint.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/android/app/src/main/res/drawable/ic_display_normal.xml b/android/app/src/main/res/drawable/ic_display_normal.xml
new file mode 100644
index 0000000..4ffbf8f
--- /dev/null
+++ b/android/app/src/main/res/drawable/ic_display_normal.xml
@@ -0,0 +1,9 @@
+
+
+
\ No newline at end of file
diff --git a/android/app/src/main/res/drawable/ic_display_stretch.xml b/android/app/src/main/res/drawable/ic_display_stretch.xml
new file mode 100644
index 0000000..605cf01
--- /dev/null
+++ b/android/app/src/main/res/drawable/ic_display_stretch.xml
@@ -0,0 +1,9 @@
+
+
+
\ No newline at end of file
diff --git a/android/app/src/main/res/drawable/ic_display_zoom.xml b/android/app/src/main/res/drawable/ic_display_zoom.xml
new file mode 100644
index 0000000..c260698
--- /dev/null
+++ b/android/app/src/main/res/drawable/ic_display_zoom.xml
@@ -0,0 +1,13 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/android/app/src/main/res/layout/activity_stream.xml b/android/app/src/main/res/layout/activity_stream.xml
index 770c42c..c320d3f 100644
--- a/android/app/src/main/res/layout/activity_stream.xml
+++ b/android/app/src/main/res/layout/activity_stream.xml
@@ -34,8 +34,6 @@
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="bottom"
- tools:paddingRight="12dp"
- tools:paddingTop="25dp"
android:fitsSystemWindows="true">
-
+
+
+
+
+
+
+
+
+
\ No newline at end of file
From 945dc697cc9d8f86e5b6fb37b3bd5ce3df4debaf Mon Sep 17 00:00:00 2001
From: FearlessSpiff
Date: Mon, 27 Jan 2020 21:30:22 +0100
Subject: [PATCH 021/291] Add Flag to keep the Screen Awake in the
StreamActivity (Fix #114) (#149)
---
android/app/src/main/res/layout/activity_stream.xml | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/android/app/src/main/res/layout/activity_stream.xml b/android/app/src/main/res/layout/activity_stream.xml
index c320d3f..255ccde 100644
--- a/android/app/src/main/res/layout/activity_stream.xml
+++ b/android/app/src/main/res/layout/activity_stream.xml
@@ -4,7 +4,8 @@
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:app="http://schemas.android.com/apk/res-auto"
- tools:context=".stream.StreamActivity">
+ tools:context=".stream.StreamActivity"
+ android:keepScreenOn="true">
Date: Mon, 27 Jan 2020 21:32:36 +0100
Subject: [PATCH 022/291] Version 1.1.3
---
CMakeLists.txt | 2 +-
android/app/build.gradle | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/CMakeLists.txt b/CMakeLists.txt
index f4108ee..90529e0 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -15,7 +15,7 @@ option(CHIAKI_CLI_ARGP_STANDALONE "Search for standalone argp lib for CLI" OFF)
set(CHIAKI_VERSION_MAJOR 1)
set(CHIAKI_VERSION_MINOR 1)
-set(CHIAKI_VERSION_PATCH 2)
+set(CHIAKI_VERSION_PATCH 3)
set(CHIAKI_VERSION ${CHIAKI_VERSION_MAJOR}.${CHIAKI_VERSION_MINOR}.${CHIAKI_VERSION_PATCH})
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake")
diff --git a/android/app/build.gradle b/android/app/build.gradle
index ae37d9a..db962f9 100644
--- a/android/app/build.gradle
+++ b/android/app/build.gradle
@@ -24,7 +24,7 @@ android {
applicationId "com.metallic.chiaki"
minSdkVersion 21
targetSdkVersion 29
- versionCode 3
+ versionCode 4
versionName chiakiVersion
externalNativeBuild {
cmake {
From a0aaa1178871b00b60d1e4dd0fa8c3361af7ce27 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Florian=20M=C3=A4rkl?=
Date: Tue, 28 Jan 2020 21:42:52 +0100
Subject: [PATCH 023/291] Build SDL2 with udev on Linux (for #32)
---
.travis.yml | 1 +
1 file changed, 1 insertion(+)
diff --git a/.travis.yml b/.travis.yml
index 11f706c..4dbcca6 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -56,6 +56,7 @@ matrix:
- qt512svg
- libgl1-mesa-dev
- nasm
+ - libudev-dev
env:
- CMAKE_PREFIX_PATH="$TRAVIS_BUILD_DIR/ffmpeg-prefix;$TRAVIS_BUILD_DIR/sdl2-prefix;/opt/qt512"
- CMAKE_EXTRA_ARGS="-DCMAKE_INSTALL_PREFIX=/usr"
From 5bf530d56df09bdab4c6bb0cf49106baff626c29 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Florian=20M=C3=A4rkl?=
Date: Tue, 28 Jan 2020 22:09:33 +0100
Subject: [PATCH 024/291] Add oshi.at upload from Travis (#153)
---
.travis.yml | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/.travis.yml b/.travis.yml
index 4dbcca6..606f380 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -145,7 +145,9 @@ before_install:
- if [ ! -z "$encrypted_31d5e6477a29_iv" ]; then openssl aes-256-cbc -K $encrypted_31d5e6477a29_key -iv $encrypted_31d5e6477a29_iv -in secret.tar.enc -out secret.tar -d && tar -xf secret.tar; fi
after_success:
- - if [ ! -z "$DEPLOY_FILE" ]; then curl -m 30 --upload-file "$DEPLOY_FILE" "https://transfer.sh/$DEPLOY_FILE"; echo; fi
+ - if [ ! -z "$DEPLOY_FILE" ]; then echo "--- SHA256 for $DEPLOY_FILE"; openssl dgst -sha256 "$DEPLOY_FILE"; echo; fi
+ - if [ ! -z "$DEPLOY_FILE" ]; then echo "--- transfer.sh"; curl -m 30 --upload-file "$DEPLOY_FILE" "https://transfer.sh/$DEPLOY_FILE"; echo; fi
+ - if [ ! -z "$DEPLOY_FILE" ]; then echo "--- oshi.at"; curl -m 30 --upload-file "$DEPLOY_FILE" "https://oshi.at/$DEPLOY_FILE/129600"; echo; fi
deploy:
skip_cleanup: true
From fe1e3835f8f5a46bcc9c9b2f3d5e558f6c15dfb2 Mon Sep 17 00:00:00 2001
From: 3kinox <42655690+3kinox@users.noreply.github.com>
Date: Sun, 16 Feb 2020 17:59:09 +0100
Subject: [PATCH 025/291] Use Mouse Click for Touchpad Button in GUI (#167)
---
gui/include/streamsession.h | 2 ++
gui/include/streamwindow.h | 2 ++
gui/src/streamsession.cpp | 9 +++++++++
gui/src/streamwindow.cpp | 12 ++++++++++++
4 files changed, 25 insertions(+)
diff --git a/gui/include/streamsession.h b/gui/include/streamsession.h
index a6ca741..721270b 100644
--- a/gui/include/streamsession.h
+++ b/gui/include/streamsession.h
@@ -28,6 +28,7 @@
#include
#include
+#include
#if CHIAKI_GUI_ENABLE_QT_GAMEPAD
class QGamepad;
@@ -105,6 +106,7 @@ class StreamSession : public QObject
VideoDecoder *GetVideoDecoder() { return &video_decoder; }
void HandleKeyboardEvent(QKeyEvent *event);
+ void HandleMouseEvent(QMouseEvent *event);
signals:
void CurrentImageUpdated();
diff --git a/gui/include/streamwindow.h b/gui/include/streamwindow.h
index 5e67e6e..3e664bc 100644
--- a/gui/include/streamwindow.h
+++ b/gui/include/streamwindow.h
@@ -44,6 +44,8 @@ class StreamWindow: public QMainWindow
void keyPressEvent(QKeyEvent *event) override;
void keyReleaseEvent(QKeyEvent *event) override;
void closeEvent(QCloseEvent *event) override;
+ void mousePressEvent(QMouseEvent *event) override;
+ void mouseReleaseEvent(QMouseEvent *event) override;
private slots:
void SessionQuit(ChiakiQuitReason reason, const QString &reason_str);
diff --git a/gui/src/streamsession.cpp b/gui/src/streamsession.cpp
index 2b4eafa..e4edf59 100644
--- a/gui/src/streamsession.cpp
+++ b/gui/src/streamsession.cpp
@@ -141,6 +141,15 @@ void StreamSession::SetLoginPIN(const QString &pin)
chiaki_session_set_login_pin(&session, (const uint8_t *)data.constData(), data.size());
}
+void StreamSession::HandleMouseEvent(QMouseEvent *event)
+{
+ if(event->type() == QEvent::MouseButtonPress)
+ keyboard_state.buttons |= CHIAKI_CONTROLLER_BUTTON_TOUCHPAD;
+ else
+ keyboard_state.buttons &= ~CHIAKI_CONTROLLER_BUTTON_TOUCHPAD;
+ SendFeedbackState();
+}
+
void StreamSession::HandleKeyboardEvent(QKeyEvent *event)
{
uint64_t button_mask;
diff --git a/gui/src/streamwindow.cpp b/gui/src/streamwindow.cpp
index cfddbda..91ae8b0 100644
--- a/gui/src/streamwindow.cpp
+++ b/gui/src/streamwindow.cpp
@@ -86,6 +86,18 @@ void StreamWindow::keyReleaseEvent(QKeyEvent *event)
session->HandleKeyboardEvent(event);
}
+void StreamWindow::mousePressEvent(QMouseEvent *event)
+{
+ if(session)
+ session->HandleMouseEvent(event);
+}
+
+void StreamWindow::mouseReleaseEvent(QMouseEvent *event)
+{
+ if(session)
+ session->HandleMouseEvent(event);
+}
+
void StreamWindow::closeEvent(QCloseEvent *)
{
if(session)
From d9773c55e0a83d61ec8a56816e258f927f9ba720 Mon Sep 17 00:00:00 2001
From: Ritiek Malhotra
Date: Wed, 19 Feb 2020 23:03:00 +0530
Subject: [PATCH 026/291] Add wakeup command to CLI (#168)
---
cli/CMakeLists.txt | 3 +-
cli/include/chiaki-cli.h | 1 +
cli/src/main.c | 5 ++-
cli/src/wakeup.c | 92 ++++++++++++++++++++++++++++++++++++++++
gui/src/main.cpp | 3 +-
5 files changed, 101 insertions(+), 3 deletions(-)
create mode 100644 cli/src/wakeup.c
diff --git a/cli/CMakeLists.txt b/cli/CMakeLists.txt
index c718185..83c37a9 100644
--- a/cli/CMakeLists.txt
+++ b/cli/CMakeLists.txt
@@ -1,7 +1,8 @@
set(SOURCE
include/chiaki-cli.h
- src/discover.c)
+ src/discover.c
+ src/wakeup.c)
add_library(chiaki-cli-lib STATIC ${SOURCE})
target_include_directories(chiaki-cli-lib PUBLIC "include")
diff --git a/cli/include/chiaki-cli.h b/cli/include/chiaki-cli.h
index 0bd1e1b..13743e0 100644
--- a/cli/include/chiaki-cli.h
+++ b/cli/include/chiaki-cli.h
@@ -26,6 +26,7 @@ extern "C" {
#endif
CHIAKI_EXPORT int chiaki_cli_cmd_discover(ChiakiLog *log, int argc, char *argv[]);
+CHIAKI_EXPORT int chiaki_cli_cmd_wakeup(ChiakiLog *log, int argc, char *argv[]);
#ifdef __cplusplus
}
diff --git a/cli/src/main.c b/cli/src/main.c
index 7395ba8..05f0b4c 100644
--- a/cli/src/main.c
+++ b/cli/src/main.c
@@ -27,7 +27,8 @@ static const char doc[] =
"CLI for Chiaki (PS4 Remote Play Client)"
"\v"
"Supported commands are:\n"
- " discover Discover Consoles.\n";
+ " discover Discover Consoles.\n"
+ " wakeup Send Wakeup Packet.\n";
#define ARG_KEY_VERBOSE 'v'
@@ -73,6 +74,8 @@ static int parse_opt(int key, char *arg, struct argp_state *state)
case ARGP_KEY_ARG:
if(strcmp(arg, "discover") == 0)
exit(call_subcmd(state, "discover", chiaki_cli_cmd_discover));
+ else if(strcmp(arg, "wakeup") == 0)
+ exit(call_subcmd(state, "wakeup", chiaki_cli_cmd_wakeup));
// fallthrough
case ARGP_KEY_END:
argp_usage(state);
diff --git a/cli/src/wakeup.c b/cli/src/wakeup.c
new file mode 100644
index 0000000..06a6220
--- /dev/null
+++ b/cli/src/wakeup.c
@@ -0,0 +1,92 @@
+/*
+ * 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 .
+ */
+
+#include
+
+#include
+
+#include
+#include
+
+static char doc[] = "Send a PS4 wakeup packet.";
+
+#define ARG_KEY_HOST 'h'
+#define ARG_KEY_REGISTKEY 'r'
+
+static struct argp_option options[] = {
+ { "host", ARG_KEY_HOST, "Host", 0, "Host to send wakeup packet to", 0 },
+ { "registkey", ARG_KEY_REGISTKEY, "RegistKey", 0, "PS4 registration key", 0 },
+ { 0 }
+};
+
+typedef struct arguments
+{
+ const char *host;
+ const char *registkey;
+} Arguments;
+
+static int parse_opt(int key, char *arg, struct argp_state *state)
+{
+ Arguments *arguments = state->input;
+
+ switch(key)
+ {
+ case ARG_KEY_HOST:
+ arguments->host = arg;
+ break;
+ case ARG_KEY_REGISTKEY:
+ arguments->registkey = arg;
+ break;
+ case ARGP_KEY_ARG:
+ argp_usage(state);
+ break;
+ default:
+ return ARGP_ERR_UNKNOWN;
+ }
+
+ return 0;
+}
+
+static struct argp argp = { options, parse_opt, 0, doc, 0, 0, 0 };
+
+CHIAKI_EXPORT int chiaki_cli_cmd_wakeup(ChiakiLog *log, int argc, char *argv[])
+{
+ Arguments arguments = { 0 };
+ error_t argp_r = argp_parse(&argp, argc, argv, ARGP_IN_ORDER, NULL, &arguments);
+ if(argp_r != 0)
+ return 1;
+
+ if(!arguments.host)
+ {
+ fprintf(stderr, "No host specified, see --help.\n");
+ return 1;
+ }
+ if(!arguments.registkey)
+ {
+ fprintf(stderr, "No registration key specified, see --help.\n");
+ return 1;
+ }
+ if(strlen(arguments.registkey) > 8)
+ {
+ fprintf(stderr, "Given registkey is too long.\n");
+ return 1;
+ }
+
+ uint64_t credential = (uint64_t)strtoull(arguments.registkey, NULL, 16);
+
+ return chiaki_discovery_wakeup(log, NULL, arguments.host, credential);
+}
diff --git a/gui/src/main.cpp b/gui/src/main.cpp
index ec5ec30..3a2b449 100644
--- a/gui/src/main.cpp
+++ b/gui/src/main.cpp
@@ -40,7 +40,8 @@ struct CLICommand
};
static const QMap cli_commands = {
- { "discover", { chiaki_cli_cmd_discover } }
+ { "discover", { chiaki_cli_cmd_discover } },
+ { "wakeup", { chiaki_cli_cmd_wakeup } }
};
#endif
From a605ba083d1cfde8154c6372446440bee5d5d0eb Mon Sep 17 00:00:00 2001
From: Felipe Lavratti
Date: Sat, 29 Feb 2020 11:38:03 -0300
Subject: [PATCH 027/291] GUI: Add settings for keyboard mapping (#174)
---
gui/CMakeLists.txt | 2 +
gui/include/settings.h | 18 +++++
gui/include/settingskeycapturedialog.h | 37 ++++++++++
gui/include/streamsession.h | 5 +-
gui/src/settings.cpp | 97 ++++++++++++++++++++++++++
gui/src/settingsdialog.cpp | 61 +++++++++++++---
gui/src/settingskeycapturedialog.cpp | 45 ++++++++++++
gui/src/streamsession.cpp | 79 ++++++++++-----------
8 files changed, 292 insertions(+), 52 deletions(-)
create mode 100644 gui/include/settingskeycapturedialog.h
create mode 100644 gui/src/settingskeycapturedialog.cpp
diff --git a/gui/CMakeLists.txt b/gui/CMakeLists.txt
index 76aec59..072320f 100644
--- a/gui/CMakeLists.txt
+++ b/gui/CMakeLists.txt
@@ -60,6 +60,8 @@ add_executable(chiaki WIN32
src/registdialog.cpp
include/host.h
src/host.cpp
+ include/settingskeycapturedialog.h
+ src/settingskeycapturedialog.cpp
include/settingsdialog.h
src/settingsdialog.cpp
include/manualhostdialog.h
diff --git a/gui/include/settings.h b/gui/include/settings.h
index 71cff6c..e15a56a 100644
--- a/gui/include/settings.h
+++ b/gui/include/settings.h
@@ -24,6 +24,19 @@
#include
+enum class ControllerButtonExt
+{
+ // must not overlap with ChiakiControllerButton and ChiakiControllerAnalogButton
+ ANALOG_STICK_LEFT_X_UP = (1 << 18),
+ ANALOG_STICK_LEFT_X_DOWN = (1 << 19),
+ ANALOG_STICK_LEFT_Y_UP = (1 << 20),
+ ANALOG_STICK_LEFT_Y_DOWN = (1 << 21),
+ ANALOG_STICK_RIGHT_X_UP = (1 << 22),
+ ANALOG_STICK_RIGHT_X_DOWN = (1 << 23),
+ ANALOG_STICK_RIGHT_Y_UP = (1 << 24),
+ ANALOG_STICK_RIGHT_Y_DOWN = (1 << 25),
+};
+
class Settings : public QObject
{
Q_OBJECT
@@ -90,6 +103,11 @@ class Settings : public QObject
bool GetManualHostExists(int id) { return manual_hosts.contains(id); }
ManualHost GetManualHost(int id) const { return manual_hosts[id]; }
+ static QString GetChiakiControllerButtonName(int);
+ void SetControllerButtonMapping(int, Qt::Key);
+ QMap GetControllerMapping();
+ QMap GetControllerMappingForDecoding();
+
signals:
void RegisteredHostsUpdated();
void ManualHostsUpdated();
diff --git a/gui/include/settingskeycapturedialog.h b/gui/include/settingskeycapturedialog.h
new file mode 100644
index 0000000..a4d7b36
--- /dev/null
+++ b/gui/include/settingskeycapturedialog.h
@@ -0,0 +1,37 @@
+/*
+ * 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 .
+ */
+
+#ifndef CHIAKI_SETTINGSKEYCAPTUREDIALOG_H
+#define CHIAKI_SETTINGSKEYCAPTUREDIALOG_H
+
+#include
+
+class SettingsKeyCaptureDialog : public QDialog
+{
+ Q_OBJECT
+
+ signals:
+ void KeyCaptured(Qt::Key);
+
+ protected:
+ void keyReleaseEvent(QKeyEvent *event) override;
+
+ public:
+ explicit SettingsKeyCaptureDialog(QWidget *parent = nullptr);
+};
+
+#endif // CHIAKI_SETTINGSKEYCAPTUREDIALOG_H
diff --git a/gui/include/streamsession.h b/gui/include/streamsession.h
index 721270b..fabb634 100644
--- a/gui/include/streamsession.h
+++ b/gui/include/streamsession.h
@@ -29,6 +29,7 @@
#include
#include
#include
+#include
#if CHIAKI_GUI_ENABLE_QT_GAMEPAD
class QGamepad;
@@ -47,6 +48,7 @@ class ChiakiException: public Exception
struct StreamSessionConnectInfo
{
+ QMap key_map;
uint32_t log_level_mask;
QString log_file;
QString host;
@@ -55,7 +57,6 @@ struct StreamSessionConnectInfo
ChiakiConnectVideoProfile video_profile;
unsigned int audio_buffer_size;
- StreamSessionConnectInfo();
StreamSessionConnectInfo(Settings *settings, QString host, QByteArray regist_key, QByteArray morning);
};
@@ -83,6 +84,8 @@ class StreamSession : public QObject
QAudioOutput *audio_output;
QIODevice *audio_io;
+ QMap key_map;
+
void PushAudioFrame(int16_t *buf, size_t samples_count);
void PushVideoSample(uint8_t *buf, size_t buf_size);
void Event(ChiakiEvent *event);
diff --git a/gui/src/settings.cpp b/gui/src/settings.cpp
index b74552b..559c4e4 100644
--- a/gui/src/settings.cpp
+++ b/gui/src/settings.cpp
@@ -16,6 +16,7 @@
*/
#include
+#include
#define SETTINGS_VERSION 1
@@ -207,3 +208,99 @@ void Settings::RemoveManualHost(int id)
SaveManualHosts();
emit ManualHostsUpdated();
}
+
+QString Settings::GetChiakiControllerButtonName(int button)
+{
+ switch(button)
+ {
+ case CHIAKI_CONTROLLER_BUTTON_CROSS : return tr("Cross");
+ case CHIAKI_CONTROLLER_BUTTON_MOON : return tr("Moon");
+ case CHIAKI_CONTROLLER_BUTTON_BOX : return tr("Box");
+ case CHIAKI_CONTROLLER_BUTTON_PYRAMID : return tr("Pyramid");
+ case CHIAKI_CONTROLLER_BUTTON_DPAD_LEFT : return tr("D-Pad Left");
+ case CHIAKI_CONTROLLER_BUTTON_DPAD_RIGHT : return tr("D-Pad Right");
+ case CHIAKI_CONTROLLER_BUTTON_DPAD_UP : return tr("D-Pad Up");
+ case CHIAKI_CONTROLLER_BUTTON_DPAD_DOWN : return tr("D-Pad Down");
+ case CHIAKI_CONTROLLER_BUTTON_L1 : return tr("L1");
+ case CHIAKI_CONTROLLER_BUTTON_R1 : return tr("R1");
+ case CHIAKI_CONTROLLER_BUTTON_L3 : return tr("L3");
+ case CHIAKI_CONTROLLER_BUTTON_R3 : return tr("R3");
+ case CHIAKI_CONTROLLER_BUTTON_OPTIONS : return tr("Options");
+ case CHIAKI_CONTROLLER_BUTTON_SHARE : return tr("Share");
+ case CHIAKI_CONTROLLER_BUTTON_TOUCHPAD : return tr("Touchpad");
+ case CHIAKI_CONTROLLER_BUTTON_PS : return tr("PS");
+ case CHIAKI_CONTROLLER_ANALOG_BUTTON_L2 : return tr("L2");
+ case CHIAKI_CONTROLLER_ANALOG_BUTTON_R2 : return tr("R2");
+ case static_cast(ControllerButtonExt::ANALOG_STICK_LEFT_X_UP) : return tr("Left Stick Right");
+ case static_cast(ControllerButtonExt::ANALOG_STICK_LEFT_Y_UP) : return tr("Left Stick Up");
+ case static_cast(ControllerButtonExt::ANALOG_STICK_RIGHT_X_UP) : return tr("Right Stick Right");
+ case static_cast(ControllerButtonExt::ANALOG_STICK_RIGHT_Y_UP) : return tr("Right Stick Up");
+ case static_cast(ControllerButtonExt::ANALOG_STICK_LEFT_X_DOWN) : return tr("Left Stick Left");
+ case static_cast(ControllerButtonExt::ANALOG_STICK_LEFT_Y_DOWN) : return tr("Left Stick Down");
+ case static_cast(ControllerButtonExt::ANALOG_STICK_RIGHT_X_DOWN) : return tr("Right Stick Left");
+ case static_cast(ControllerButtonExt::ANALOG_STICK_RIGHT_Y_DOWN) : return tr("Right Stick Down");
+ default: return "Unknown";
+ }
+}
+
+void Settings::SetControllerButtonMapping(int chiaki_button, Qt::Key key)
+{
+ auto button_name = GetChiakiControllerButtonName(chiaki_button).replace(' ', '_').toLower();
+ settings.setValue("keymap/" + button_name, QKeySequence(key).toString());
+}
+
+QMap Settings::GetControllerMapping()
+{
+ // Initialize with default values
+ QMap result =
+ {
+ {CHIAKI_CONTROLLER_BUTTON_CROSS , Qt::Key::Key_Return},
+ {CHIAKI_CONTROLLER_BUTTON_MOON , Qt::Key::Key_Backspace},
+ {CHIAKI_CONTROLLER_BUTTON_BOX , Qt::Key::Key_Backslash},
+ {CHIAKI_CONTROLLER_BUTTON_PYRAMID , Qt::Key::Key_C},
+ {CHIAKI_CONTROLLER_BUTTON_DPAD_LEFT , Qt::Key::Key_Left},
+ {CHIAKI_CONTROLLER_BUTTON_DPAD_RIGHT, Qt::Key::Key_Right},
+ {CHIAKI_CONTROLLER_BUTTON_DPAD_UP , Qt::Key::Key_Up},
+ {CHIAKI_CONTROLLER_BUTTON_DPAD_DOWN , Qt::Key::Key_Down},
+ {CHIAKI_CONTROLLER_BUTTON_L1 , Qt::Key::Key_2},
+ {CHIAKI_CONTROLLER_BUTTON_R1 , Qt::Key::Key_3},
+ {CHIAKI_CONTROLLER_BUTTON_L3 , Qt::Key::Key_5},
+ {CHIAKI_CONTROLLER_BUTTON_R3 , Qt::Key::Key_6},
+ {CHIAKI_CONTROLLER_BUTTON_OPTIONS , Qt::Key::Key_O},
+ {CHIAKI_CONTROLLER_BUTTON_SHARE , Qt::Key::Key_F},
+ {CHIAKI_CONTROLLER_BUTTON_TOUCHPAD , Qt::Key::Key_T},
+ {CHIAKI_CONTROLLER_BUTTON_PS , Qt::Key::Key_Escape},
+ {CHIAKI_CONTROLLER_ANALOG_BUTTON_L2 , Qt::Key::Key_1},
+ {CHIAKI_CONTROLLER_ANALOG_BUTTON_R2 , Qt::Key::Key_4},
+ {static_cast(ControllerButtonExt::ANALOG_STICK_LEFT_X_UP) , Qt::Key::Key_BracketRight},
+ {static_cast(ControllerButtonExt::ANALOG_STICK_LEFT_X_DOWN) , Qt::Key::Key_BracketLeft},
+ {static_cast(ControllerButtonExt::ANALOG_STICK_LEFT_Y_UP) , Qt::Key::Key_Insert},
+ {static_cast(ControllerButtonExt::ANALOG_STICK_LEFT_Y_DOWN) , Qt::Key::Key_Delete},
+ {static_cast(ControllerButtonExt::ANALOG_STICK_RIGHT_X_UP) , Qt::Key::Key_Equal},
+ {static_cast(ControllerButtonExt::ANALOG_STICK_RIGHT_X_DOWN), Qt::Key::Key_Minus},
+ {static_cast(ControllerButtonExt::ANALOG_STICK_RIGHT_Y_UP) , Qt::Key::Key_PageUp},
+ {static_cast(ControllerButtonExt::ANALOG_STICK_RIGHT_Y_DOWN), Qt::Key::Key_PageDown}
+ };
+
+ // Then fill in from settings
+ auto chiaki_buttons = result.keys();
+ for(auto chiaki_button : chiaki_buttons)
+ {
+ auto button_name = GetChiakiControllerButtonName(chiaki_button).replace(' ', '_').toLower();
+ if(settings.contains("keymap/" + button_name))
+ result[static_cast(chiaki_button)] = Qt::Key(QKeySequence(settings.value("keymap/" + button_name).toString())[0]);
+ }
+
+ return result;
+}
+
+QMap Settings::GetControllerMappingForDecoding()
+{
+ auto map = GetControllerMapping();
+ QMap result;
+ for(auto it = map.begin(); it != map.end(); ++it)
+ {
+ result[it.value()] = it.key();
+ }
+ return result;
+}
diff --git a/gui/src/settingsdialog.cpp b/gui/src/settingsdialog.cpp
index 86b47d9..30dc00a 100644
--- a/gui/src/settingsdialog.cpp
+++ b/gui/src/settingsdialog.cpp
@@ -17,9 +17,11 @@
#include
#include
+#include
#include
#include
+#include
#include
#include
#include
@@ -32,7 +34,6 @@
#include
#include
-
const char * const about_string =
"
Chiaki
by thestr4ng3r, version " CHIAKI_VERSION
""
@@ -46,21 +47,28 @@ const char * const about_string =
"MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the "
"GNU General Public License for more details.