Task configuration:
{"task_id": "14", "task_name": "set_hotkey", "description": "Set hotkey to trigger recording", "application_info": {"name": "obs-studio", "executable_path": "/workspace/PC-Canary/apps/obs-studio/build_ubuntu/rundir/Debug/bin/obs", "args": []}, "task_parameters": {"hotkey": {"control": true, "key": "OBS_KEY_R"}}, "instruction_template": "Please set the shortcut key for starting and ending recording in OBS to ${hotkey}, and test the shortcut key by triggering it", "evaluation_setup": {"scripts": [{"role": "hook", "path": "hooker.js"}, {"role": "handler", "path": "handler.py"}], "timeout": 180}, "preconditions": {"obs_studio_running": true}, "total_key_steps": 3, "events": {"set_hotkey_success": {"description": "Hotkey set successfully", "is_key_step": true, "key_step_index": 1, "key_step_name": "Hotkey set successfully"}, "found_success": {"description": "Hotkey found in configuration file", "is_key_step": true, "key_step_index": 2, "key_step_name": "Hotkey found in configuration file"}, "hotkey_press": {"description": "Hotkey triggered", "is_key_step": true, "key_step_index": 3, "key_step_name": "Hotkey triggered"}}, "mcp_servers": [{"command": "node", "args": ["/home/agent/obs-mcp/build/index.js"]}]}

Hook script:
(function () {
    // Script settings
    const EVENT_ON_ENTER = "function called";
    const EVENT_ON_LEAVE = "function returned";

    const MESSAGE_called = "Intercepted function call";
    const MESSAGE_returned = "Function returned";
    const MESSAGE_script_initialized = "Monitoring script has started";
    const MESSAGE_hook_installed = "Monitoring hook installed, waiting for operation...";

    // Send events to the evaluation system
    function sendEvent(eventType, data = {}) {
        const payload = {
            event: eventType,
            ...data,
            timestamp: new Date().getTime()
        };
        send(payload);
    }

    // Get function address
    function getFunctionAddress(functionName) {
        const funcAddr = DebugSymbol.getFunctionByName(functionName);
        if (!funcAddr) {
            sendEvent("error", {
                error_type: "function_not_found",
                message: `Cannot find function ${functionName}`
            });
            return null;
        }

        sendEvent("function_found", {
            address: funcAddr.toString(),
            message: `Found the actual address of function ${functionName}`
        });
        return funcAddr;
    }

    // Initialize recording update hooks
    function hook() {
        let function_name = "create_binding";
        let symbol_name = "create_binding";

        Interceptor.attach(getFunctionAddress(function_name), {
            onEnter(args) {
                sendEvent(EVENT_ON_ENTER, {
                    message: MESSAGE_called,
                    function: function_name,
                    symbol: symbol_name
                });
                const name = args[0].add(8).readPointer().readCString(-1);
                this.name = name;
                console.log(name);
            },

            onLeave(retval) {
                sendEvent(EVENT_ON_LEAVE, {
                    message: MESSAGE_returned,
                    function: function_name,
                    symbol: symbol_name
                });
                sendEvent("set_hotkey_success", {
                    message: "Create new hotkey completed",
                    name: this.name
                });
            }
        });
    }

    function hook_obs_save_hotkey() {
        const function_name = "OBSBasicSettings::SaveSettings";
        const symbol_name = "_ZN16OBSBasicSettings12SaveSettingsEv";

        Interceptor.attach(getFunctionAddress(symbol_name), {
            onEnter(args) {
                sendEvent(EVENT_ON_ENTER, {
                    message: MESSAGE_called,
                    function: function_name,
                    symbol: symbol_name
                });
                const main_offset = 0x28;
                const main = args[0].add(main_offset).readPointer();
                const getConfigAddr = getFunctionAddress("_ZNK8OBSBasic6ConfigEv");
                const getConfig = new NativeFunction(getConfigAddr, 'pointer', ['pointer']);
                const config_ptr = getConfig(main);
                const file_name = config_ptr.readPointer().readCString(-1);
                this.file = file_name;
            },

            onLeave(retval) {
                sendEvent(EVENT_ON_LEAVE, {
                    message: MESSAGE_returned,
                    function: function_name,
                    symbol: symbol_name
                });
                sendEvent("save_success", {
                    message: "Configuration file saved",
                    file: this.file
                });
            }
        });
    }

    function hook_obs_hotkey_press() {
        const function_name = "obs_hotkey_pair_first_func";
        const symbol_name = "obs_hotkey_pair_first_func";
        Interceptor.attach(getFunctionAddress(symbol_name), {
            onEnter(args) {
                sendEvent(EVENT_ON_ENTER, {
                    message: MESSAGE_called,
                    function: function_name,
                    symbol: symbol_name
                });
                const name_offset = 0x8;
                const name = args[2].add(name_offset).readPointer().readCString(-1);
                this.name = name;
                this.pressed = args[3];
            },

            onLeave(retval) {
                sendEvent(EVENT_ON_LEAVE, {
                    message: MESSAGE_returned,
                    function: function_name,
                    symbol: symbol_name
                });
                console.log(this.pressed);
                sendEvent("hotkey_press", {
                    message: "Hotkey triggered",
                    name: this.name,
                    pressed: this.pressed == 0x1 ? "true" : "false"
                });
            }
        });
    }

    function init_hotkey_inject() {
        Interceptor.attach(getFunctionAddress("inject_hotkey"), {
            onEnter(args) {
                this.binding = args[2];
            },
            onLeave(retval) {
                const obs_hotkey_binding_get_hotkey = new NativeFunction(
                    getFunctionAddress("obs_hotkey_binding_get_hotkey"),
                    'pointer', ['pointer']
                );
                const obs_hotkey_get_name = new NativeFunction(
                    getFunctionAddress("obs_hotkey_get_name"),
                    'pointer', ['pointer']
                );
                const hotkey = obs_hotkey_binding_get_hotkey(this.binding);
                const name = obs_hotkey_get_name(hotkey).readCString();
                console.log(name);
                const pressed = this.binding.add(8).readU8();
                console.log(pressed);
                sendEvent("inject_hotkey", {
                    message: "Hotkey triggered",
                    name: name,
                    pressed: pressed == 0x1 ? "true" : "false"
                });
            }
        });
    }

    // Initialize hooks
    function initHook() {
        sendEvent("script_initialized", {
            message: MESSAGE_script_initialized
        });

        // Initialize individual hooks
        hook();
        hook_obs_save_hotkey();
        hook_obs_hotkey_press();
        init_hotkey_inject();
        sendEvent("hook_installed", {
            message: MESSAGE_hook_installed
        });
    }

    // Start script
    initHook();
})();

Evaluation handler:
#!/usr/bin/env python3
# -*- coding: utf-8 -*-

from typing import Dict, Any, Optional, List

step = 0


def message_handler(
    message: Dict[str, Any], logger, task_parameter: Dict[str, Any]
) -> Optional[List[Dict[str, Any]]]:
    global step
    payload = message["payload"]
    event_type = payload["event"]
    logger.debug(f"Received event: {event_type}")
    if event_type == "hotkey_press":
        name = payload.get("name", "")
        if name == "OBSBasic.StartRecording":
            if step == 2:
                return [
                    {"status": "key_step", "index": 3},
                    {
                        "status": "success",
                        "reason": "Successfully found the hotkey and triggered the test completion",
                    },
                ]

    elif event_type == "inject_hotkey":
        name = payload.get("name", "")
        if name == "OBSBasic.StartRecording":
            if step == 2:
                return [
                    {"status": "key_step", "index": 3},
                    {
                        "status": "success",
                        "reason": "Successfully found the hotkey and triggered the test completion",
                    },
                ]

    elif event_type == "set_hotkey_success":
        name = payload.get("name", "")
        print("set_hotkey_success: " + name)
        if name == "OBSBasic.StartRecording" or name == "OBSBasic.StopRecording":
            if step == 0:
                step = 1
                return [
                    {"status": "key_step", "index": 1},
                ]

    elif event_type == "save_success":
        file_path = payload.get("file", "")
        if not file_path:
            logger.error("Failed to get the configuration file path")
            return None
        logger.info(f"Configuration file path: {file_path}")

        try:
            import configparser

            config = configparser.ConfigParser()
            config.read(file_path)

            if not config.has_section("Hotkeys"):
                return [
                    {
                        "status": "error",
                        "reason": "script_error",
                        "message": "No hotkey configuration found in the configuration file",
                    },
                ]

            start_recording = config.get(
                "Hotkeys", "OBSBasic.StartRecording", fallback=""
            )
            stop_recording = config.get(
                "Hotkeys", "OBSBasic.StopRecording", fallback=""
            )

            if not start_recording or not stop_recording:
                return [
                    {
                        "status": "error",
                        "reason": "script_error",
                        "message": "No recording-related hotkey configuration found",
                    },
                ]

            import json

            start_bindings = json.loads(start_recording).get("bindings", [])
            stop_bindings = json.loads(stop_recording).get("bindings", [])

            if not start_bindings or not stop_bindings:
                return [
                    {
                        "status": "error",
                        "reason": "script_error",
                        "message": "Recording hotkey not bound",
                    },
                ]

            start_key = start_bindings[0]
            stop_key = stop_bindings[0]
            expected_key = task_parameter.get("hotkey", {})

            if start_key == expected_key and stop_key == expected_key:
                if step == 1:
                    step = 2
                    return [{"status": "key_step", "index": 2}]
            else:
                return [
                    {
                        "status": "error",
                        "reason": "script_error",
                        "message": "Incorrect hotkey configuration",
                    },
                ]

        except Exception as e:
            return [
                {
                    "status": "error",
                    "reason": "script_error",
                    "message": f"Error verifying hotkey configuration: {str(e)}",
                },
            ]

    return None