From fba17cba5349c33866c7e703e38f7185e866ceae Mon Sep 17 00:00:00 2001 From: Anthony Samms Date: Sun, 9 Nov 2025 10:16:01 -0500 Subject: [PATCH] all keys are rebindable --- PyTaiko.py | 7 ++++--- config.toml | 8 +++++++- libs/global_data.py | 9 ++++++++- libs/utils.py | 39 ++++++++++++++------------------------- pyproject.toml | 1 + scenes/game.py | 5 +++-- scenes/settings.py | 7 ++++--- scenes/song_select.py | 5 +++-- uv.lock | 20 ++++++++++++++++++++ 9 files changed, 64 insertions(+), 37 deletions(-) diff --git a/PyTaiko.py b/PyTaiko.py index 23322a9..d9a2884 100644 --- a/PyTaiko.py +++ b/PyTaiko.py @@ -16,6 +16,7 @@ from libs.screen import Screen from libs.utils import ( force_dedicated_gpu, get_config, + get_key_code, global_data, global_tex ) @@ -187,16 +188,16 @@ def main(): ray.gen_texture_mipmaps(target.texture) ray.set_texture_filter(target.texture, ray.TextureFilter.TEXTURE_FILTER_TRILINEAR) ray.rl_set_blend_factors_separate(RL_SRC_ALPHA, RL_ONE_MINUS_SRC_ALPHA, RL_ONE, RL_ONE_MINUS_SRC_ALPHA, RL_FUNC_ADD, RL_FUNC_ADD) - ray.set_exit_key(ord(global_data.config["keys_1p"]["exit_key"])) + ray.set_exit_key(get_key_code(global_data.config["keys"]["exit_key"])) ray.hide_cursor() logger.info("Cursor hidden") while not ray.window_should_close(): - if ray.is_key_pressed(ray.KeyboardKey.KEY_F11): + if ray.is_key_pressed(get_key_code(global_data.config["keys"]["fullscreen_key"])): ray.toggle_fullscreen() logger.info("Toggled fullscreen") - elif ray.is_key_pressed(ray.KeyboardKey.KEY_F10): + elif ray.is_key_pressed(get_key_code(global_data.config["keys"]["borderless_key"])): ray.toggle_borderless_windowed() logger.info("Toggled borderless windowed mode") diff --git a/config.toml b/config.toml index a1a2c26..a88efe3 100644 --- a/config.toml +++ b/config.toml @@ -31,8 +31,14 @@ rainbow = false tja_path = ['Songs'] video_path = ['Videos'] -[keys_1p] +[keys] exit_key = 'Q' +borderless_key = 'F10' +fullscreen_key = 'F11' +back_key = 'ESCAPE' +restart_key = 'F1' + +[keys_1p] left_kat = ['D'] left_don = ['F'] right_don = ['J'] diff --git a/libs/global_data.py b/libs/global_data.py index 1d0016e..33351b4 100644 --- a/libs/global_data.py +++ b/libs/global_data.py @@ -27,8 +27,14 @@ class PathsConfig(TypedDict): tja_path: list[str] video_path: list[str] -class Keys1PConfig(TypedDict): +class KeysConfig(TypedDict): exit_key: str + fullscreen_key: str + borderless_key: str + back_key: str + restart_key: str + +class Keys1PConfig(TypedDict): left_kat: list[str] left_don: list[str] right_don: list[str] @@ -72,6 +78,7 @@ class Config(TypedDict): nameplate_1p: NameplateConfig nameplate_2p: NameplateConfig paths: PathsConfig + keys: KeysConfig keys_1p: Keys1PConfig keys_2p: Keys2PConfig gamepad: GamepadConfig diff --git a/libs/utils.py b/libs/utils.py index f85c89f..8d2f637 100644 --- a/libs/utils.py +++ b/libs/utils.py @@ -84,7 +84,7 @@ def get_config() -> Config: return json.loads(json.dumps(config_file)) -def save_config(config: dict[str, Any]) -> None: +def save_config(config: Config) -> None: """Save the configuration to the TOML file""" if Path('dev-config.toml').exists(): with open(Path('dev-config.toml'), "w", encoding="utf-8") as f: @@ -93,6 +93,15 @@ def save_config(config: dict[str, Any]) -> None: with open(Path('config.toml'), "w", encoding="utf-8") as f: tomlkit.dump(config, f) +def get_key_code(key: str) -> int: + if len(key) == 1 and key.isalnum(): + return ord(key.upper()) + else: + key_code = getattr(ray, f"KEY_{key.upper()}", None) + if key_code is None: + raise ValueError(f"Invalid key: {key}") + return key_code + def is_l_don_pressed(player_num: str = '0') -> bool: """Check if the left don button is pressed""" if global_data.input_locked: @@ -106,12 +115,7 @@ def is_l_don_pressed(player_num: str = '0') -> bool: else: return False for key in keys: - if len(key) == 1 and key.isalnum(): - key_code = ord(key.upper()) - else: - key_code = getattr(ray, f"KEY_{key.upper()}", None) - if key_code is None: - continue + key_code = get_key_code(key) if ray.is_key_pressed(key_code): return True @@ -147,12 +151,7 @@ def is_r_don_pressed(player_num: str = '0') -> bool: else: return False for key in keys: - if len(key) == 1 and key.isalnum(): - key_code = ord(key.upper()) - else: - key_code = getattr(ray, f"KEY_{key.upper()}", None) - if key_code is None: - continue + key_code = get_key_code(key) if ray.is_key_pressed(key_code): return True @@ -188,12 +187,7 @@ def is_l_kat_pressed(player_num: str = '0') -> bool: else: return False for key in keys: - if len(key) == 1 and key.isalnum(): - key_code = ord(key.upper()) - else: - key_code = getattr(ray, f"KEY_{key.upper()}", None) - if key_code is None: - continue + key_code = get_key_code(key) if ray.is_key_pressed(key_code): return True @@ -229,12 +223,7 @@ def is_r_kat_pressed(player_num: str = '0') -> bool: else: return False for key in keys: - if len(key) == 1 and key.isalnum(): - key_code = ord(key.upper()) - else: - key_code = getattr(ray, f"KEY_{key.upper()}", None) - if key_code is None: - continue + key_code = get_key_code(key) if ray.is_key_pressed(key_code): return True diff --git a/pyproject.toml b/pyproject.toml index cee1fdf..557b5c8 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -18,6 +18,7 @@ paths = ["."] dev = [ "nuitka>=2.8.4", "pyinstrument>=5.1.1", + "pyrefly>=0.40.1", "ruff>=0.14.2", "vulture>=2.14", ] diff --git a/scenes/game.py b/scenes/game.py index fb0120f..1880adc 100644 --- a/scenes/game.py +++ b/scenes/game.py @@ -29,6 +29,7 @@ from libs.transition import Transition from libs.utils import ( OutlinedText, get_current_ms, + get_key_code, global_data, global_tex, is_l_don_pressed, @@ -199,14 +200,14 @@ class GameScreen(Screen): self.song_started = True def global_keys(self): - if ray.is_key_pressed(ray.KeyboardKey.KEY_F1): + if ray.is_key_pressed(get_key_code(global_data.config["keys"]["restart_key"])): if self.song_music is not None: audio.stop_music_stream(self.song_music) self.init_tja(global_data.session_data[global_data.player_num-1].selected_song) audio.play_sound('restart', 'sound') self.song_started = False - if ray.is_key_pressed(ray.KeyboardKey.KEY_ESCAPE): + if ray.is_key_pressed(get_key_code(global_data.config["keys"]["back_key"])): if self.song_music is not None: audio.stop_music_stream(self.song_music) return self.on_screen_end('SONG_SELECT') diff --git a/scenes/settings.py b/scenes/settings.py index f7f3fab..446bbf3 100644 --- a/scenes/settings.py +++ b/scenes/settings.py @@ -4,6 +4,7 @@ import pyray as ray from libs.audio import audio from libs.screen import Screen from libs.utils import ( + get_key_code, global_data, is_l_don_pressed, is_l_kat_pressed, @@ -120,7 +121,7 @@ class SettingsScreen(Screen): self.config[current_header][setting_key] = [new_key] self.editing_key = False logger.info(f"Key binding updated: {current_header}.{setting_key} -> {new_key}") - elif key_pressed == ray.KeyboardKey.KEY_ESCAPE: + elif key_pressed == get_key_code(global_data.config["keys"]["back_key"]): self.editing_key = False logger.info("Key binding edit cancelled") @@ -139,7 +140,7 @@ class SettingsScreen(Screen): self.config[current_header][setting_key] = [button_pressed] self.editing_gamepad = False logger.info(f"Gamepad binding updated: {current_header}.{setting_key} -> {button_pressed}") - if ray.is_key_pressed(ray.KeyboardKey.KEY_ESCAPE): + if ray.is_key_pressed(get_key_code(global_data.config["keys"]["back_key"])): self.editing_gamepad = False logger.info("Gamepad binding edit cancelled") @@ -221,7 +222,7 @@ class SettingsScreen(Screen): if ('keys' not in current_header) and ('gamepad' not in current_header): self.handle_string_cycle(current_header, setting_key) - elif ray.is_key_pressed(ray.KeyboardKey.KEY_ESCAPE): + elif ray.is_key_pressed(get_key_code(global_data.config["keys"]["back_key"])): self.in_setting_edit = False logger.info("Exited section edit") diff --git a/scenes/song_select.py b/scenes/song_select.py index e5d9813..e004699 100644 --- a/scenes/song_select.py +++ b/scenes/song_select.py @@ -17,6 +17,7 @@ from libs.transition import Transition from libs.utils import ( OutlinedText, get_current_ms, + get_key_code, global_data, is_l_don_pressed, is_l_kat_pressed, @@ -305,8 +306,8 @@ class SongSelectScreen(Screen): if not current_box.is_back and get_current_ms() >= song.box.wait + (83.33*3): self.texture_index = current_box.texture_index - if ray.is_key_pressed(ray.KeyboardKey.KEY_ESCAPE): - logger.info("Escape key pressed, returning to ENTRY screen") + if ray.is_key_pressed(get_key_code(global_data.config["keys"]["back_key"])): + logger.info("Back key pressed, returning to ENTRY screen") return self.on_screen_end('ENTRY') def draw_background_diffs(self): diff --git a/uv.lock b/uv.lock index 7dcd5a8..0ce7f9f 100644 --- a/uv.lock +++ b/uv.lock @@ -340,6 +340,22 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/b3/30/177102e798539368aef25688a6a171d66ec92e6f16b6b651a89045a2bd13/pyinstrument-5.1.1-cp314-cp314t-win_amd64.whl", hash = "sha256:fa254f269a72a007b5d02c18cd4b67081e0efabbd33e18acdbd5e3be905afa06", size = 126528, upload-time = "2025-08-12T11:35:22.578Z" }, ] +[[package]] +name = "pyrefly" +version = "0.40.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/72/d3/5e3fe52f38099810054d486f84513133ec1cfa18e42d0e5ab935ab8c339e/pyrefly-0.40.1.tar.gz", hash = "sha256:9e7975292fbb64fdf69ee7f71b46c032eacdd6d71910103c012d6d46ff5bcd34", size = 3691680, upload-time = "2025-11-07T19:02:10.184Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/dc/08/0ac510399c601aa920d2b2d6d5cd7f7d8930c09dd20d6de18295da042460/pyrefly-0.40.1-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:1899722f7ae5fcd7d2ec74119289d04f14d97e9ad9d44dbb36725a6769b3a328", size = 9275616, upload-time = "2025-11-07T19:01:51.249Z" }, + { url = "https://files.pythonhosted.org/packages/4c/fc/6b0a4d48cdc7b3c2fc95f86a82c528db5d53fef6d69114c2325865e2e52f/pyrefly-0.40.1-py3-none-macosx_11_0_arm64.whl", hash = "sha256:c4e956ce758139c2d5357ec202aa93cbcb0102fc882160b5c51c526f80858ace", size = 8811737, upload-time = "2025-11-07T19:01:54.001Z" }, + { url = "https://files.pythonhosted.org/packages/da/9a/6f088a8dc4c37c2a7a01a2e2e2e3d3141c39ff2124cb0aa7b6fa08668ef3/pyrefly-0.40.1-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:435f3d757f127313a6accc941441fe2e5564a4d60e990daa815a58382a9551b3", size = 9032074, upload-time = "2025-11-07T19:01:56.428Z" }, + { url = "https://files.pythonhosted.org/packages/56/d5/141d15d52ef1d9905d8cf5f3118908a8dc00877271a5bc310a26f9b3a089/pyrefly-0.40.1-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:49aa72dbf47e0eb940443f81aa20cbdc1dee8fdedbedfa5defa45185cb75fd22", size = 9932653, upload-time = "2025-11-07T19:01:58.495Z" }, + { url = "https://files.pythonhosted.org/packages/da/05/36d0354f25d72d78612aadb9ee16a8e4c8d3ac08ed7e9107a22390494a4a/pyrefly-0.40.1-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a009c91ceb16e578c664c8e82b354249d63a316c4c951742608faac0aea37e99", size = 9566494, upload-time = "2025-11-07T19:02:00.715Z" }, + { url = "https://files.pythonhosted.org/packages/ef/d4/3b4329d101ab59e530ab1389c9f89e9e92cc8a449fc3bedaf316d7cbead9/pyrefly-0.40.1-py3-none-win32.whl", hash = "sha256:0540b4b68048d2b96208b0e60500125cc511360fc0179eaf010de3431fcca5f9", size = 9091751, upload-time = "2025-11-07T19:02:03.157Z" }, + { url = "https://files.pythonhosted.org/packages/46/30/006380355a1d02ee7f0c9e8519d2e50597ed5a7978474d2357100b82943e/pyrefly-0.40.1-py3-none-win_amd64.whl", hash = "sha256:6c66bb4f132ddf23812a299e490ee9d1209dcb72f02e6c770fc07f8c681e3089", size = 9556642, upload-time = "2025-11-07T19:02:05.62Z" }, + { url = "https://files.pythonhosted.org/packages/a7/c4/60de39397cc474ccbd154d5d24907f7caeb9bff1e5cac800f491bd65f2df/pyrefly-0.40.1-py3-none-win_arm64.whl", hash = "sha256:9e36eb9ba594e4b4f21432d807f8ab326de887f6586b1e6b6549558bcc65be20", size = 9107988, upload-time = "2025-11-07T19:02:08.114Z" }, +] + [[package]] name = "pytaiko" version = "0.9.0" @@ -354,6 +370,7 @@ dependencies = [ dev = [ { name = "nuitka" }, { name = "pyinstrument" }, + { name = "pyrefly" }, { name = "ruff" }, { name = "vulture" }, ] @@ -369,6 +386,7 @@ requires-dist = [ dev = [ { name = "nuitka", specifier = ">=2.8.4" }, { name = "pyinstrument", specifier = ">=5.1.1" }, + { name = "pyrefly", specifier = ">=0.40.1" }, { name = "ruff", specifier = ">=0.14.2" }, { name = "vulture", specifier = ">=2.14" }, ] @@ -406,6 +424,8 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/1f/84/61bb530fbb6a467551e147dfefd6ea11fa25dbd35fea65fa7854bc29fe92/raylib_sdl-5.5.0.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:245d6c32a8ad1833d4d37933d4d6067f7d919ebb3554609e6779154309c67c38", size = 2856661, upload-time = "2025-09-03T16:04:01.287Z" }, { url = "https://files.pythonhosted.org/packages/13/09/a67ec3441260a529f60b4738686575fa5ad5a3aa3f9f4bb45136b9abd737/raylib_sdl-5.5.0.3-cp313-cp313-win_amd64.whl", hash = "sha256:292962fd41759a9a149e4389588e7a38c3a6ec69eb50a88a3ea4ace76c9a1eed", size = 1630831, upload-time = "2025-09-03T16:04:03.369Z" }, { url = "https://files.pythonhosted.org/packages/72/74/6e567a13c02741c2604a7ca75bebf07403dae3323c8402e3064f28acd1cf/raylib_sdl-5.5.0.3-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:99a38716b6f60f96bd27cb2f8726161eb3295d305ae4634dfb9046ab758b9e30", size = 2197098, upload-time = "2025-09-03T16:04:05.667Z" }, + { url = "https://files.pythonhosted.org/packages/b2/38/6460ced11ba4bbf26588178dc366e414f2e3cf2c0eb17506095f4503a405/raylib_sdl-5.5.0.3-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:7a0563e45b9f2767a7a648c6dcf255ef67bf770f3c1634885605fa480b0c7b43", size = 2195980, upload-time = "2025-10-29T14:11:21.906Z" }, + { url = "https://files.pythonhosted.org/packages/79/4b/bdd7ddf420db78f2b741582881f4c7a6ec2c4dc2c5406ed7cddb88c03fc3/raylib_sdl-5.5.0.3-cp314-cp314-manylinux2014_aarch64.whl", hash = "sha256:ae85790f1da9472a02a9235239bd0da2763d4a06a171e03495630bfdd1615744", size = 2816550, upload-time = "2025-10-29T14:03:48.263Z" }, { url = "https://files.pythonhosted.org/packages/21/62/c842f623d9197488e16b1d72a2ba492ab9eed57a446eb93458c497313383/raylib_sdl-5.5.0.3-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:fdd57c75ca760ceceea12f25ae6e22df1b3f11b322257a9272bbf25dea0bac93", size = 2852329, upload-time = "2025-10-27T19:09:07.765Z" }, { url = "https://files.pythonhosted.org/packages/ea/a1/23464c0fbf8d3c75225023021ea10477e24dddc4bd0432bec0fb2f786f03/raylib_sdl-5.5.0.3-cp314-cp314-win_amd64.whl", hash = "sha256:f3333e14389e0ac653cb47ddb7405f07eb096749acd19c7a59a47cdac716b2b8", size = 1683742, upload-time = "2025-09-03T16:04:07.657Z" }, { url = "https://files.pythonhosted.org/packages/51/5f/83eba7bf283f13f3dd8b89bb170f8d7853064c7584c762aafbc500e57e98/raylib_sdl-5.5.0.3-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:3c0c0c6f2a94c1f84c1c7f716721f99e735a6f2de40be9be06a605fe4f4970eb", size = 1809538, upload-time = "2025-09-03T16:04:16.4Z" },