Skip to content

Commit

Permalink
All scripts and WSL GUI work
Browse files Browse the repository at this point in the history
  • Loading branch information
Avasam committed Dec 9, 2023
1 parent d6d75c2 commit 9c7b2ae
Show file tree
Hide file tree
Showing 14 changed files with 79 additions and 50 deletions.
4 changes: 2 additions & 2 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,9 @@
"editor.tabSize": 2,
"editor.formatOnSave": true,
"editor.codeActionsOnSave": {
"source.fixAll": true,
"source.fixAll": "explicit",
// Let dedicated linter (Ruff) organize imports
"source.organizeImports": false,
"source.organizeImports": "never"
},
"emeraldwalk.runonsave": {
"commands": [
Expand Down
5 changes: 4 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,8 @@ This program can be used to automatically start, split, and reset your preferred

- Windows 10 and 11.
- Linux (Only tested on Ubuntu 22.04)
- Wayland is not supported
- Wayland is not currently supported
- WSL2/WSLg requires an additional Desktop Environment, external X11 server, and/or systemd
- Python 3.10+ (Not required for normal use. Refer to the [build instructions](/docs/build%20instructions.md) if you'd like run the application directly in Python).

## OPTIONS
Expand Down Expand Up @@ -286,6 +287,8 @@ Not a developer? You can still help through the following methods:
- Sharing AutoSplit with other speedrunners
- Upvoting the following upstream issues in libraries and tools we use:
- <https://bugreports.qt.io/browse/QTBUG-114436>
- <https://bugreports.qt.io/browse/QTBUG-114635>
- <https://bugreports.qt.io/browse/PYSIDE-2542>
- <https://github.com/astral-sh/ruff/issues?q=is%3Aopen+involves%3AAvasam>
- <https://github.com/opencv/opencv/issues?q=is%3Aopen+involves%3AAvasam>
- <https://github.com/opencv/opencv/issues/23906>
Expand Down
2 changes: 1 addition & 1 deletion docs/CONTRIBUTING.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<!-- This has to in the repository's root, `docs/`, or `.github/` directory to be picked by github. Read more at: https://docs.github.com/en/communities/setting-up-your-project-for-healthy-contributions/setting-guidelines-for-repository-contributors#about-contributing-guidelines -->
<!-- This has to be in the repository's root, `docs/`, or `.github/` directory to be picked by github. Read more at: https://docs.github.com/en/communities/setting-up-your-project-for-healthy-contributions/setting-guidelines-for-repository-contributors#about-contributing-guidelines -->

# Contributing guidelines

Expand Down
38 changes: 20 additions & 18 deletions scripts/install.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -34,13 +34,8 @@ $dev = If ($Env:GITHUB_JOB -eq 'Build') { '' } Else { '-dev' }
If ($IsLinux) {
If (-not $Env:GITHUB_JOB -or $Env:GITHUB_JOB -eq 'Build') {
sudo apt-get update
# python3-tk for splash screen, npm for pyright
sudo apt-get install -y python3-pip python3-tk npm
# Helps ensure build machine has the required PySide6 libraries for all target machines.
# Not everything here is required, but using the documentation from
# https://wiki.qt.io/Building_Qt_5_from_Git#Libxcb
# TODO: Test if still necessary with PySide6
sudo apt-get install -y '^libxcb.*-dev' libx11-xcb-dev libglu1-mesa-dev libxrender-dev libxi-dev libxkbcommon-dev libxkbcommon-x11-dev
# python3-tk for splash screen, npm for pyright, the rest for PySide6
sudo apt-get install -y python3-pip python3-tk npm libegl1 libxkbcommon
}
}
# Ensures installation tools are up to date. This also aliases pip to pip3 on MacOS.
Expand All @@ -61,21 +56,28 @@ pip install PyAutoGUI ImageHash scipy --no-deps --upgrade
$libPath = &"$python" -c 'import pyautogui as _; print(_.__path__[0])'
(Get-Content "$libPath/_pyautogui_win.py").replace('ctypes.windll.user32.SetProcessDPIAware()', 'pass') |
Set-Content "$libPath/_pyautogui_win.py"
$libPath = &"$python" -c 'import pymonctl as _; print(_.__path__[0])'
(Get-Content "$libPath/_pymonctl_win.py").replace('ctypes.windll.shcore.SetProcessDpiAwareness(2)', 'pass') |
Set-Content "$libPath/_pymonctl_win.py"
$libPath = &"$python" -c 'import pywinbox as _; print(_.__path__[0])'
(Get-Content "$libPath/_pywinbox_win.py").replace('ctypes.windll.shcore.SetProcessDpiAwareness(2)', 'pass') |
Set-Content "$libPath/_pywinbox_win.py"
If ($IsWindows) {
$libPath = &"$python" -c 'import pymonctl as _; print(_.__path__[0])'
(Get-Content "$libPath/_pymonctl_win.py").replace('ctypes.windll.shcore.SetProcessDpiAwareness(2)', 'pass') |
Set-Content "$libPath/_pymonctl_win.py"
$libPath = &"$python" -c 'import pywinbox as _; print(_.__path__[0])'
(Get-Content "$libPath/_pywinbox_win.py").replace('ctypes.windll.shcore.SetProcessDpiAwareness(2)', 'pass') |
Set-Content "$libPath/_pywinbox_win.py"
pip uninstall pyscreeze
}
# Because Ubuntu 22.04 is forced to use an older version of PySide6, we do a dirty typing patch
# https://bugreports.qt.io/browse/QTBUG-114635
If ($IsLinux) {
$libPath = &"$python" -c 'import PySide6 as _; print(_.__path__[0])'
(Get-Content "$libPath/QtWidgets.pyi").replace('-> Tuple:', '-> Tuple[str, ...]:') |
Set-Content "$libPath/QtWidgets.pyi"
}
# Uninstall optional dependencies if PyAutoGUI was installed outside this script
# pyscreeze -> pyscreenshot -> mss deps call SetProcessDpiAwareness
# pyscreeze -> pyscreenshot -> mss deps call SetProcessDpiAwareness, used to be installed
# pygetwindow, pymsgbox, pytweening, MouseInfo are picked up by PySide6
# (also --exclude from build script, but more consistent with unfrozen run)
pip uninstall pyscreenshot mss pygetwindow pymsgbox pytweening MouseInfo -y
If (-not $IsLinux) {
pip uninstall pyscreeze
}

If ($IsWindows) { pip uninstall pyscreeze }

# Don't compile resources on the Build CI job as it'll do so in build script
If ($dev) {
Expand Down
28 changes: 28 additions & 0 deletions scripts/linux_build_and_install_python.bash
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
cd ..

# Update package lists
sudo apt update

# Install dependent libraries:
sudo apt install build-essential zlib1g-dev libncurses5-dev libgdbm-dev libnss3-dev libssl-dev libsqlite3-dev libreadline-dev libffi-dev curl libbz2-dev tk-dev

# Download Python binary package:
wget https://www.python.org/ftp/python/3.10.13/Python-3.10.13.tgz

# Unzip the package:
tar -xzf Python-3.10.13.tgz

# Execute configure script
cd Python-3.10.13
./configure --enable-optimizations --enable-shared

# Build Python 3.10
make -j 2

# Install Python 3.10
sudo make install

# Verify the installation
python3.10 -V

echo "If Python version did not print, you may need to stop active processes"
3 changes: 2 additions & 1 deletion scripts/requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@ psutil>=5.9.6 # Python 3.12 fixes
PyAutoGUI
PyWinCtl>=0.0.42 # py.typed
# When needed, dev builds can be found at https://download.qt.io/snapshots/ci/pyside/dev?C=M;O=D
PySide6-Essentials>=6.6.0 # Python 3.12 support
PySide6-Essentials>=6.6.0 ; sys_platform == 'win32' # Python 3.12 support
PySide6-Essentials<6.5.1 ; sys_platform == 'linux' # Wayland issue on Ubuntu 22.04 https://bugreports.qt.io/browse/QTBUG-114635
requests>=2.28.2 # charset_normalizer 3.x update
toml
typing-extensions>=4.4.0 # @override decorator support
Expand Down
12 changes: 4 additions & 8 deletions src/capture_method/Screenshot using QT attempt.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,25 +3,21 @@

if sys.platform != "linux":
raise OSError()
from typing import TYPE_CHECKING, cast
from typing import cast

import cv2
import numpy as np
from cv2.typing import MatLike
from PySide6.QtCore import QBuffer, QIODeviceBase
from PySide6.QtGui import QGuiApplication
from capture_method.CaptureMethodBase import CaptureMethodBase
from capture_method.CaptureMethodBase import ThreadedLoopCaptureMethod
from typing_extensions import override

if TYPE_CHECKING:
from AutoSplit import AutoSplit


class ScrotCaptureMethod(CaptureMethodBase):
class QtCaptureMethod(ThreadedLoopCaptureMethod):
_render_full_content = False

@override
def get_frame(self):
def _read_action(self):
buffer = QBuffer()
buffer.open(QIODeviceBase.OpenModeFlag.ReadWrite)
winid = self._autosplit_ref.winId()
Expand Down
6 changes: 1 addition & 5 deletions src/capture_method/ScrotCaptureMethod.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,11 +40,7 @@ def _read_action(self):
selection["height"],
),
)
return np.array(image)

@override
def get_frame(self):
image = super().get_frame()
image = np.array(image)
if not is_valid_image(image):
return None
return cv2.cvtColor(image, cv2.COLOR_RGB2BGRA)
3 changes: 2 additions & 1 deletion src/capture_method/VideoCaptureDeviceCaptureMethod.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,11 +43,13 @@ class VideoCaptureDeviceCaptureMethod(ThreadedLoopCaptureMethod):
capture_device: cv2.VideoCapture

def __init__(self, autosplit: "AutoSplit"):
super().__init__(autosplit)
self.capture_device = cv2.VideoCapture(autosplit.settings_dict["capture_device_id"])
self.capture_device.setExceptionMode(True)

# The video capture device isn't accessible, don't bother with it.
if not self.capture_device.isOpened():
self.close()
return

# Ensure we're using the right camera size. And not OpenCV's default 640x480
Expand All @@ -62,7 +64,6 @@ def __init__(self, autosplit: "AutoSplit"):
except cv2.error:
# Some cameras don't allow changing the resolution
pass
super().__init__(autosplit)

@override
def close(self):
Expand Down
6 changes: 1 addition & 5 deletions src/capture_method/XDisplayCaptureMethod.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,11 +43,7 @@ def _read_action(self):
),
xdisplay=self._xdisplay,
)
return np.array(image)

@override
def get_frame(self):
image = super().get_frame()
image = np.array(image)
if not is_valid_image(image):
return None
return cv2.cvtColor(image, cv2.COLOR_RGB2BGRA)
Expand Down
6 changes: 3 additions & 3 deletions src/capture_method/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@

if sys.platform == "linux":
import pyscreeze
from PIL import features
from PIL import UnidentifiedImageError, features

from capture_method.ScrotCaptureMethod import ScrotCaptureMethod
from capture_method.XDisplayCaptureMethod import XDisplayCaptureMethod
Expand Down Expand Up @@ -152,7 +152,7 @@ def get(self, key: CaptureMethodEnum, __default: object = None):
CAPTURE_METHODS[CaptureMethodEnum.XDISPLAY] = XDisplayCaptureMethod
try:
pyscreeze.screenshot()
except NotImplementedError:
except UnidentifiedImageError:
pass
else:
# TODO: Investigate solution for Slow Scrot:
Expand Down Expand Up @@ -202,7 +202,7 @@ def get_input_devices():
return cameras


def get_input_device_resolution(index: int):
def get_input_device_resolution(index: int) -> tuple[int, int] | None:
if sys.platform != "win32":
return (0, 0)
filter_graph = FilterGraph()
Expand Down
2 changes: 1 addition & 1 deletion src/error_messages.py
Original file line number Diff line number Diff line change
Expand Up @@ -168,7 +168,7 @@ def linux_groups():
def linux_uinput():
set_text_message(
"Failed to create a device file using `uinput` module. "
+ "This can happen when runnign Linux under WSL. "
+ "This can happen when running Linux under WSL. "
+ "Keyboard events have been disabled.",
)

Expand Down
12 changes: 8 additions & 4 deletions src/region_selection.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
from cv2.typing import MatLike
from PySide6 import QtCore, QtGui, QtWidgets
from PySide6.QtTest import QTest
from pywinctl import getTopWindowAt
from typing_extensions import override

import error_messages
Expand All @@ -34,6 +33,11 @@

if sys.platform == "linux":
from Xlib.display import Display
# This variable may be missing in desktopless environment. x11 | wayland
os.environ.setdefault("XDG_SESSION_TYPE", "x11")

# Must come after the linux XDG_SESSION_TYPE environment variable is set
from pywinctl import getTopWindowAt

if TYPE_CHECKING:
from AutoSplit import AutoSplit
Expand Down Expand Up @@ -113,7 +117,7 @@ def select_region(autosplit: "AutoSplit"):
if not window:
error_messages.region()
return
hwnd = window.getHandle().id if sys.platform == "linux" else window.getHandle()
hwnd = window.getHandle()
window_text = window.title
if not is_valid_hwnd(hwnd) or not window_text:
error_messages.region()
Expand Down Expand Up @@ -162,7 +166,7 @@ def select_window(autosplit: "AutoSplit"):
if not window:
error_messages.region()
return
hwnd = window.getHandle().id if sys.platform == "linux" else window.getHandle()
hwnd = window.getHandle()
window_text = window.title
if not is_valid_hwnd(hwnd) or not window_text:
error_messages.region()
Expand All @@ -179,7 +183,7 @@ def select_window(autosplit: "AutoSplit"):
border_width = ceil((window_width - client_width) / 2)
titlebar_with_border_height = window_height - client_height - border_width
else:
data = window.getHandle().get_geometry()._data # noqa: SLF001
data = window._xWin.get_geometry()._data # pyright:ignore[reportPrivateUsage] # noqa: SLF001
client_height = data["height"]
client_width = data["width"]
border_width = data["border_width"]
Expand Down
2 changes: 2 additions & 0 deletions src/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,8 @@ def first(iterable: Iterable[T]) -> T:


def try_delete_dc(dc: "PyCDC"):
if sys.platform != "win32":
raise OSError
try:
dc.DeleteDC()
except win32ui.error:
Expand Down

0 comments on commit 9c7b2ae

Please sign in to comment.