├── demo.png ├── assets ├── configure.png ├── reload_btn.png ├── user-home-symbolic.png ├── error_window.ui └── main.ui ├── LICENSE ├── README.md ├── README_PT-BR.md ├── install_uninstall.py └── main.py /demo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hayukimori/scrcpy-pyqtgui/HEAD/demo.png -------------------------------------------------------------------------------- /assets/configure.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hayukimori/scrcpy-pyqtgui/HEAD/assets/configure.png -------------------------------------------------------------------------------- /assets/reload_btn.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hayukimori/scrcpy-pyqtgui/HEAD/assets/reload_btn.png -------------------------------------------------------------------------------- /assets/user-home-symbolic.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hayukimori/scrcpy-pyqtgui/HEAD/assets/user-home-symbolic.png -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 hayukimori 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /assets/error_window.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | MainWindow 4 | 5 | 6 | 7 | 0 8 | 0 9 | 372 10 | 259 11 | 12 | 13 | 14 | Error Window 15 | 16 | 17 | QMainWindow{ 18 | background-color:rgb(1, 10, 15); 19 | } 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 16777215 28 | 50 29 | 30 | 31 | 32 | QLabel{ 33 | color: white; 34 | } 35 | 36 | 37 | Erro Desconhecido 38 | 39 | 40 | true 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 16777215 49 | 25 50 | 51 | 52 | 53 | QPushButton{ 54 | background-color:rgb(80,80,80); 55 | border:none; 56 | border-radius:5px; 57 | color:rgb(255,255,255); 58 | } 59 | 60 | 61 | OK 62 | 63 | 64 | Return 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Scrcpy PyQt GUI 2 | > A simple interface to scrcpy made with Qt5 3 | 4 | ![Python Ver](https://img.shields.io/badge/Python-3.10-blue?style=flat-square) 5 | ![PyQt5 Ver](https://img.shields.io/badge/PyQt5-5.15.6-blue?style=flat-square) 6 | ![PPADB Ver](https://img.shields.io/badge/ppadb-0.3.0.dev0-blue?style=flat-square) 7 | 8 | 9 | 10 | Scrcpy PyQtGUI is a Qt5 frontend to ease the use of scrcpy (currently run via command line). 11 | 12 | By not having access to the output of Scrcpy, there is the possibility of errors that do not appear on the screen or total crash in the interface (in case of running via Windows cmd) 13 | 14 | **Versão PT-BR: [README_PT-BR.md](README_PT-BR.md)** 15 | ![Demo](demo.png) 16 | 17 | ## Preparation and installation 18 | Some packages are necessary for the program to work, and they can be installed with the following commands: 19 | 20 | 21 | #### Ubuntu/Debian 22 | 23 | ```sh 24 | $ sudo apt-get install snapd python3-pip adb 25 | $ sudo snap install scrcpy 26 | $ pip3 install PyQt5 pure-python-adb 27 | ``` 28 | 29 | 30 | #### Arch/Manjaro 31 | (NOTE: Both PARU and YAY can be used in this process, if you have either installed. In this case, I will be using YAY as an example) 32 | 33 | ```sh 34 | $ yay -S python3 python3-pip scrcpy 35 | $ sudo pacman -S android-tools 36 | $ pip3 install PyQt5 pure-python-adb 37 | ``` 38 | 39 | 40 | ### Installation 41 | To install on linux distros, just run the `install_uninstall.py` script. 42 | I warn you that the installation of this version will take place in a different directory. It will be in `/home/{your_username}/.local/share/HayukiApps/` 43 | 44 | Also notice here that the commands _must_ be executed inside the folder; 45 | 46 | ```sh 47 | $ python install_uninstall.py 48 | ``` 49 | 50 | #### Windows 51 | Unfortunately the installer is not ready for Windows yet, I will be developing it soon. But I think the program works fine if it has all dependencies and if `adb.exe` and `scrcpy.exe` are in the Windows PATH 52 | 53 | ## Common problems 54 | 55 | If `scrcpy_gui` doesn't start from terminal, check if `/home/user/.local/bin` is in $PATH, you can check with `$ echo $PATH` 56 | 57 | #### Default Bash 58 | If the path is not there, you can add to "~/.bashrc" the following line at the end of the file 59 | 60 | ```sh 61 | export PATH=$PATH:/home/{your username}/.local/bin 62 | ``` 63 | 64 | #### Fish 65 | If you are using `fish`, it's a different case. 66 | You can add the path as follows: 67 | 68 | In your favorite text editor, add the following line to the `~/.config/fish/config.fish` file 69 | 70 | ```sh 71 | set -U fish_user_paths /home/{your user}/.local/bin $fish_user_paths 72 | ``` 73 | 74 | ##### Other problems 75 | 76 | If the problem is not the one above, you can [open an issue](https://github.com/hayukimori/scrcpy-pyqtgui/issues/new). (PT BR or English) 77 | 78 | ## About 79 | 80 | Code and layout by _Ana Beatriz_ ([@hayukimori](https://twitter.com/hayukimori/)) 81 | -------------------------------------------------------------------------------- /README_PT-BR.md: -------------------------------------------------------------------------------- 1 | # Scrcpy GUI 2 | > Interface simples em Qt5 para o scrcpy 3 | 4 | ![Python Ver](https://img.shields.io/badge/Python-3.10-blue?style=flat-square) 5 | ![PyQt5 Ver](https://img.shields.io/badge/PyQt5-5.15.6-blue?style=flat-square) 6 | ![PPADB Ver](https://img.shields.io/badge/ppadb-0.3.0.dev0-blue?style=flat-square) 7 | 8 | Scrcpy PyQtGUI é uma interface em Qt5 para facilitar o uso do Scrcpy (atualmente executado via linha de comando). 9 | 10 | Por não ter acesso ao output do Scrcpy, há a possibilidade de ocorrer erros que não apareçam na tela ou travamento total da interface (no caso de rodar via cmd do Windows) 11 | 12 | ![Demo](demo.png) 13 | 14 | ## Preparação e Instalação 15 | Alguns pacotes são necessários para o funcionamento de programa, e podem ser instalados com os seguintes comandos: 16 | 17 | 18 | #### Ubuntu/Debian 19 | 20 | ```sh 21 | $ sudo apt-get install snapd python3-pip adb 22 | $ sudo snap install scrcpy 23 | $ pip3 install PyQt5 pure-python-adb 24 | ``` 25 | 26 | 27 | #### Arch/Manjaro 28 | (NOTA: Tanto PARU quanto YAY pode ser utilizado neste processo, caso tenha algum dos dois instalado. Neste caso, estarei utilizando YAY como exemplo) 29 | 30 | ```sh 31 | $ yay -S python3 python3-pip scrcpy 32 | $ sudo pacman -S android-tools 33 | $ pip3 install PyQt5 pure-python-adb 34 | ``` 35 | 36 | 37 | ### Instalação 38 | 39 | #### Linux 40 | Para fazer a instalação em distros linux, basta rodar o script `install_uninstall.py` e seguir os passos. 41 | Deixo avisado que a instalação desta versão ocorrerá num diretório diferente. Ficará no `/home/{seu_usuário}/.local/share/HayukiApps/` 42 | 43 | Aviso aqui também que os comandos _devem_ ser executados dentro da pasta; 44 | ```sh 45 | $ python install_uninstall.py 46 | ``` 47 | 48 | #### Windows 49 | Infelizmente o instalador ainda não está pronto para o Windows, estarei desenvolvendo em breve. Mas creio que o programa funcione bem se estiver com todas as dependências e se `adb.exe` e `scrcpy.exe` estiverem no PATH do Windows 50 | 51 | 52 | ## Uso 53 | Para lançar o programa, pode utilizar o ícone que é criado após a instalação (linux), ou iniciar através do terminal pelo seguinte comando; 54 | 55 | ```sh 56 | $ scrcpy_gui 57 | ``` 58 | 59 | 60 | 61 | ## Solução de problemas 62 | 63 | Caso `scrcpy_gui` não inicie pelo terminal, verifique se `/home/usuario/.local/bin` está em $PATH, você pode verificar com `$ echo $PATH` 64 | 65 | #### Bash padrão 66 | Caso o path não esteja, você pode adicionar ao "~/.bashrc" a seguinte linha no final do arquivo 67 | ```sh 68 | export PATH=$PATH:/home/{seu usuario}/.local/bin 69 | ``` 70 | 71 | #### Fish 72 | Se você estiver utilizando o `fish`, o caso é outro 73 | Você pode adicionar o path da seguinte forma: 74 | 75 | 76 | No seu editor de texto preferido, adicione a seguinte linha no arquivo `~/.config/fish/config.fish` 77 | ```sh 78 | set -U fish_user_paths /home/{seu usuário}/.local/bin $fish_user_paths 79 | ``` 80 | 81 | ##### Outros problemas 82 | Caso seu problema não seja o de cima, você pode [abrir uma issue](https://github.com/hayukimori/scrcpy-pyqtgui/issues/new). 83 | 84 | 85 | 86 | 87 | ## Sobre 88 | 89 | Código e layout por _Ana Beatriz_ ([@hayukimori](https://twitter.com/hayukimori/)) 90 | -------------------------------------------------------------------------------- /install_uninstall.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | import os, sys, platform 3 | 4 | USER_SYSTEM = platform.system() 5 | VAR_HOME = os.getenv('HOME') 6 | 7 | ################## NEW -- LINUX BASED ######################## 8 | linux_default_appbase_instalation_path = VAR_HOME + '/.local/share/HayukiApps/scrcpy_pyqtgui/' 9 | linux_default_assets_folder = linux_default_appbase_instalation_path + '/assets/' 10 | linux_default_shell_script = VAR_HOME + '/.local/bin/scrcpy_pyqtgui' 11 | linux_default_desktop_path = VAR_HOME + '/.local/share/applications/' 12 | linux_default_desktop_filename = 'scrcpy_pyqtgui' 13 | ################################################################ 14 | 15 | 16 | # GLB => GLOBAL --- abbreviated global variables 17 | glb_ldai = linux_default_appbase_instalation_path 18 | glb_laf = linux_default_assets_folder 19 | glb_ldsc = linux_default_shell_script 20 | glb_ddp = linux_default_desktop_path 21 | a_files = ['error_window.ui', 'main.ui', 'reload_btn.png', 'configure.png', 'user-home-symbolic.png'] 22 | 23 | 24 | 25 | def infoAlert(info: str, error=False): 26 | if error == False: 27 | print('[INFO] ' + info) 28 | 29 | elif error == True: 30 | print('[ERROR] ' + info) 31 | 32 | try: 33 | if type(error) != bool: 34 | if error.lower() == "alert": 35 | print(f"< {error.lower()} > " + info) 36 | 37 | except Exception as e: 38 | infoAlert(str(e), error=True) 39 | 40 | class ManageInstaller(): 41 | def __init__(self, operational_system_base='linux'): 42 | self.osb = operational_system_base; 43 | 44 | 45 | if self.osb.lower() == 'linux': 46 | self.installerMain = LinuxInstaller() 47 | 48 | else: 49 | infoAlert(info="Non Linux-based system detected; Unfortunately this program don't have a installer for this system (not yet).\n\n Try to contact me on social networks:\n\n-Twitter: https://twitter.com/hayukimori\n-Discord: hayukimori#0599\nGitHub: https://github.com/hayukimori", error="alert") 50 | 51 | class LinuxInstaller(): 52 | def __init__(self): 53 | if self.verifyExistingInstallation() != True: 54 | self.startInstaller() 55 | 56 | else: 57 | self.uninstall(quest=True) 58 | 59 | 60 | def startInstaller(self): 61 | 62 | if self.verifyLocalFiles() == False: 63 | infoAlert(f"Some files couldn't be found, please verify files and try again;\nRequired files: {a_files}", error=True) 64 | 65 | else: 66 | try: 67 | 68 | # => Informing about package 69 | package_info = f"\n=============================================\nApp: Scrcpy PtQtGui\nApp: scrcpy_pyqtgui,\nFont: github\nCreator: hayukimori\n\nInstallation Path: {linux_default_appbase_instalation_path}\nStatus: installing\n=============================================\n" 70 | infoAlert(package_info, error=False) 71 | 72 | 73 | 74 | # => Creating Directories (HayukiApps, assets) 75 | infoAlert(f"Creating directiories:\n {linux_default_appbase_instalation_path}\n{linux_default_assets_folder}", error=False) 76 | os.system('mkdir -p ' + linux_default_appbase_instalation_path) 77 | os.system('mkdir -p ' + linux_default_assets_folder) 78 | 79 | 80 | # => Moving files to paths 81 | infoAlert("Moving files (assets)", error=False) 82 | for file in a_files: 83 | print(file) 84 | os.system(f"cp assets/{file} " + linux_default_assets_folder) 85 | 86 | 87 | infoAlert("Moving main files", error=False) 88 | for file in ['main.py', 'install_uninstall.py']: 89 | os.system(f'cp {file} ' + linux_default_appbase_instalation_path) 90 | 91 | 92 | 93 | # => Making Shell Script 94 | 95 | # Checks if ".local/bin/" is in $PATH 96 | if self.localbin_in_SystemPath() == False: 97 | infoAlert(f"'{VAR_HOME}/.local/bin' isn't in PATH. To start this application using terminal, you'll need to add in $PATH. See README.md to see how to make it", error=False) 98 | infoAlert("Creating shell script", error=False) 99 | 100 | 101 | self.makeShellScript() 102 | 103 | 104 | # => Creating desktop file 105 | infoAlert("Creating desktop file", error=False) 106 | dfileText = f'''[Desktop Entry]\nVersion=1.0\nType=Application\nName=Scrcpy Gui\nComment=Scrcpy PyQt5 gui\nIcon=smartphone\nExec=python main.py\nPath={linux_default_appbase_instalation_path}\nTerminal=false\nStartupNotify=true\nCategories=AudioVideo;nUtility;''' 107 | 108 | 109 | with open(linux_default_desktop_path + linux_default_desktop_filename + '.desktop', 'w') as df: 110 | df.write(dfileText) 111 | df.close() 112 | 113 | 114 | 115 | 116 | 117 | except Exception as e: 118 | infoAlert(str(e) + '\n', error=True) 119 | 120 | def verifyLocalFiles(self): 121 | 122 | results = [] 123 | 124 | for a in a_files: 125 | if os.path.exists("./assets/" + a) == True: 126 | results.append(True) 127 | 128 | 129 | if all_true(results): 130 | return True 131 | else: 132 | return False 133 | 134 | 135 | def verifyExistingInstallation(self): 136 | # for newer version Only 137 | if os.path.exists(linux_default_appbase_instalation_path) == True: 138 | return True 139 | 140 | else: 141 | return False 142 | 143 | def uninstall(self, quest=True): 144 | print("=====================SCRCPY PYQT GUI FOUND IN SYSTEM ==========================") 145 | print(f"Installation found in {VAR_HOME}/.local/share/HayukiApps/") 146 | uinput = input("Uninstall current version or Update (UPdate / UNinstall)\n((default: Update)): ") 147 | print("===============================================================================") 148 | 149 | uinput_no_spaces = uinput.replace(" ", '') 150 | 151 | if uinput_no_spaces.lower().startswith('un'): 152 | os.system(f'rm -rf ' + linux_default_appbase_instalation_path) 153 | os.system(f'rm -rf ' + linux_default_desktop_path + linux_default_desktop_filename) 154 | 155 | 156 | else: 157 | os.system(f'rm -rf ' + linux_default_appbase_instalation_path) 158 | self.startInstaller() 159 | 160 | 161 | def makeShellScript(self): 162 | script_text = f'''#!/bin/bash\ncd {linux_default_appbase_instalation_path}/\npython main.py''' 163 | 164 | 165 | with open(linux_default_shell_script, 'w') as ss: 166 | ss.write(script_text) 167 | ss.close() 168 | os.system(f"chmod +x {linux_default_shell_script}") 169 | 170 | 171 | def localbin_in_SystemPath(self): 172 | path_linux_var = os.getenv('PATH') 173 | 174 | if '/.local/bin' in path_linux_var: 175 | return True 176 | else: 177 | return False 178 | 179 | 180 | def all_true(items): 181 | return all(x == True for x in items) 182 | 183 | 184 | if __name__ == "__main__": 185 | Installer = ManageInstaller(operational_system_base=USER_SYSTEM) 186 | -------------------------------------------------------------------------------- /main.py: -------------------------------------------------------------------------------- 1 | import os, sys, re, subprocess; 2 | from PyQt5 import uic, QtWidgets 3 | from PyQt5.QtCore import * 4 | from PyQt5.QtGui import * 5 | from PyQt5.QtWidgets import * 6 | 7 | from ppadb.client import Client as AdbClient 8 | 9 | linux_nobrake = "&" # This works for PowerShell too 10 | nobrake = linux_nobrake 11 | 12 | adb = AdbClient(host="127.0.0.1", port=5037) 13 | app = QtWidgets.QApplication([]) 14 | 15 | 16 | class MainProgram: 17 | 18 | def get_devices(win_devices): 19 | try: 20 | devices = adb.devices() 21 | 22 | if len(devices) == 0: 23 | ErrorShower("No devices connected") 24 | 25 | for device in devices: 26 | win_devices.addItem(device.serial) 27 | 28 | except Exception as e: 29 | ErrorShower(error=str(e)) 30 | 31 | 32 | def normalStart(self): 33 | 34 | try: 35 | 36 | space = " " 37 | 38 | device = window.normal_devices.currentText() 39 | bitrate = window.normal_bitrate.text() 40 | fullscreen = window.normal_fullscreen.isChecked() 41 | view_only = window.normal_view_only.isChecked() 42 | borderless = window.normal_borderless.isChecked() 43 | render = window.normal_render.currentText() 44 | 45 | code = 'scrcpy' + space 46 | 47 | if fullscreen == True: 48 | code = code + '--fullscreen' + space 49 | 50 | if view_only == True: 51 | code = code + '--no-control' + space 52 | 53 | if borderless == True: 54 | code = code + '--window borderless' + space 55 | 56 | 57 | final_code = f'''{code} --serial {device} -b {bitrate} --render-driver="{render}"''' + nobrake 58 | os.system(final_code) 59 | 60 | except Exception as e: 61 | ErrorShower(str(e)) 62 | 63 | 64 | def otgStart(self): 65 | try: 66 | 67 | space = " " 68 | 69 | device = window.otg_devices.currentText() 70 | bitrate = window.otg_bitrate.text() 71 | fullscreen = window.otg_fullscreen.isChecked() 72 | borderless = window.otg_borderless.isChecked() 73 | render = window.otg_render.currentText() 74 | 75 | code = 'scrcpy' + space 76 | 77 | if fullscreen == True: 78 | code = code + '--fullscreen' + space 79 | 80 | if borderless == True: 81 | code = code + '--window borderless' + space 82 | 83 | 84 | final_code = f'''{code} -K -M --serial {device} -b {bitrate} --render-driver="{render} "''' + nobrake 85 | os.system(final_code) 86 | 87 | except Exception as e: 88 | ErrorShower(str(e)) 89 | 90 | 91 | def gameStart(self): 92 | try: 93 | 94 | space = " " 95 | 96 | device = window.game_devices.currentText() 97 | bitrate = window.game_bitrate.text() 98 | fullscreen = window.game_fullscreen.isChecked() 99 | borderless = window.game_borderless.isChecked() 100 | no_otg = window.game_no_otg.isChecked() 101 | render = window.game_render.currentText() 102 | 103 | 104 | code = 'scrcpy' + space 105 | 106 | if fullscreen == True: 107 | code = code + '--fullscreen' + space 108 | 109 | 110 | if borderless == True: 111 | code = code + '--window borderless' + space 112 | 113 | 114 | if no_otg != True: 115 | code = code + '-K -M' 116 | 117 | 118 | final_code = f'''{code} --serial {device} -b {bitrate} --render-driver="{render}"''' + nobrake 119 | os.system(final_code) 120 | 121 | except Exception as e: 122 | ErrorShower(str(e)) 123 | 124 | 125 | def manualStart(self): 126 | try: 127 | 128 | space = " " 129 | 130 | device = window.manual_devices.currentText() 131 | bitrate = window.manual_bitrate.text() 132 | fullscreen = window.manual_fullscreen.isChecked() 133 | view_only = window.manual_view_only.isChecked() 134 | borderless = window.manual_borderless.isChecked() 135 | render = window.manual_render.currentText() 136 | add_args = window.manual_args.toPlainText() 137 | 138 | code = 'scrcpy' + space 139 | 140 | if fullscreen == True: 141 | code = code + '--fullscreen' + space 142 | 143 | if view_only == True: 144 | code = code + '--no-control' + space 145 | 146 | if borderless == True: 147 | code = code + '--window borderless' + space 148 | 149 | if len(add_args) >= 1: 150 | code = code + add_args + space 151 | 152 | 153 | final_code = f'''{code} --serial {device} -b {bitrate} --render-driver="{render}"''' + nobrake 154 | os.system(final_code) 155 | 156 | except Exception as e: 157 | ErrorShower(str(e)) 158 | 159 | 160 | 161 | 162 | class WindowManager(): 163 | 164 | def defineFlags(): 165 | window.setWindowFlags(Qt.FramelessWindowHint) 166 | window.setAttribute(Qt.WA_TranslucentBackground) 167 | 168 | def showMain(): 169 | window.show() 170 | 171 | 172 | def _home_page(): 173 | window.stackedWidget.setCurrentIndex(0) 174 | 175 | def _normal_page(): 176 | window.stackedWidget.setCurrentIndex(1) 177 | 178 | WindowManager.reZero(window.normal_devices) 179 | MainProgram.get_devices(window.normal_devices) 180 | 181 | def _otg_page(): 182 | window.stackedWidget.setCurrentIndex(2) 183 | 184 | WindowManager.reZero(window.otg_devices) 185 | MainProgram.get_devices(window.otg_devices) 186 | 187 | def _game_page(): 188 | window.stackedWidget.setCurrentIndex(3) 189 | 190 | WindowManager.reZero(window.game_devices) 191 | MainProgram.get_devices(window.game_devices) 192 | 193 | def _manual_page(): 194 | window.stackedWidget.setCurrentIndex(4) 195 | 196 | WindowManager.reZero(window.manual_devices) 197 | MainProgram.get_devices(window.manual_devices) 198 | 199 | 200 | def _confs_page(): 201 | window.stackedWidget.setCurrentIndex(5) 202 | 203 | 204 | 205 | 206 | def _reload_normal_d(): 207 | WindowManager.reZero(window.normal_devices) 208 | MainProgram.get_devices(window.normal_devices) 209 | 210 | 211 | def _reload_otg_d(): 212 | WindowManager.reZero(window.otg_devices) 213 | MainProgram.get_devices(window.otg_devices) 214 | 215 | def _reload_game_d(): 216 | WindowManager.reZero(window.game_devices) 217 | MainProgram.get_devices(window.game_devices) 218 | 219 | 220 | def _reload_manual_d(): 221 | WindowManager.reZero(window.manual_devices) 222 | MainProgram.get_devices(window.manual_devices) 223 | 224 | 225 | 226 | 227 | def reZero(win_devices): 228 | while len(win_devices) > 0: 229 | win_devices.removeItem(0) 230 | 231 | 232 | 233 | 234 | class ErrorShower(): 235 | def __init__(self, error, windowed=True): 236 | self.error = error 237 | self.windowed = windowed 238 | 239 | if windowed == True: 240 | errorWindow.text.setText(str(error)) 241 | errorWindow.show() 242 | else: 243 | print(f" {str(error)}") 244 | 245 | 246 | 247 | window = uic.loadUi("assets/main.ui") 248 | errorWindow = uic.loadUi("assets/error_window.ui") 249 | window.exit_button.clicked.connect(sys.exit) 250 | 251 | 252 | # Button Functions 253 | window.home_btn.clicked.connect(WindowManager._home_page) 254 | window.normal_btn.clicked.connect(WindowManager._normal_page) 255 | window.otg_btn.clicked.connect(WindowManager._otg_page) 256 | window.game_btn.clicked.connect(WindowManager._game_page) 257 | window.manual_btn.clicked.connect(WindowManager._manual_page) 258 | window.configure_btn.clicked.connect(WindowManager._confs_page) 259 | 260 | window.minimize_btn.clicked.connect(window.showMinimized) 261 | errorWindow.ok_btn.clicked.connect(errorWindow.close) 262 | 263 | # Reload Buttons 264 | window.normal_reload_btn.clicked.connect(WindowManager._reload_normal_d) 265 | window.otg_reload_btn.clicked.connect(WindowManager._reload_otg_d) 266 | window.game_reload_btn.clicked.connect(WindowManager._reload_game_d) 267 | window.manual_reload_btn.clicked.connect(WindowManager._reload_manual_d) 268 | 269 | 270 | # Start Buttons 271 | window.normal_start.clicked.connect(MainProgram.normalStart) 272 | window.otg_start.clicked.connect(MainProgram.otgStart) 273 | window.game_start.clicked.connect(MainProgram.gameStart) 274 | window.manual_start.clicked.connect(MainProgram.manualStart) 275 | 276 | 277 | 278 | 279 | if __name__ == "__main__": 280 | WindowManager.defineFlags() 281 | WindowManager.showMain() 282 | app.exec() 283 | -------------------------------------------------------------------------------- /assets/main.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | MainWindow 4 | 5 | 6 | 7 | 0 8 | 0 9 | 962 10 | 499 11 | 12 | 13 | 14 | Scrcpy PyQt5 GUI 15 | 16 | 17 | 18 | 19 | 0 20 | 21 | 22 | 4 23 | 24 | 25 | 0 26 | 27 | 28 | 4 29 | 30 | 31 | 0 32 | 33 | 34 | 35 | 36 | QFrame{ 37 | background-color: rgb(0,0,0); 38 | border-radius:10%; 39 | } 40 | 41 | 42 | QFrame::StyledPanel 43 | 44 | 45 | QFrame::Raised 46 | 47 | 48 | 49 | 50 | 850 51 | 30 52 | 51 53 | 41 54 | 55 | 56 | 57 | 58 | 12 59 | 60 | 61 | 62 | QPushButton{ 63 | color: rgb(119, 118, 123); 64 | background: none; 65 | border: none; 66 | border-radius: 5%; 67 | } 68 | 69 | QPushButton:hover{ 70 | background-color: rgb(22,22,22); 71 | color: rgb(255,255,255); 72 | } 73 | 74 | 75 | - 76 | 77 | 78 | 79 | 80 | 81 | 900 82 | 30 83 | 51 84 | 41 85 | 86 | 87 | 88 | QPushButton{ 89 | color: rgb(119, 118, 123); 90 | background: none; 91 | border: none; 92 | border-radius: 5%; 93 | } 94 | 95 | QPushButton:hover{ 96 | background-color: rgb(237, 51, 59); 97 | color: rgb(255,255,255); 98 | } 99 | 100 | 101 | X 102 | 103 | 104 | 105 | 106 | 107 | 20 108 | 120 109 | 51 110 | 331 111 | 112 | 113 | 114 | QGroupBox{ 115 | background-color: rgba(53, 132, 228,190); 116 | border-radius: 10%; 117 | } 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 0 126 | 20 127 | 51 128 | 51 129 | 130 | 131 | 132 | QPushButton{ 133 | background-color: none; 134 | border: none; 135 | } 136 | 137 | QPushButton:hover{ 138 | background-color: rgb(0,0,0); 139 | border-radius: 10px; 140 | } 141 | 142 | 143 | 144 | 145 | 146 | 147 | configure.pngconfigure.png 148 | 149 | 150 | 151 | 152 | 153 | 0 154 | 70 155 | 51 156 | 51 157 | 158 | 159 | 160 | QPushButton{ 161 | background-color: none; 162 | border: none; 163 | } 164 | 165 | QPushButton:hover{ 166 | background-color: rgb(0,0,0); 167 | border-radius: 10px; 168 | } 169 | 170 | 171 | 172 | 173 | 174 | 175 | user-home-symbolic.pnguser-home-symbolic.png 176 | 177 | 178 | 179 | 180 | 181 | 182 | 90 183 | 120 184 | 851 185 | 331 186 | 187 | 188 | 189 | QStackedWidget{ 190 | background:rgba(53, 132, 228,190); 191 | } 192 | 193 | 194 | 0 195 | 196 | 197 | 198 | 199 | 200 | 40 201 | 10 202 | 151 203 | 311 204 | 205 | 206 | 207 | QFrame{ 208 | background-color: rgb(22,22,22); 209 | } 210 | 211 | 212 | QFrame::StyledPanel 213 | 214 | 215 | QFrame::Raised 216 | 217 | 218 | 219 | 220 | 10 221 | 10 222 | 131 223 | 291 224 | 225 | 226 | 227 | QPushButton{ 228 | background-color: white; 229 | } 230 | 231 | QPushButton:hover{ 232 | background-color: rgb(192, 191, 188); 233 | } 234 | 235 | 236 | Normal 237 | 238 | 239 | 240 | 241 | 242 | 243 | 240 244 | 10 245 | 151 246 | 311 247 | 248 | 249 | 250 | QFrame{ 251 | background-color: rgb(22,22,22); 252 | } 253 | 254 | 255 | QFrame::StyledPanel 256 | 257 | 258 | QFrame::Raised 259 | 260 | 261 | 262 | 263 | 10 264 | 10 265 | 131 266 | 291 267 | 268 | 269 | 270 | QPushButton{ 271 | background-color: white; 272 | } 273 | 274 | QPushButton:hover{ 275 | background-color: rgb(192, 191, 188); 276 | } 277 | 278 | 279 | OTG Mode 280 | 281 | 282 | 283 | 284 | 285 | 286 | 450 287 | 10 288 | 151 289 | 311 290 | 291 | 292 | 293 | QFrame{ 294 | background-color: rgb(22,22,22); 295 | } 296 | 297 | 298 | QFrame::StyledPanel 299 | 300 | 301 | QFrame::Raised 302 | 303 | 304 | 305 | 306 | 10 307 | 10 308 | 131 309 | 291 310 | 311 | 312 | 313 | QPushButton{ 314 | background-color: white; 315 | } 316 | 317 | QPushButton:hover{ 318 | background-color: rgb(192, 191, 188); 319 | } 320 | 321 | 322 | Game Mode 323 | 324 | 325 | false 326 | 327 | 328 | false 329 | 330 | 331 | false 332 | 333 | 334 | 335 | 336 | 337 | 338 | 660 339 | 10 340 | 151 341 | 311 342 | 343 | 344 | 345 | QFrame{ 346 | background-color: rgb(22,22,22); 347 | } 348 | 349 | 350 | QFrame::StyledPanel 351 | 352 | 353 | QFrame::Raised 354 | 355 | 356 | 357 | 358 | 10 359 | 10 360 | 131 361 | 291 362 | 363 | 364 | 365 | QPushButton{ 366 | background-color: white; 367 | } 368 | 369 | QPushButton:hover{ 370 | background-color: rgb(192, 191, 188); 371 | } 372 | 373 | 374 | Manual 375 | 376 | 377 | 378 | 379 | 380 | 381 | 382 | 383 | 10 384 | 10 385 | 151 386 | 311 387 | 388 | 389 | 390 | QFrame{ 391 | background-color: rgb(22,22,22); 392 | } 393 | 394 | 395 | QFrame::StyledPanel 396 | 397 | 398 | QFrame::Raised 399 | 400 | 401 | 402 | 403 | 10 404 | 10 405 | 131 406 | 291 407 | 408 | 409 | 410 | QLabel{ 411 | background-color: white; 412 | } 413 | 414 | 415 | Normal 416 | 417 | 418 | Qt::AlignCenter 419 | 420 | 421 | 422 | 423 | 424 | 425 | 180 426 | 10 427 | 661 428 | 311 429 | 430 | 431 | 432 | QFrame{ 433 | color: rgb(255,255,255); 434 | } 435 | 436 | 437 | QFrame::StyledPanel 438 | 439 | 440 | QFrame::Raised 441 | 442 | 443 | 444 | 445 | 20 446 | 20 447 | 61 448 | 41 449 | 450 | 451 | 452 | Device 453 | 454 | 455 | 456 | 457 | 458 | 80 459 | 30 460 | 571 461 | 21 462 | 463 | 464 | 465 | QComboBox{ 466 | color:white; 467 | border: none; 468 | padding-top: 2px; 469 | padding-bottom: 5px; 470 | background-color:rgb(22, 22, 22); 471 | border-radius:3px; 472 | } 473 | 474 | 475 | 476 | 477 | 478 | 20 479 | 70 480 | 61 481 | 51 482 | 483 | 484 | 485 | Bitrate 486 | 487 | 488 | 489 | 490 | 491 | 80 492 | 80 493 | 91 494 | 26 495 | 496 | 497 | 498 | QLineEdit{ 499 | color:white; 500 | border: none; 501 | padding-top: 2px; 502 | padding-bottom: 5px; 503 | background-color:rgb(22, 22, 22); 504 | border-radius:3px; 505 | } 506 | 507 | 508 | 8000000 509 | 510 | 511 | 512 | 513 | 514 | 180 515 | 90 516 | 41 517 | 18 518 | 519 | 520 | 521 | Hz 522 | 523 | 524 | 525 | 526 | 527 | 380 528 | 80 529 | 141 530 | 31 531 | 532 | 533 | 534 | 535 | 8 536 | 537 | 538 | 539 | PointingHandCursor 540 | 541 | 542 | QCheckBox{ 543 | color:white; 544 | border: none; 545 | padding-left:4px; 546 | background-color:rgb(22, 22, 22); 547 | border-radius:3px; 548 | } 549 | QCheckBox::indicator 550 | { 551 | border-radius: 0.25em; 552 | border: 0.1em solid rgb(114, 159, 207); 553 | } 554 | 555 | QCheckBox::indicator::checked 556 | { 557 | background-color:rgb(114, 159, 207); 558 | } 559 | 560 | 561 | Fullscreen 562 | 563 | 564 | Ctrl+F 565 | 566 | 567 | 568 | 569 | 570 | 220 571 | 80 572 | 151 573 | 31 574 | 575 | 576 | 577 | 578 | 8 579 | 580 | 581 | 582 | PointingHandCursor 583 | 584 | 585 | true 586 | 587 | 588 | QCheckBox{ 589 | color:white; 590 | border: none; 591 | padding-left:4px; 592 | background-color:rgb(22, 22, 22); 593 | border-radius:3px; 594 | } 595 | QCheckBox::indicator 596 | { 597 | border-radius: 0.25em; 598 | border: 0.1em solid rgb(114, 159, 207); 599 | } 600 | 601 | QCheckBox::indicator::checked 602 | { 603 | background-color:rgb(114, 159, 207); 604 | } 605 | 606 | 607 | View Only 608 | 609 | 610 | Ctrl+X 611 | 612 | 613 | 614 | 615 | 616 | 530 617 | 80 618 | 121 619 | 31 620 | 621 | 622 | 623 | 624 | 8 625 | 626 | 627 | 628 | PointingHandCursor 629 | 630 | 631 | true 632 | 633 | 634 | QCheckBox{ 635 | color:white; 636 | border: none; 637 | padding-left:4px; 638 | background-color:rgb(22, 22, 22); 639 | border-radius:3px; 640 | } 641 | QCheckBox::indicator 642 | { 643 | border-radius: 0.25em; 644 | border: 0.1em solid rgb(114, 159, 207); 645 | } 646 | 647 | QCheckBox::indicator::checked 648 | { 649 | background-color:rgb(114, 159, 207); 650 | } 651 | 652 | 653 | Borderless 654 | 655 | 656 | Ctrl+B 657 | 658 | 659 | 660 | 661 | 662 | 20 663 | 140 664 | 121 665 | 18 666 | 667 | 668 | 669 | Render Driver 670 | 671 | 672 | 673 | 674 | 675 | 120 676 | 140 677 | 531 678 | 21 679 | 680 | 681 | 682 | 683 | 0 684 | 0 685 | 686 | 687 | 688 | 689 | 16777215 690 | 16777215 691 | 692 | 693 | 694 | 695 | 8 696 | 697 | 698 | 699 | PointingHandCursor 700 | 701 | 702 | QComboBox 703 | { 704 | color:white; 705 | border: none; 706 | padding-top: 2px; 707 | padding-bottom: 5px; 708 | background-color:rgb(22, 22, 22); 709 | border-radius:3px; 710 | } 711 | 712 | 713 | 714 | opengles2 715 | 716 | 717 | 718 | 719 | opengles 720 | 721 | 722 | 723 | 724 | opengl 725 | 726 | 727 | 728 | 729 | direct3d 730 | 731 | 732 | 733 | 734 | metal 735 | 736 | 737 | 738 | 739 | software 740 | 741 | 742 | 743 | 744 | 745 | 746 | 20 747 | 190 748 | 631 749 | 31 750 | 751 | 752 | 753 | QLabel{ 754 | opacity: .5; 755 | } 756 | 757 | 758 | <html><head/><body><p><span style=" color:#ffff00;">* If you're using Windows, is recommended to use 'direct3d' render driver</span></p></body></html> 759 | 760 | 761 | 762 | 763 | 764 | 20 765 | 250 766 | 141 767 | 31 768 | 769 | 770 | 771 | 772 | 16777215 773 | 16777215 774 | 775 | 776 | 777 | QPushButton{ 778 | background-color:rgba(53, 132, 228,190); 779 | border: none; 780 | border-radius:10px; 781 | color:white; 782 | } 783 | 784 | QPushButton:hover{ 785 | background-color:rgb(32, 74, 135); 786 | } 787 | 788 | 789 | Reload Devices 790 | 791 | 792 | 793 | reload_btn.pngreload_btn.png 794 | 795 | 796 | Ctrl+R 797 | 798 | 799 | 800 | 801 | 802 | 520 803 | 250 804 | 121 805 | 31 806 | 807 | 808 | 809 | 810 | 16777215 811 | 16777215 812 | 813 | 814 | 815 | PointingHandCursor 816 | 817 | 818 | QPushButton{ 819 | color:rgb(255,255,255); 820 | background-color:rgba(53, 132, 228,190); 821 | border: none; 822 | border-radius:10px; 823 | } 824 | 825 | QPushButton:hover{ 826 | background:rgb(32, 74, 135); 827 | } 828 | 829 | 830 | Start 831 | 832 | 833 | 834 | 60 835 | 60 836 | 837 | 838 | 839 | Ctrl+Return 840 | 841 | 842 | 843 | 844 | 845 | 846 | 847 | 848 | 10 849 | 10 850 | 151 851 | 311 852 | 853 | 854 | 855 | QFrame{ 856 | background-color: rgb(22,22,22); 857 | } 858 | 859 | 860 | QFrame::StyledPanel 861 | 862 | 863 | QFrame::Raised 864 | 865 | 866 | 867 | 868 | 10 869 | 10 870 | 131 871 | 291 872 | 873 | 874 | 875 | QLabel{ 876 | background-color: white; 877 | } 878 | 879 | 880 | OTG Mode 881 | 882 | 883 | Qt::AlignCenter 884 | 885 | 886 | 887 | 888 | 889 | 890 | 180 891 | 10 892 | 661 893 | 311 894 | 895 | 896 | 897 | QFrame{ 898 | color: rgb(255,255,255); 899 | } 900 | 901 | 902 | QFrame::StyledPanel 903 | 904 | 905 | QFrame::Raised 906 | 907 | 908 | 909 | 910 | 20 911 | 20 912 | 61 913 | 41 914 | 915 | 916 | 917 | Device 918 | 919 | 920 | 921 | 922 | 923 | 80 924 | 30 925 | 581 926 | 21 927 | 928 | 929 | 930 | QComboBox{ 931 | color:white; 932 | border: none; 933 | padding-top: 2px; 934 | padding-bottom: 5px; 935 | background-color:rgb(22, 22, 22); 936 | border-radius:3px; 937 | } 938 | 939 | 940 | 941 | 942 | 943 | 20 944 | 70 945 | 61 946 | 51 947 | 948 | 949 | 950 | Bitrate 951 | 952 | 953 | 954 | 955 | 956 | 80 957 | 80 958 | 91 959 | 26 960 | 961 | 962 | 963 | QLineEdit{ 964 | color:white; 965 | border: none; 966 | padding-top: 2px; 967 | padding-bottom: 5px; 968 | background-color:rgb(22, 22, 22); 969 | border-radius:3px; 970 | } 971 | 972 | 973 | 8000000 974 | 975 | 976 | 977 | 978 | 979 | 180 980 | 90 981 | 41 982 | 18 983 | 984 | 985 | 986 | Hz 987 | 988 | 989 | 990 | 991 | 992 | 220 993 | 80 994 | 141 995 | 31 996 | 997 | 998 | 999 | 1000 | 8 1001 | 1002 | 1003 | 1004 | PointingHandCursor 1005 | 1006 | 1007 | QCheckBox{ 1008 | color:white; 1009 | border: none; 1010 | padding-left:4px; 1011 | background-color:rgb(22, 22, 22); 1012 | border-radius:3px; 1013 | } 1014 | QCheckBox::indicator 1015 | { 1016 | border-radius: 0.25em; 1017 | border: 0.1em solid rgb(114, 159, 207); 1018 | } 1019 | 1020 | QCheckBox::indicator::checked 1021 | { 1022 | background-color:rgb(114, 159, 207); 1023 | } 1024 | 1025 | 1026 | Fullscreen 1027 | 1028 | 1029 | Ctrl+F 1030 | 1031 | 1032 | 1033 | 1034 | 1035 | 380 1036 | 80 1037 | 121 1038 | 31 1039 | 1040 | 1041 | 1042 | 1043 | 8 1044 | 1045 | 1046 | 1047 | PointingHandCursor 1048 | 1049 | 1050 | true 1051 | 1052 | 1053 | QCheckBox{ 1054 | color:white; 1055 | border: none; 1056 | padding-left:4px; 1057 | background-color:rgb(22, 22, 22); 1058 | border-radius:3px; 1059 | } 1060 | QCheckBox::indicator 1061 | { 1062 | border-radius: 0.25em; 1063 | border: 0.1em solid rgb(114, 159, 207); 1064 | } 1065 | 1066 | QCheckBox::indicator::checked 1067 | { 1068 | background-color:rgb(114, 159, 207); 1069 | } 1070 | 1071 | 1072 | Borderless 1073 | 1074 | 1075 | Ctrl+B 1076 | 1077 | 1078 | 1079 | 1080 | 1081 | 20 1082 | 140 1083 | 121 1084 | 18 1085 | 1086 | 1087 | 1088 | Render Driver 1089 | 1090 | 1091 | 1092 | 1093 | 1094 | 120 1095 | 140 1096 | 541 1097 | 21 1098 | 1099 | 1100 | 1101 | 1102 | 0 1103 | 0 1104 | 1105 | 1106 | 1107 | 1108 | 16777215 1109 | 16777215 1110 | 1111 | 1112 | 1113 | 1114 | 8 1115 | 1116 | 1117 | 1118 | PointingHandCursor 1119 | 1120 | 1121 | QComboBox 1122 | { 1123 | color:white; 1124 | border: none; 1125 | padding-top: 2px; 1126 | padding-bottom: 5px; 1127 | background-color:rgb(22, 22, 22); 1128 | border-radius:3px; 1129 | } 1130 | 1131 | 1132 | 1133 | opengles2 1134 | 1135 | 1136 | 1137 | 1138 | opengles 1139 | 1140 | 1141 | 1142 | 1143 | opengl 1144 | 1145 | 1146 | 1147 | 1148 | direct3d 1149 | 1150 | 1151 | 1152 | 1153 | metal 1154 | 1155 | 1156 | 1157 | 1158 | software 1159 | 1160 | 1161 | 1162 | 1163 | 1164 | 1165 | 20 1166 | 190 1167 | 631 1168 | 31 1169 | 1170 | 1171 | 1172 | QLabel{ 1173 | opacity: .5; 1174 | } 1175 | 1176 | 1177 | <html><head/><body><p><span style=" color:#ffff00;">* If you're using Windows, is recommended to use 'direct3d' render driver</span></p></body></html> 1178 | 1179 | 1180 | 1181 | 1182 | 1183 | 20 1184 | 250 1185 | 141 1186 | 31 1187 | 1188 | 1189 | 1190 | 1191 | 16777215 1192 | 16777215 1193 | 1194 | 1195 | 1196 | QPushButton{ 1197 | background-color:rgba(53, 132, 228,190); 1198 | border: none; 1199 | border-radius:10px; 1200 | color:white; 1201 | } 1202 | 1203 | QPushButton:hover{ 1204 | background-color:rgb(32, 74, 135); 1205 | } 1206 | 1207 | 1208 | Reload Devices 1209 | 1210 | 1211 | 1212 | reload_btn.pngreload_btn.png 1213 | 1214 | 1215 | Ctrl+R 1216 | 1217 | 1218 | 1219 | 1220 | 1221 | 520 1222 | 250 1223 | 121 1224 | 31 1225 | 1226 | 1227 | 1228 | 1229 | 16777215 1230 | 16777215 1231 | 1232 | 1233 | 1234 | PointingHandCursor 1235 | 1236 | 1237 | QPushButton{ 1238 | color:rgb(255,255,255); 1239 | background-color:rgba(53, 132, 228,190); 1240 | border: none; 1241 | border-radius:10px; 1242 | } 1243 | 1244 | QPushButton:hover{ 1245 | background:rgb(32, 74, 135); 1246 | } 1247 | 1248 | 1249 | Start 1250 | 1251 | 1252 | 1253 | 60 1254 | 60 1255 | 1256 | 1257 | 1258 | Ctrl+Return 1259 | 1260 | 1261 | 1262 | 1263 | 1264 | 1265 | 1266 | 1267 | 10 1268 | 10 1269 | 151 1270 | 311 1271 | 1272 | 1273 | 1274 | QFrame{ 1275 | background-color: rgb(22,22,22); 1276 | } 1277 | 1278 | 1279 | QFrame::StyledPanel 1280 | 1281 | 1282 | QFrame::Raised 1283 | 1284 | 1285 | 1286 | 1287 | 10 1288 | 10 1289 | 131 1290 | 291 1291 | 1292 | 1293 | 1294 | QLabel{ 1295 | background-color: white; 1296 | } 1297 | 1298 | 1299 | Game Mode 1300 | 1301 | 1302 | Qt::AlignCenter 1303 | 1304 | 1305 | 1306 | 1307 | 1308 | 1309 | 180 1310 | 10 1311 | 661 1312 | 311 1313 | 1314 | 1315 | 1316 | QFrame{ 1317 | color: rgb(255,255,255); 1318 | } 1319 | 1320 | 1321 | QFrame::StyledPanel 1322 | 1323 | 1324 | QFrame::Raised 1325 | 1326 | 1327 | 1328 | 1329 | 20 1330 | 20 1331 | 61 1332 | 41 1333 | 1334 | 1335 | 1336 | Device 1337 | 1338 | 1339 | 1340 | 1341 | 1342 | 80 1343 | 30 1344 | 571 1345 | 21 1346 | 1347 | 1348 | 1349 | QComboBox{ 1350 | color:white; 1351 | border: none; 1352 | padding-top: 2px; 1353 | padding-bottom: 5px; 1354 | background-color:rgb(22, 22, 22); 1355 | border-radius:3px; 1356 | } 1357 | 1358 | 1359 | 1360 | 1361 | 1362 | 20 1363 | 70 1364 | 61 1365 | 51 1366 | 1367 | 1368 | 1369 | Bitrate 1370 | 1371 | 1372 | 1373 | 1374 | 1375 | 80 1376 | 80 1377 | 91 1378 | 26 1379 | 1380 | 1381 | 1382 | QLineEdit{ 1383 | color:white; 1384 | border: none; 1385 | padding-top: 2px; 1386 | padding-bottom: 5px; 1387 | background-color:rgb(22, 22, 22); 1388 | border-radius:3px; 1389 | } 1390 | 1391 | 1392 | 3000000 1393 | 1394 | 1395 | 1396 | 1397 | 1398 | 180 1399 | 90 1400 | 41 1401 | 18 1402 | 1403 | 1404 | 1405 | Hz 1406 | 1407 | 1408 | 1409 | 1410 | 1411 | 220 1412 | 80 1413 | 141 1414 | 31 1415 | 1416 | 1417 | 1418 | 1419 | 8 1420 | 1421 | 1422 | 1423 | PointingHandCursor 1424 | 1425 | 1426 | QCheckBox{ 1427 | color:white; 1428 | border: none; 1429 | padding-left:4px; 1430 | background-color:rgb(22, 22, 22); 1431 | border-radius:3px; 1432 | } 1433 | QCheckBox::indicator 1434 | { 1435 | border-radius: 0.25em; 1436 | border: 0.1em solid rgb(114, 159, 207); 1437 | } 1438 | 1439 | QCheckBox::indicator::checked 1440 | { 1441 | background-color:rgb(114, 159, 207); 1442 | } 1443 | 1444 | 1445 | Fullscreen 1446 | 1447 | 1448 | Ctrl+F 1449 | 1450 | 1451 | 1452 | 1453 | 1454 | 370 1455 | 80 1456 | 131 1457 | 31 1458 | 1459 | 1460 | 1461 | 1462 | 8 1463 | 1464 | 1465 | 1466 | PointingHandCursor 1467 | 1468 | 1469 | true 1470 | 1471 | 1472 | QCheckBox{ 1473 | color:white; 1474 | border: none; 1475 | padding-left:4px; 1476 | background-color:rgb(22, 22, 22); 1477 | border-radius:3px; 1478 | } 1479 | QCheckBox::indicator 1480 | { 1481 | border-radius: 0.25em; 1482 | border: 0.1em solid rgb(114, 159, 207); 1483 | } 1484 | 1485 | QCheckBox::indicator::checked 1486 | { 1487 | background-color:rgb(114, 159, 207); 1488 | } 1489 | 1490 | 1491 | Borderless 1492 | 1493 | 1494 | Ctrl+B 1495 | 1496 | 1497 | 1498 | 1499 | 1500 | 20 1501 | 140 1502 | 121 1503 | 18 1504 | 1505 | 1506 | 1507 | Render Driver 1508 | 1509 | 1510 | 1511 | 1512 | 1513 | 120 1514 | 140 1515 | 531 1516 | 21 1517 | 1518 | 1519 | 1520 | 1521 | 0 1522 | 0 1523 | 1524 | 1525 | 1526 | 1527 | 16777215 1528 | 16777215 1529 | 1530 | 1531 | 1532 | 1533 | 8 1534 | 1535 | 1536 | 1537 | PointingHandCursor 1538 | 1539 | 1540 | QComboBox 1541 | { 1542 | color:white; 1543 | border: none; 1544 | padding-top: 2px; 1545 | padding-bottom: 5px; 1546 | background-color:rgb(22, 22, 22); 1547 | border-radius:3px; 1548 | } 1549 | 1550 | 1551 | 1552 | opengl 1553 | 1554 | 1555 | 1556 | 1557 | opengles 1558 | 1559 | 1560 | 1561 | 1562 | opengles2 1563 | 1564 | 1565 | 1566 | 1567 | direct3d 1568 | 1569 | 1570 | 1571 | 1572 | metal 1573 | 1574 | 1575 | 1576 | 1577 | software 1578 | 1579 | 1580 | 1581 | 1582 | 1583 | 1584 | 20 1585 | 180 1586 | 631 1587 | 41 1588 | 1589 | 1590 | 1591 | QLabel{ 1592 | opacity: .5; 1593 | } 1594 | 1595 | 1596 | <html><head/><body><p><span style=" color:#ffff00;">* If you're using Windows, is recommended to use 'direct3d' render driver<br/>* In Game Mode, OTG tag is automatically launched with scrcpy args, to disable this, click &quot;No OTG&quot;</span></p></body></html> 1597 | 1598 | 1599 | 1600 | 1601 | 1602 | 20 1603 | 250 1604 | 141 1605 | 31 1606 | 1607 | 1608 | 1609 | 1610 | 16777215 1611 | 16777215 1612 | 1613 | 1614 | 1615 | QPushButton{ 1616 | background-color:rgba(53, 132, 228,190); 1617 | border: none; 1618 | border-radius:10px; 1619 | color:white; 1620 | } 1621 | 1622 | QPushButton:hover{ 1623 | background-color:rgb(32, 74, 135); 1624 | } 1625 | 1626 | 1627 | Reload Devices 1628 | 1629 | 1630 | 1631 | reload_btn.pngreload_btn.png 1632 | 1633 | 1634 | Ctrl+R 1635 | 1636 | 1637 | 1638 | 1639 | 1640 | 520 1641 | 250 1642 | 121 1643 | 31 1644 | 1645 | 1646 | 1647 | 1648 | 16777215 1649 | 16777215 1650 | 1651 | 1652 | 1653 | PointingHandCursor 1654 | 1655 | 1656 | QPushButton{ 1657 | color:rgb(255,255,255); 1658 | background-color:rgba(53, 132, 228,190); 1659 | border: none; 1660 | border-radius:10px; 1661 | } 1662 | 1663 | QPushButton:hover{ 1664 | background:rgb(32, 74, 135); 1665 | } 1666 | 1667 | 1668 | Start 1669 | 1670 | 1671 | 1672 | 60 1673 | 60 1674 | 1675 | 1676 | 1677 | Ctrl+Return 1678 | 1679 | 1680 | 1681 | 1682 | 1683 | 510 1684 | 80 1685 | 141 1686 | 31 1687 | 1688 | 1689 | 1690 | 1691 | 8 1692 | 1693 | 1694 | 1695 | PointingHandCursor 1696 | 1697 | 1698 | QCheckBox{ 1699 | color:white; 1700 | border: none; 1701 | padding-left:4px; 1702 | background-color:rgb(22, 22, 22); 1703 | border-radius:3px; 1704 | } 1705 | QCheckBox::indicator 1706 | { 1707 | border-radius: 0.25em; 1708 | border: 0.1em solid rgb(114, 159, 207); 1709 | } 1710 | 1711 | QCheckBox::indicator::checked 1712 | { 1713 | background-color:rgb(114, 159, 207); 1714 | } 1715 | 1716 | 1717 | No OTG 1718 | 1719 | 1720 | Ctrl+F 1721 | 1722 | 1723 | 1724 | 1725 | 1726 | 1727 | 1728 | 1729 | 10 1730 | 10 1731 | 151 1732 | 311 1733 | 1734 | 1735 | 1736 | QFrame{ 1737 | background-color: rgb(22,22,22); 1738 | } 1739 | 1740 | 1741 | QFrame::StyledPanel 1742 | 1743 | 1744 | QFrame::Raised 1745 | 1746 | 1747 | 1748 | 1749 | 10 1750 | 10 1751 | 131 1752 | 291 1753 | 1754 | 1755 | 1756 | QLabel{ 1757 | background-color: white; 1758 | } 1759 | 1760 | 1761 | Manual 1762 | 1763 | 1764 | Qt::AlignCenter 1765 | 1766 | 1767 | 1768 | 1769 | 1770 | 1771 | 180 1772 | 10 1773 | 661 1774 | 311 1775 | 1776 | 1777 | 1778 | QFrame{ 1779 | color: rgb(255,255,255); 1780 | } 1781 | 1782 | 1783 | QFrame::StyledPanel 1784 | 1785 | 1786 | QFrame::Raised 1787 | 1788 | 1789 | 1790 | 1791 | 20 1792 | 20 1793 | 61 1794 | 41 1795 | 1796 | 1797 | 1798 | Device 1799 | 1800 | 1801 | 1802 | 1803 | 1804 | 80 1805 | 30 1806 | 571 1807 | 21 1808 | 1809 | 1810 | 1811 | QComboBox{ 1812 | color:white; 1813 | border: none; 1814 | padding-top: 2px; 1815 | padding-bottom: 5px; 1816 | background-color:rgb(22, 22, 22); 1817 | border-radius:3px; 1818 | } 1819 | 1820 | 1821 | 1822 | 1823 | 1824 | 20 1825 | 70 1826 | 61 1827 | 51 1828 | 1829 | 1830 | 1831 | Bitrate 1832 | 1833 | 1834 | 1835 | 1836 | 1837 | 80 1838 | 80 1839 | 91 1840 | 26 1841 | 1842 | 1843 | 1844 | QLineEdit{ 1845 | color:white; 1846 | border: none; 1847 | padding-top: 2px; 1848 | padding-bottom: 5px; 1849 | background-color:rgb(22, 22, 22); 1850 | border-radius:3px; 1851 | } 1852 | 1853 | 1854 | 1855 | 1856 | 1857 | 1858 | 1859 | 1860 | 180 1861 | 90 1862 | 41 1863 | 18 1864 | 1865 | 1866 | 1867 | Hz 1868 | 1869 | 1870 | 1871 | 1872 | 1873 | 380 1874 | 80 1875 | 141 1876 | 31 1877 | 1878 | 1879 | 1880 | 1881 | 8 1882 | 1883 | 1884 | 1885 | PointingHandCursor 1886 | 1887 | 1888 | QCheckBox{ 1889 | color:white; 1890 | border: none; 1891 | padding-left:4px; 1892 | background-color:rgb(22, 22, 22); 1893 | border-radius:3px; 1894 | } 1895 | QCheckBox::indicator 1896 | { 1897 | border-radius: 0.25em; 1898 | border: 0.1em solid rgb(114, 159, 207); 1899 | } 1900 | 1901 | QCheckBox::indicator::checked 1902 | { 1903 | background-color:rgb(114, 159, 207); 1904 | } 1905 | 1906 | 1907 | Fullscreen 1908 | 1909 | 1910 | Ctrl+F 1911 | 1912 | 1913 | 1914 | 1915 | 1916 | 220 1917 | 80 1918 | 151 1919 | 31 1920 | 1921 | 1922 | 1923 | 1924 | 8 1925 | 1926 | 1927 | 1928 | PointingHandCursor 1929 | 1930 | 1931 | true 1932 | 1933 | 1934 | QCheckBox{ 1935 | color:white; 1936 | border: none; 1937 | padding-left:4px; 1938 | background-color:rgb(22, 22, 22); 1939 | border-radius:3px; 1940 | } 1941 | QCheckBox::indicator 1942 | { 1943 | border-radius: 0.25em; 1944 | border: 0.1em solid rgb(114, 159, 207); 1945 | } 1946 | 1947 | QCheckBox::indicator::checked 1948 | { 1949 | background-color:rgb(114, 159, 207); 1950 | } 1951 | 1952 | 1953 | View Only 1954 | 1955 | 1956 | Ctrl+X 1957 | 1958 | 1959 | 1960 | 1961 | 1962 | 530 1963 | 80 1964 | 121 1965 | 31 1966 | 1967 | 1968 | 1969 | 1970 | 8 1971 | 1972 | 1973 | 1974 | PointingHandCursor 1975 | 1976 | 1977 | true 1978 | 1979 | 1980 | QCheckBox{ 1981 | color:white; 1982 | border: none; 1983 | padding-left:4px; 1984 | background-color:rgb(22, 22, 22); 1985 | border-radius:3px; 1986 | } 1987 | QCheckBox::indicator 1988 | { 1989 | border-radius: 0.25em; 1990 | border: 0.1em solid rgb(114, 159, 207); 1991 | } 1992 | 1993 | QCheckBox::indicator::checked 1994 | { 1995 | background-color:rgb(114, 159, 207); 1996 | } 1997 | 1998 | 1999 | Borderless 2000 | 2001 | 2002 | Ctrl+B 2003 | 2004 | 2005 | 2006 | 2007 | 2008 | 20 2009 | 140 2010 | 121 2011 | 18 2012 | 2013 | 2014 | 2015 | Render Driver 2016 | 2017 | 2018 | 2019 | 2020 | 2021 | 120 2022 | 140 2023 | 531 2024 | 21 2025 | 2026 | 2027 | 2028 | 2029 | 0 2030 | 0 2031 | 2032 | 2033 | 2034 | 2035 | 16777215 2036 | 16777215 2037 | 2038 | 2039 | 2040 | 2041 | 8 2042 | 2043 | 2044 | 2045 | PointingHandCursor 2046 | 2047 | 2048 | QComboBox 2049 | { 2050 | color:white; 2051 | border: none; 2052 | padding-top: 2px; 2053 | padding-bottom: 5px; 2054 | background-color:rgb(22, 22, 22); 2055 | border-radius:3px; 2056 | } 2057 | 2058 | 2059 | 2060 | opengles2 2061 | 2062 | 2063 | 2064 | 2065 | opengles 2066 | 2067 | 2068 | 2069 | 2070 | opengl 2071 | 2072 | 2073 | 2074 | 2075 | direct3d 2076 | 2077 | 2078 | 2079 | 2080 | metal 2081 | 2082 | 2083 | 2084 | 2085 | software 2086 | 2087 | 2088 | 2089 | 2090 | 2091 | 2092 | 20 2093 | 250 2094 | 141 2095 | 31 2096 | 2097 | 2098 | 2099 | 2100 | 16777215 2101 | 16777215 2102 | 2103 | 2104 | 2105 | QPushButton{ 2106 | background-color:rgba(53, 132, 228,190); 2107 | border: none; 2108 | border-radius:10px; 2109 | color:white; 2110 | } 2111 | 2112 | QPushButton:hover{ 2113 | background-color:rgb(32, 74, 135); 2114 | } 2115 | 2116 | 2117 | Reload Devices 2118 | 2119 | 2120 | 2121 | reload_btn.pngreload_btn.png 2122 | 2123 | 2124 | Ctrl+R 2125 | 2126 | 2127 | 2128 | 2129 | 2130 | 520 2131 | 250 2132 | 121 2133 | 31 2134 | 2135 | 2136 | 2137 | 2138 | 16777215 2139 | 16777215 2140 | 2141 | 2142 | 2143 | PointingHandCursor 2144 | 2145 | 2146 | QPushButton{ 2147 | color:rgb(255,255,255); 2148 | background-color:rgba(53, 132, 228,190); 2149 | border: none; 2150 | border-radius:10px; 2151 | } 2152 | 2153 | QPushButton:hover{ 2154 | background:rgb(32, 74, 135); 2155 | } 2156 | 2157 | 2158 | Start 2159 | 2160 | 2161 | 2162 | 60 2163 | 60 2164 | 2165 | 2166 | 2167 | Ctrl+Return 2168 | 2169 | 2170 | 2171 | 2172 | 2173 | 20 2174 | 180 2175 | 101 2176 | 21 2177 | 2178 | 2179 | 2180 | Additional args 2181 | 2182 | 2183 | 2184 | 2185 | 2186 | 120 2187 | 180 2188 | 521 2189 | 51 2190 | 2191 | 2192 | 2193 | 2194 | 10 2195 | 2196 | 2197 | 2198 | QTextEdit{ 2199 | color:white; 2200 | border: none; 2201 | padding-top: 2px; 2202 | padding-bottom: 5px; 2203 | background-color:rgb(22, 22, 22); 2204 | border-radius:3px; 2205 | } 2206 | 2207 | 2208 | <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> 2209 | <html><head><meta name="qrichtext" content="1" /><style type="text/css"> 2210 | p, li { white-space: pre-wrap; } 2211 | </style></head><body style=" font-family:'Noto Sans, '; font-size:10pt; font-weight:400; font-style:normal;"> 2212 | <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">--max-fps=60 </p></body></html> 2213 | 2214 | 2215 | 2216 | 2217 | 2218 | 2219 | 2220 | 2221 | 690 2222 | 10 2223 | 151 2224 | 311 2225 | 2226 | 2227 | 2228 | QFrame{ 2229 | background-color: rgb(22,22,22); 2230 | } 2231 | 2232 | 2233 | QFrame::StyledPanel 2234 | 2235 | 2236 | QFrame::Raised 2237 | 2238 | 2239 | 2240 | 2241 | 10 2242 | 10 2243 | 131 2244 | 291 2245 | 2246 | 2247 | 2248 | QLabel{ 2249 | background-color: white; 2250 | } 2251 | 2252 | 2253 | Configs 2254 | 2255 | 2256 | Qt::AlignCenter 2257 | 2258 | 2259 | 2260 | 2261 | 2262 | 2263 | 10 2264 | 10 2265 | 661 2266 | 311 2267 | 2268 | 2269 | 2270 | QFrame{ 2271 | color: rgb(255,255,255); 2272 | } 2273 | 2274 | 2275 | QFrame::StyledPanel 2276 | 2277 | 2278 | QFrame::Raised 2279 | 2280 | 2281 | 2282 | 2283 | 140 2284 | 10 2285 | 351 2286 | 61 2287 | 2288 | 2289 | 2290 | 2291 | Cantarell 2292 | 11 2293 | 2294 | 2295 | 2296 | Configurations 2297 | 2298 | 2299 | Qt::AlignCenter 2300 | 2301 | 2302 | 2303 | 2304 | 2305 | 20 2306 | 60 2307 | 641 2308 | 121 2309 | 2310 | 2311 | 2312 | QFrame::Plain 2313 | 2314 | 2315 | <html><head/><body><p><span style=" font-weight:600;">Sorry :(</span></p><p>Configurations not implemented yet.</p><p>You can receive upcoming early access versions through Project's Github Page:</p><p><a href="https://github.com/hayukimori/scrcpy-pyqtgui/"><span style=" text-decoration: underline; color:#0000ff;">https://github.com/hayukimori/scrcpy-pyqtgui/</span></a></p></body></html> 2316 | 2317 | 2318 | false 2319 | 2320 | 2321 | Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop 2322 | 2323 | 2324 | true 2325 | 2326 | 2327 | true 2328 | 2329 | 2330 | 2331 | 2332 | 2333 | 2334 | 2335 | 2336 | 110 2337 | 30 2338 | 711 2339 | 41 2340 | 2341 | 2342 | 2343 | QFrame{ 2344 | background-color: rgba(28, 113, 216, 210) 2345 | } 2346 | 2347 | 2348 | QFrame::StyledPanel 2349 | 2350 | 2351 | QFrame::Raised 2352 | 2353 | 2354 | 2355 | 2356 | 2357 | 2358 | Noto Sans Arabic Light 2359 | 11 2360 | 50 2361 | false 2362 | 2363 | 2364 | 2365 | QLabel{ 2366 | background: none; 2367 | color: white; 2368 | } 2369 | 2370 | 2371 | Scrcpy PyQt5 GUI 2372 | 2373 | 2374 | Qt::AlignCenter 2375 | 2376 | 2377 | 2378 | 2379 | 2380 | stackedWidget 2381 | minimize_btn 2382 | exit_button 2383 | groupBox 2384 | frame_6 2385 | 2386 | 2387 | 2388 | 2389 | 2390 | 2391 | 2392 | 2393 | --------------------------------------------------------------------------------