Skip to content

Commit 6fba407

Browse files
authored
Merge pull request #57 from PiterWeb/main
v3.1 Remote Controller
2 parents 760fc3a + 91e0883 commit 6fba407

40 files changed

+438
-268
lines changed

README.md

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -123,8 +123,12 @@ finally go to the build/bin folder and your executables will be there.
123123

124124
If you are interested to contribute to this project you can follow this [guide](./CONTRIBUTING.md)
125125

126-
## Thanks to the ViGEm project ♥
127-
[ViGEmBus](https://github.com/nefarius/ViGEmBus) is making this project a reallity. We embed ViGEmBus Installation Wizard and ViGEmBus Client DLLS within the executable for Windows
126+
## Acknowledgements
127+
128+
### Thanks to jbdemonte/virtual-device ❤
129+
[jbdemonte/virtual-device](https://github.com/jbdemonte/virtual-device) is making this project a reality. This is the source of magic that enables RemoteController to generate virtual gamepads on Linux, is very fast and made in pure Go.
130+
### Thanks to the ViGEm project ❤
131+
[ViGEmBus](https://github.com/nefarius/ViGEmBus) is making this project a reallity. This is the source of magic that enables RemoteController to generate virtual gamepads on Windows. We embed ViGEmBus Installation Wizard and ViGEmBus Client DLLS within the executable for Windows
128132

129133
## Did you like the project 👍 ?
130134
You can give a star and review us on Product Hunt

docs/LINUX.md

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,18 @@
55
When you run RemoteController you will need to be sure to:
66

77
- Your user has read/write permissions for /dev/input/event/* and uinput devices
8-
- Example in Debian: sudo usermod -aG input $USER
8+
- Example in Debian:
9+
```sh
10+
sudo usermod -aG input $USER
11+
```
912
- Uinput module enabled
10-
- Example in Debian: sudo modprobe uinput
13+
- Check if it is loaded:
14+
- Example in Debian:
15+
```sh
16+
lsmod | grep uinput
17+
```
18+
- Load the module:
19+
- Example in Debian:
20+
```sh
21+
sudo modprobe uinput
22+
```

frontend/.npmrc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
engine-strict=true
1+
engine-strict=false

frontend/src/lib/detection/onwebsite.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// This file is used to determine if the app is running on the website(client only) or not.
1+
// This file is used to determine if the app is running on the website(vercel client only) or not.
22
const onwebsite = import.meta.env?.VITE_ON_WEBSITE === 'true';
33

44
// This will be true if using the linux client when browser opens

frontend/src/lib/gamepad/gamepad_hook.ts

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,3 +27,26 @@ export function cloneGamepad(gamepad: Gamepad): ClonedGamepad {
2727
index: gamepad.index
2828
};
2929
}
30+
31+
export function handleGamepad(controllerChannel: RTCDataChannel) {
32+
const sendGamepadData = () => {
33+
const gamepadData = navigator.getGamepads();
34+
35+
gamepadData.forEach((gamepad) => {
36+
if (!gamepad) return;
37+
38+
const serializedData = JSON.stringify(cloneGamepad(gamepad));
39+
controllerChannel.send(serializedData);
40+
});
41+
};
42+
43+
const gamepadLoop = () => {
44+
sendGamepadData();
45+
46+
// Continue the loop
47+
requestAnimationFrame(gamepadLoop);
48+
};
49+
50+
// Start the gamepad loop
51+
gamepadLoop();
52+
}

frontend/src/lib/i18n/LanguageSelector.svelte

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
<script lang="ts">
22
import {locale, locales, _ } from 'svelte-i18n';
33
4-
function setLocale(event: Event) {
4+
async function setLocale(event: Event) {
55
const target = event.target as HTMLButtonElement;
6-
locale.set(target.dataset.value);
6+
await locale.set(target.dataset.value);
77
}
88
99
function getLocaleName(locale: string) {

frontend/src/lib/i18n/en.json

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,5 +78,12 @@
7878
"tutorial_prev_text": "Previous",
7979
"tutorial_play_title": "You are ready to play",
8080
"tutorial_play_description": "Now select your prefered mode to play (in web there is only one) and follow the instructions inside",
81-
"share-the-code-with-your-client": "Share the code with your client"
81+
"share-the-code-with-your-client": "Share the code with your client",
82+
"go-browser": "You default browser should have been opened automatically (There are known issues in Firefox: We recommend using Chromium based Browsers)",
83+
"relay-title": "Go to the browser tab",
84+
"warning-go-browser": "Don't close the APP or go back in the menu",
85+
"resolutions": "Resolutions",
86+
"framerate": "Framerate",
87+
"ideal-framerate": "Ideal Framerate",
88+
"max-framerate": "Max Framerate"
8289
}

frontend/src/lib/i18n/es.json

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,5 +78,12 @@
7878
"tutorial_prev_text": "Anterior",
7979
"tutorial_play_title": "Estas listo para jugar",
8080
"tutorial_play_description": "Ahora selecciona tu modo preferido para jugar (en la web solo hay uno) y sigue las instrucciones que aparecen dentro",
81-
"share-the-code-with-your-client": "Comparte el código con tu cliente."
81+
"share-the-code-with-your-client": "Comparte el código con tu cliente.",
82+
"framerate": "FPS",
83+
"go-browser": "Tu navegador por defecto debería abrirse automáticamente (Hay problemas conocidos en Firefox: recomendamos usar navegadores basados en Chromium)",
84+
"ideal-framerate": "FPS ideal",
85+
"max-framerate": "FPS máximo",
86+
"relay-title": "Ir a la pestaña del navegador",
87+
"resolutions": "Resoluciones",
88+
"warning-go-browser": "No cierres la aplicación o vuelvas atrás en el menú"
8289
}

frontend/src/lib/i18n/gl.json

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,5 +78,12 @@
7878
"tutorial_prev_text": "Anterior",
7979
"tutorial_play_title": "Estás listo para xogar",
8080
"tutorial_play_description": "Agora selecciona o teu modo preferido para xogar (na web só hai un) e sigue as instrucións que hai dentro",
81-
"share-the-code-with-your-client": "Comparte o código co teu cliente"
81+
"share-the-code-with-your-client": "Comparte o código co teu cliente",
82+
"framerate": "FPS",
83+
"go-browser": "O teu navegador por defecto tivo que abrirse automáticamente (Hay problemas coñecidos con Firefox: recomendase usar navegadores baseados en Chromium)",
84+
"ideal-framerate": "FPS Ideais",
85+
"max-framerate": "FPS Máximos",
86+
"relay-title": "Vai a xanela do teu navegador",
87+
"resolutions": "Resolucións",
88+
"warning-go-browser": "Non peches a APP ou volvas atrás no menú"
8289
}

frontend/src/lib/i18n/i18n.ts

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { browser } from '$app/environment'
2-
import { init, register, getLocaleFromNavigator } from 'svelte-i18n'
2+
import { init, register, getLocaleFromNavigator, locale} from 'svelte-i18n'
33

44
const defaultLocale = 'en'
55

@@ -11,5 +11,21 @@ register('fr', () => import('./fr.json'))
1111

1212
init({
1313
fallbackLocale: defaultLocale,
14-
initialLocale: browser ? new Intl.Locale(getLocaleFromNavigator() ?? defaultLocale).language : defaultLocale,
15-
})
14+
initialLocale: browser ? new Intl.Locale(getLocaleFromLocalStorage() ?? getLocaleFromNavigator() ?? defaultLocale).language : defaultLocale,
15+
})
16+
17+
export function getLocaleFromLocalStorage() {
18+
const locale_stored = localStorage.getItem('locale')
19+
return locale_stored
20+
}
21+
22+
function saveLocaleToLocalStorage(locale: string) {
23+
browser && localStorage.setItem('locale', locale)
24+
}
25+
26+
locale.subscribe((value) => {
27+
console.log('locale changed to', value)
28+
saveLocaleToLocalStorage(value ?? defaultLocale)
29+
})
30+
31+

frontend/src/lib/layout/icons/DeleteIcon.svelte

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,6 @@
88
stroke-width="2"
99
stroke-linecap="round"
1010
stroke-linejoin="round"
11-
class="hover:stroke-red-500 hover:scale-110 transition-transform"
11+
class="hover:stroke-red-500 hover:scale-110 transition-transform dark:stroke-white stroke-gray-900"
1212
><circle cx="12" cy="12" r="10" /><path d="m15 9-6 6" /><path d="m9 9 6 6" /></svg
1313
>

frontend/src/lib/layout/icons/PencilIcon.svelte

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,6 @@
88
stroke-width="2"
99
stroke-linecap="round"
1010
stroke-linejoin="round"
11-
class="lucide lucide-pencil"
11+
class="lucide lucide-pencil dark:stroke-white stroke-gray-900"
1212
><path d="M17 3a2.85 2.83 0 1 1 4 4L7.5 20.5 2 22l1.5-5.5Z" /><path d="m15 5 4 4" /></svg
1313
>

frontend/src/lib/layout/icons/TrashIcon.svelte

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
stroke-width="2"
99
stroke-linecap="round"
1010
stroke-linejoin="round"
11-
class="hover:stroke-red-500 hover:scale-110 transition-transform"
11+
class="hover:stroke-red-500 hover:scale-110 transition-transform dark:stroke-white stroke-gray-900"
1212
><path d="M3 6h18" /><path d="M19 6v14c0 1-1 2-2 2H7c-1 0-2-1-2-2V6" /><path
1313
d="M8 6V4c0-1 1-2 2-2h4c1 0 2 1 2 2v2"
1414
/><line x1="10" x2="10" y1="11" y2="17" /><line x1="14" x2="14" y1="11" y2="17" /></svg

frontend/src/lib/wailsjs/runtime/runtime.d.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -134,7 +134,7 @@ export function WindowIsFullscreen(): Promise<boolean>;
134134

135135
// [WindowSetSize](https://wails.io/docs/reference/runtime/window#windowsetsize)
136136
// Sets the width and height of the window.
137-
export function WindowSetSize(width: number, height: number): Promise<Size>;
137+
export function WindowSetSize(width: number, height: number): void;
138138

139139
// [WindowGetSize](https://wails.io/docs/reference/runtime/window#windowgetsize)
140140
// Gets the width and height of the window.

frontend/src/lib/webrtc/ICEServerManager.svelte

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -136,9 +136,9 @@
136136
e.preventDefault()
137137
groupToCreate = '';
138138
}}
139-
class="flex flex-col gap-4 items-center justify-center sm:w-[30vw] w-[75vw] p-4 my-4 border rounded-lg shadow sm:p-6 bg-gray-800 border-gray-700"
139+
class="flex flex-col gap-4 items-center justify-center sm:w-[30vw] w-[75vw] p-4 my-4 bg-white border border-gray-200 rounded-lg shadow dark:bg-gray-800 dark:border-gray-700"
140140
>
141-
<label for="group" class="block mb-2 font-medium text-gray-900 dark:text-white"
141+
<label for="group" class="block mb-2 font-medium text-gray-900 dark:text-white"
142142
>{$_('create_group')}</label
143143
>
144144
<input
@@ -163,7 +163,7 @@
163163
</p>
164164
{/if}
165165
{#each Object.keys($servers) as server_group, i}
166-
<li class="w-[75vw] p-4 my-4 border rounded-lg shadow sm:p-6 bg-gray-800 border-gray-700">
166+
<li class="w-[75vw] p-4 my-4 border rounded-lg shadow sm:p-6 bg-white border-gray-200 dark:bg-gray-800 dark:border-gray-700">
167167
<div class="flex justify-end h-0 mb-4 lg:mb-1">
168168
<button
169169
type="button"
@@ -204,7 +204,7 @@
204204
newserverToAdd = '';
205205
}}
206206
>
207-
<label for="domain" class="block mb-2 text-sm font-medium text-gray-900 dark:text-white"
207+
<label for="domain" class="block mb-2 text-sm font-medium text-gray-400 dark:text-white"
208208
>{$_('new_server')}</label
209209
>
210210
<input
@@ -239,7 +239,7 @@
239239
<li class="pb-3 sm:pb-4">
240240
<div class="flex items-center space-x-4 rtl:space-x-reverse">
241241
<div class="flex-1 min-w-0">
242-
<p class="text-lg truncate text-white">
242+
<p class="text-lg truncate text-gray-400 dark:text-white">
243243
{#if type === 'stun'}
244244
{server.split('stun:')[1]}
245245
{:else}
@@ -262,7 +262,7 @@
262262
<form action="">
263263
<label
264264
for="user-{i}"
265-
class="block mb-2 text-sm font-medium text-gray-900 dark:text-white"
265+
class="block mb-2 text-sm font-medium text-gray-400 dark:text-white"
266266
>{$_('username')}</label
267267
>
268268
<input
@@ -277,7 +277,7 @@
277277

278278
<label
279279
for="password"
280-
class="block mb-2 text-sm font-medium text-gray-900 dark:text-white"
280+
class="block mb-2 text-sm font-medium text-gray-400 dark:text-white"
281281
>{$_('password')}</label
282282
>
283283

frontend/src/lib/webrtc/client_webrtc_hook.ts

Lines changed: 2 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { showToast, ToastType } from '$lib/toast/toast_hook';
22
import { goto } from '$app/navigation';
3-
import { cloneGamepad } from '$lib/gamepad/gamepad_hook';
3+
import { cloneGamepad, handleGamepad } from '$lib/gamepad/gamepad_hook';
44
import { handleKeyDown, handleKeyUp, unhandleKeyDown, unhandleKeyUp } from '$lib/keyboard/keyboard_hook';
55
import { toogleLoading } from '$lib/loading/loading_hook';
66
import { CreateClientStream } from '$lib/webrtc/stream/client_stream_hook';
@@ -84,26 +84,7 @@ async function CreateClientWeb() {
8484
}
8585

8686
controllerChannel.onopen = () => {
87-
const sendGamepadData = () => {
88-
const gamepadData = navigator.getGamepads();
89-
90-
gamepadData.forEach((gamepad) => {
91-
if (!gamepad) return;
92-
93-
const serializedData = JSON.stringify(cloneGamepad(gamepad));
94-
controllerChannel.send(serializedData);
95-
});
96-
};
97-
98-
const gamepadLoop = () => {
99-
sendGamepadData();
100-
101-
// Continue the loop
102-
requestAnimationFrame(gamepadLoop);
103-
};
104-
105-
// Start the gamepad loop
106-
gamepadLoop();
87+
handleGamepad(controllerChannel)
10788
};
10889

10990
streamingSignalChannel.onopen = () => {

frontend/src/lib/webrtc/stream/client_stream_hook.ts

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { exportStunServers } from '$lib/webrtc/stun_servers';
22
import { setConsumingStream, type SignalingData } from '$lib/webrtc/stream/stream_signal_hook.svelte';
33
import { exportTurnServers } from '$lib/webrtc/turn_servers';
4+
import { getSortedVideoCodecs } from './stream_config';
45

56
let peerConnection: RTCPeerConnection | undefined;
67
let inboundStream: MediaStream | null = null;
@@ -62,22 +63,29 @@ async function CreateClientStream(
6263
}
6364
};
6465

66+
6567
const offer = await peerConnection.createOffer({
6668
offerToReceiveAudio: true,
6769
offerToReceiveVideo: true
6870
});
6971

72+
try {
73+
const [transceiver] = peerConnection.getTransceivers();
74+
transceiver.setCodecPreferences(getSortedVideoCodecs());
75+
} catch {
76+
77+
}
78+
7079
await peerConnection.setLocalDescription(offer);
7180

7281
// Configuración de parámetros del códec
7382
peerConnection.getSenders().forEach((sender) => {
7483
const params = sender.getParameters();
84+
7585
if (!params.encodings) {
7686
params.encodings = [{}];
7787
}
78-
params.encodings[0].maxBitrate = 5_000_000; // Configura el bitrate máximo (en bits por segundo)
79-
params.encodings[0].maxFramerate = 60; // Configura el frame rate máximo
80-
// params.encodings[i].scaleResolutionDownBy = 1.25
88+
params.encodings[0].maxBitrate = 8_500_000; // Configura el bitrate máximo (en bits por segundo)
8189
params.encodings[0].priority = "high"
8290
sender.setParameters(params);
8391
});

0 commit comments

Comments
 (0)