Skip to content

Restore stable F11 KeyChanger toggle behavior; add LiveSplit docs; introduce configurable checkpoint voice prompts#10

Draft
Copilot wants to merge 3 commits into
masterfrom
copilot/restore-f11-keychanger-behavior
Draft

Restore stable F11 KeyChanger toggle behavior; add LiveSplit docs; introduce configurable checkpoint voice prompts#10
Copilot wants to merge 3 commits into
masterfrom
copilot/restore-f11-keychanger-behavior

Conversation

Copy link
Copy Markdown

Copilot AI commented Apr 18, 2026

This PR addresses three requested items: revert the F11 KeyChanger regression to legacy behavior (toggle only, no process restart), add LiveSplit-focused documentation under docs/, and add configurable checkpoint voice prompts (checkpoint/faster/slower) with external mp3/wav support.

  • F11 KeyChanger behavior regression fix (Pal98Timer/GForm.cs)

    • Reverted F11 handling to legacy semantics:
      • Disable() / Enable() only
      • removed Close() on disable and Open()+wait on enable
    • Keeps KeyChanger process lifecycle independent from F11 toggling, matching the known-good historical behavior.
  • Checkpoint voice prompt feature (new Pal98Timer/VoicePrompt.cs + TimerCore integration)

    • Added VoicePrompt static service with:
      • PlaySound(string filePath)
      • PlayCheckpointSound(string checkpointName)
      • PlayFasterSound()
      • PlaySlowerSound()
    • Added voice_config.txt-based configuration loading:
      • enable switch
      • faster/slower sound paths
      • per-checkpoint sound mapping (checkpoint.<name>=... / cp.<name>=...)
    • Integrated into checkpoint trigger flow in TimerCore.Checking():
      • play checkpoint sound on checkpoint hit
      • play faster/slower prompt by checkpoint delta sign
    • Uses mciSendString (no external dependency) and supports both sounds/ and voice/ directories.
    • Added basic path/file-type hardening for playback command input (.mp3/.wav only).
  • Project wiring

    • Included VoicePrompt.cs in Pal98Timer.csproj.
  • Documentation additions (docs/)

    • docs/livesplit_pal98_kb.md
      • LiveSplit overview and repo link
      • LiveSplit vs PalTimer framing
      • ASL autosplitter structure and callback examples (state/start/split/reset/isLoading)
      • PAL98 DX9 memory-reading strategy notes
      • LiveSplit Server and external communication direction
      • layout/component customization notes
    • docs/TODO_PLAN.md
      • Added/updated roadmap items aligned with LiveSplit ecosystem integration and voice prompt evolution.
case Keys.F11:
    if (hookStruct.flags >= 128)
    {
        if (KeyChangerDel.IsEnable()) KeyChangerDel.Disable();
        else KeyChangerDel.Enable();
        ShowKCEnable();
        core.OnFunctionKey(11);
    }
    handle = core.NeedBlockFunctionKey(11);
    break;
Original prompt

本PR需要处理三个任务:

任务1:恢复F11 KeyChanger的老版本行为(只禁用不杀进程)

当前 master 分支 Pal98Timer/GForm.cs 中 F11 的处理逻辑是:禁用改键时调用 KeyChangerDel.Close() 杀掉 keychanger.exe 进程,启用时调用 KeyChangerDel.Open() 重新启动进程。这导致 F11 有时不能让 keychanger.exe 正常出现。

需要恢复为 commit 286f7cf4fae11fcaa7762b551b354cc88eac76b5 的做法:F11只切换 Enable/Disable 状态,不杀掉也不重启进程。

当前代码(需要修改)在 Pal98Timer/GForm.cs 约第544-568行

case Keys.F11:
    if (hookStruct.flags >= 128)
    {
        if (KeyChangerDel.IsEnable())
        {
            KeyChangerDel.Disable();
            ShowKCEnable();
            KeyChangerDel.Close();  // 要删掉这个
        }
        else
        {
            Run(delegate() {
                KeyChangerDel.Open();  // 要删掉这些
                for (int i = 0; i < 30 && !KeyChangerDel.IsWindowOpen(); i++)
                {
                    System.Threading.Thread.Sleep(100);
                }
                KeyChangerDel.Enable();
                UI(delegate() { ShowKCEnable(); });
            });
        }
        core.OnFunctionKey(11);
    }

需要恢复为老版本的简洁逻辑

case Keys.F11:
    if (hookStruct.flags >= 128)
    {
        if (KeyChangerDel.IsEnable())
        {
            KeyChangerDel.Disable();
        }
        else
        {
            KeyChangerDel.Enable();
        }
        ShowKCEnable();
        core.OnFunctionKey(11);
    }
    handle = core.NeedBlockFunctionKey(11);
    break;

任务2:在 docs 目录下生成 LiveSplit 知识库文件和 TODO_PLAN

在项目根目录创建 docs/ 目录(如果不存在),并生成以下文件:

2a. docs/livesplit_pal98_kb.md — LiveSplit 与仙剑98 DX9 的知识库

内容应包含:

  • LiveSplit 简介(著名开源计时器,GitHub: https://github.com/LiveSplit/LiveSplit)
  • LiveSplit 与 PalTimer 的对比
  • 如何通过 LiveSplit 的 Auto Splitter(ASL脚本)支持仙剑98 DX9
  • ASL 脚本基本结构示例(state, start, split, reset, isLoading 等回调)
  • 仙剑98 DX9 的内存地址读取思路(可参考 PalTimer 现有的内存读取逻辑)
  • LiveSplit Server 组件和 WebSocket 通信方式
  • 自定义 Layout 和组件配置

2b. docs/TODO_PLAN.md — 未来可加入的功能规划

列出可以从 LiveSplit 生态借鉴或集成的功能,例如:

  • 支持 LiveSplit 的 .lss(LiveSplit Splits)格式导入导出
  • 支持 LiveSplit Server 协议通信,使 PalTimer 可以作为 LiveSplit 的数据源
  • 实现 ASL(Auto Split Language)兼容层,复用 LiveSplit 社区已有的 Auto Splitter 脚本
  • 支持 Sum of Best Segments 计算
  • 支持 Delta 显示(对比最佳/平均的时间差)
  • 支持多种比较方式(Personal Best, Average, Median, Best Segments 等)
  • 支持 Subsplits(子节点分组)
  • 节点语音提示功能(见任务3)
  • 支持通过 WebSocket/HTTP 暴露实时计时数据给 OBS 等工具
  • 支持回放(Run History)统计和图表
  • 支持自定义主题/皮肤导入

任务3:节点语音提示功能设计与实现

在项目中加入节点语音提示功能。具体需求:

  1. 当节点触发时播放语音提示:到达某个检查点(checkpoint)时,播放对应的提示音。
  2. 支持自定义 mp3/wav 文件:用户可以在一个目录(如 sounds/voice/)下放置自己的 mp3 或 wav 文件。
  3. 节点快慢语音提示
    • 如果当前节点比最佳时间慢了,播放"慢了"的语音(如 sounds/slower.mp3 或用户自定义文件)
    • 如果当前节点比最佳时间快了,播放"快了"的语音(如 sounds/faster.mp3 或用户自定义文件)
    • 节点到达时也可播放节点名称对应的语音(如 sounds/节点��.mp3
  4. 配置方式:可以通过一个配置文件(如 voice_config.txt)来配置:
    • 是否启用语音提示
    • 快了/慢了的音频文件路径
    • 各节点对应的自定义音频文件路径
  5. 实现方式:在 C# 中可以使用 System.Media.SoundPlayer(仅支持 wav)或引用 NAudio 等库来播放 mp3。考虑到简单性和不增加外部依赖,可以先用 Windows API mciSendString 来播放 mp3/wav,这在 WinForms 中很常见。

Pal98Timer 项目中创建一个新的 VoicePrompt.cs 类,提供:

  • PlaySound(string filePath) — 播放音频文件
  • PlayCheckpointSound(string checkpointName) — 播放节点到达提示
  • PlayFasterSound() / PlaySlowerSound() — 播放快了/慢了提示
  • TimerCore 或检查点切换逻辑中集成调用

同时在 docs/TODO_PLAN.md 中也要体现语音提示功能的规划。

The following is the prior conversation context from the user's chat exploration (may be truncated):

User: 目前主分支是最新代码,现在有三个事情要处理:1. 最新代码当中,按F11有时候不能让keychanger.exe正常出现,所以keychanger的改键就失效。但是commit 286f7cf 是正常的,所以要对比看看是怎么回事。如果区别是新版变成要杀掉keychanger.exe进程而老版本只是禁用不是杀掉进程,那可以恢复老版本的做法。2. livesplit也是很著名的开源计时器,而且也能通过修改插件支持仙剑98DX9,可以帮忙生成docs下的kb文件作为知识库,并且列一个TODO_PLAN,表示可以加入一些功能的。3. 节点加入语音提示,并且可以自己定义mp3/wav,如果这个节点慢或者快了,就可以有节点慢或者快的语音播放,然后这个语音播放最好是外部的mp3放自己想要的提示语音。

Assistant: Now let me get the old version's F11 handling in GForm.cs and compare with the current version:

Assistant: 我已经完成了对比分析,现在来汇总三个任务的结果,并创建一个 PR 来处理所有问题。

任务1分析:F11 KeyChanger 问题

对比 commit 286f7cf4 和当前 master 的 F11 处理逻辑,确认了你的猜测

老版本 (286f7cf) — 只是切换 Enable/Disable,不杀进程:

case Keys.F11:
    if (hookStruct.flags >= 128)
    {
        if (KeyChangerDel.IsEnable())
        {
            KeyChangerDel.Disable();  // 只是发消息禁用
        }
        else
        {
            KeyChangerDel.Enable();   // 只是发消息启用
        }
        ShowKCEnable();
        core.OnFunctionKey(11);
    }

新版本 (master) — 禁用时杀掉进程,启用时重新启动进程:

case Keys.F11:
    if (hookStruct.flags >= 128)
    {
        if (KeyChangerDel.IsEnable())
        {
            KeyChangerDel.Disable();
            ShowKCEnable();
            KeyChangerDel.Close();    // 杀掉进程!
        }
        else
        {
            Run(delegate() {
                KeyChangerDel.Open(); // 重新启动进程
                for (int i = 0; i < 30 && !KeyChangerDel.IsWindowOpen(); i++)
                {
               ...

</details>



<!-- START COPILOT CODING AGENT SUFFIX -->

*This pull request was created from Copilot chat.*
>

Copilot AI changed the title [WIP] Restore old F11 KeyChanger behavior to disable without killing process Restore stable F11 KeyChanger toggle behavior; add LiveSplit docs; introduce configurable checkpoint voice prompts Apr 18, 2026
Copilot AI requested a review from othercat April 18, 2026 15:55
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants