【项目复现】音效键盘SoundKeyboard的复现经验

作为写过点开源垃圾的学生,今天准备复现一款项目并尝试解析其中的代码。毕竟我太想进步了。

大家也可以试试复现我的一些垃圾:https://github.com/apcipotrain

源素材

我开发了按键盘就放音效的有声键盘,扣1笑面虎,扣2乌角鲨,扣Z键自刎归天_哔哩哔哩_bilibili

Github链接:https://github.com/PizzaDark/SoundKeyboard

下载

没想到卡住我的第一步,是下载!

原来"code"内部有玄机呀!

我们当然用git clone命令。

于是乎就下载好了,这是目前的文件夹。

复现

众所周知,一个项目最先看readme。

它提供了两套方法,那我们两套方法都操作一遍。

先操作方法二:(venv是virtual environment)

目前该路径就多出来了一个.venv的文件夹

现在运行python main.py:

这个键盘是出来了,但是呢,没有声音!这个问题下面再说。

接着我们用run.bat文件试试能不能达到相同的效果。

没有问题,依然是在后面我们逐步拆解这个bat文件在干什么。

配置音频

走到这里我的注意力也下滑了,操作也变难了,然后墨迹了很久。

(于是我决定写一个项目,给它我自己的路径,能够输出目录树,毕竟要被自己的效率气晕嘞)

一直走到这里,我发现github上的源代码没有音频,原来网盘分享的是带了音频的代码。

然后逐个导入,我发现还是太麻烦,视频上写的是exe文件拖进去。所以我又生成了exe文件,操作如下:

现在下载好了,在SoundKeyboard\dist文件夹下面出现了SoundKeyboard.exe文件。

回过头来看,原来是导入音效包,选中文件夹就可以了,不是选择mp3文件,他会自己配对键盘对应的文件。

现在敲键盘,这音效跟tm三国杀一样。

证明我成功了。

代码

rule.json

文件大致如下。

键名是键盘按键,值是一个对象,包含文件名和状态值两个数据。

run.bat

这里面的注释很详细

:: 第一步:检查 Python 3.10+ 环境

:: 第二步:检查 Git 环境

:: 第三步:创建虚拟环境

:: 第四步:激活虚拟环境

:: 第五步:安装依赖

main.py

这是一个1k行出头的文件。

主要模块、类、函数:

===================== Win32 常量与结构 =====================23-184行

class KEYBDINPUT(ctypes.Structure):

class HARDWAREINPUT(ctypes.Structure):

class MOUSEINPUT(ctypes.Structure):

class INPUT_UNION(ctypes.Union):

class INPUT(ctypes.Structure):

def _make_key_input(vk, flags=0):

"""构造一个键盘 INPUT 结构"""

def do_send_input(inputs):

"""发送一组 INPUT"""

def simulate_keys(key, modifier_keys=None, target_hwnd=None):

"""在子线程中:恢复目标窗口焦点 → 发送按键 → 完成"""

===================== 键名规范化 =====================185-243行

def _build_key_map():

def normalize_key(name, scan_code=None):

def get_resource_path(relative_path):

"""获取资源文件的绝对路径(兼容开发环境和PyInstaller打包后的环境)"""

class KeySignal(QObject):

===================== 音频处理 =====================244-287行

def make_reversed_sound(filepath):

def make_octave_down_sound(filepath):

===================== 音频引擎 =====================288-448行

class AudioEngine:

def init(self):

def load_pack(self, pack_dir, overwrite_rules=True):

def reload_sounds(self):

def save_rules(self):

def _get_sound(self, key):

def toggle_caps(self):

def toggle_shift(self):

def _delayed_space_pause(self):

def play_key(self, key):

def release_key(self, key):

def load_performance_key(self, filepath):

===================== 按键捕获对话框 =====================449-507行

class KeyCaptureDialog(QDialog):

def init(self, parent=None):

def keyPressEvent(self, e): pass

def keyReleaseEvent(self, e): pass

def showEvent(self, e):

def hideEvent(self, e):

def _on_key(self, e):

class ReadOnlyItem(QTableWidgetItem):

def init(self, text=""):

===================== 设置面板 =====================508-777行

class CustomSettingsUI(QWidget):

def init(self, parent_vkb):

def init_ui(self):

def update_theme(self, tc):

def mousePressEvent(self, e):

def mouseMoveEvent(self, e):

def mouseReleaseEvent(self, e):

def showEvent(self, e):

def hideEvent(self, e):

def _on_close(self):

def _collect(self):

def do_load_pack(self):

def toggle_perf(self, c):

def refresh_table(self):

def _ins(self, key, file, enabled):

def _del(self, w):

def _on_cell_dbl(self, row, col):

def add_row(self):

def open_rule_dir(self):

def do_save(self):

===================== 主界面 =====================778-1053行

class VirtualKeyboardApp(QWidget):

def init(self):

def _track_fg(self):

"""★ 记住最后一个非自身的前台窗口"""

def init_tray(self):

def init_ui(self):

def _toggle_mod(self, mod, checked):

def _update_mod_styles(self):

def _vk_press(self, key):

def _vk_release(self, key):

def _style_btn(self, btn, active):

def _update_indicators(self):

def apply_styles(self):

def update_scale(self, sz):

def update_opacity(self, v):

def change_theme(self, idx):

def open_settings(self):

def toggle_vis(self):

def quit_app(self):

def mousePressEvent(self, e):

def mouseMoveEvent(self, e):

def mouseReleaseEvent(self, e):

def start_keyboard_hook(self):

def _cleanup_stuck(self):

def on_key_pressed(self, key):

def on_key_released(self, key):

主函数

python 复制代码
if __name__ == '__main__':
    QApplication.setAttribute(Qt.AA_EnableHighDpiScaling, True)
    QApplication.setAttribute(Qt.AA_UseHighDpiPixmaps, True)
    app = QApplication(sys.argv)
    QApplication.setQuitOnLastWindowClosed(False)
    window = VirtualKeyboardApp()
    window.show()
    sys.exit(app.exec_())

AI的分析

我的疑惑

build.spec

后记

1.我走过了各种路的全流程,手动进行了命令行操作,用了bat命令,最后还打包成了exe进行操作。

2.卡住我的最大的坑是音效问题,原来是选中文件夹,导入进去就行了。

3.(于是我决定写一个项目,给它我自己的路径,能够输出目录树,毕竟要被自己的效率气晕嘞)

这个坑我马上填,尽量明天写完。

4.我还可以考虑出一个周杰伦音效包和原神音效包。但是这个就是纯做mp3,而不是做项目文件了。

相关推荐
苏州福兰克2 天前
没有3D内容,裸眼3D显示器还能用吗?
3d·计算机外设
豪气的程序猿2 天前
Windows 11 外接键盘偶尔漏键?用键盘小鹿练习前先做双设备对照
计算机外设·电脑
苏州福兰克3 天前
长期看裸眼3D显示器容易视觉疲劳吗?
3d·计算机外设
苏州福兰克3 天前
商用裸眼3D显示器和家用款主要差别在哪里?
3d·计算机外设
Rudon滨海渔村3 天前
台式机Win10实现“音量+”和“音量-”,键盘映射方案
windows·计算机外设·powertoys
万化冥合4 天前
PyBox屏幕键盘如何辅助演示键盘操作?
python·计算机外设
豪气的程序猿4 天前
Windows 练字时空格键偶尔没反应?先排查焦点和键盘,再用键盘小鹿练习
计算机外设·电脑
晚风叙码5 天前
Linux 进程概念(上):从冯诺依曼到进程调度
linux·运维·计算机外设
科技每日热闻5 天前
爱攻AGON亮相2026核聚变游戏嘉年华北京站,创新科技点燃高能电竞热潮!
科技·计算机外设
沃普天科技6 天前
100W 氮化镓充电器充电头扩展坞一体化设计,实用性翻倍
驱动开发·计算机外设·音视频·硬件工程·pcb工艺