利用鼠标钩子将鼠标中键转为左键

鼠标中键转左键
本文介绍了一种解决鼠标左键失灵的方法,通过使用鼠标钩子技术将中键信号转换为左键信号,实现了无需硬件更换即可修复的目的。
部署运行你感兴趣的模型镜像
   利用鼠标钩子将鼠标中键转为左键

 鼠标的左键由于使用的多,容易损坏,我用的一个微软鼠标左键就出现了问题,点击左键没有响应了.把鼠标拆开后,也没发现什么物理性的损伤.按键还是那么 清脆,但就是没反应.网上有说可以将中键取下来换到左键上,但是,需要用电焊,按键底下的接口是与线路板焊在一起的,这可没办法了,总不能再去买个焊枪.
    硬的不行,就只有来软的了.通过截获鼠标按键消息,将中键的消息转换为左键消息发出去,实现中键转左键的功能.要实现这个功能,只能通过挂载鼠标构子函 数SetWindowsHookEx,在处理完中键转换任务后,一定要记着调用CallNextHookEx函数,将鼠标消息传下去,不然,鼠标可就动不 了了. 下面是实现的代码.
MouseHookWin32.cs代码文件:
using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;

namespace QingMouseHook
{
    public class MouseHookWin32
    {
        // wParam对应码

        public const int WM_LBUTTONDOWN = 0x201;
        public const int WM_MBUTTONDOWN = 0x207;
        public const int WM_LBUTTONUP = 0x202;
        public const int WM_MBUTTONUP = 0x208;

        // mouse_event消息码

        public const int MOUSEEVENTF_LEFTDOWN = 0x0002;
        public const int MOUSEEVENTF_LEFTUP = 0x0004;
        public const int MOUSEEVENTF_MIDDLEDOWN = 0x0020;
        public const int MOUSEEVENTF_MIDDLEUP = 0x0040;

        public const int WH_MOUSE_LL = 14; // 表示鼠标钩子


        public delegate int MouseHookHandler(int nCode, Int32 wParam, IntPtr lParam);

        // 设置钩子函数

        [DllImport("user32.dll ", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
        public static extern int SetWindowsHookEx(int idHook, MouseHookHandler lpfn, IntPtr hInstance, int threadId);

        // 卸载钩子函数

        [DllImport("user32.dll ", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
        public static extern bool UnhookWindowsHookEx(int idHook);

        // 调用下一个钩子函数

        [DllImport("user32.dll ", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
        public static extern int CallNextHookEx(int idHook, int nCode, Int32 wParam, IntPtr lParam);

        // 获取最后的错误

        [DllImport("kernel32", EntryPoint = "GetLastError")]
        public static extern int GetLastError();

        [DllImport("user32")]
        public static extern int mouse_event(int dwFlags, int dx, int dy, int cButtons, int dwExtraInfo);
    }
}
 MouseHook.cs代码文件,具体实现转换功能:
using System;
using System.Collections.Generic;
using System.Text;
using System.Reflection;
using System.Runtime.InteropServices;

namespace QingMouseHook
{
    public class MouseHook
    {
        private static int hwndMouseHook = 0; // 加载鼠标钩子后的句柄

        
        /// <summary>

        /// 装载鼠标钩子

        /// </summary>

        public void SetHook()
        {
            if (hwndMouseHook == 0)
            {
                MouseHookWin32.MouseHookHandler handler = new MouseHookWin32.MouseHookHandler(this.HookHandle);
                hwndMouseHook = MouseHookWin32.SetWindowsHookEx(MouseHookWin32.WH_MOUSE_LL,
                    handler, Marshal.GetHINSTANCE(Assembly.GetExecutingAssembly().GetModules()[0]), 0);

                if (hwndMouseHook == 0)
                {
                    this.UnHook();

                    int errno = MouseHookWin32.GetLastError();
                    throw new Exception(errno.ToString());
                }
            }
        }

        /// <summary>

        /// 卸载鼠标钩子

        /// </summary>

        public void UnHook()
        {
            if (hwndMouseHook == 0) return;

            bool isSuc = MouseHookWin32.UnhookWindowsHookEx(hwndMouseHook);
            if (!isSuc) throw new Exception("卸载鼠标钩子失败");
        }

        /// <summary>

        /// 处理钩子中的鼠标消息,发送鼠标模拟按键

        /// </summary>

        private int HookHandle(int nCode, int wParam, IntPtr lParam)
        {
            switch (wParam)
            {
                case MouseHookWin32.WM_MBUTTONDOWN :
                    MouseHookWin32.mouse_event(MouseHookWin32.MOUSEEVENTF_LEFTDOWN, 0, 0, 0, 0);
                    break;
                case MouseHookWin32.WM_MBUTTONUP :
                    MouseHookWin32.mouse_event(MouseHookWin32.MOUSEEVENTF_LEFTUP, 0, 0, 0, 0);
                    break;
            }

            // 调用下一个钩子

            return MouseHookWin32.CallNextHookEx(hwndMouseHook, nCode, wParam, lParam);
        }
    }
}
 在调用程序的代码中,只要调用MouseHook的SetHook即可装载鼠标钩子,UnHook卸载钩子.

您可能感兴趣的与本文相关的镜像

Stable-Diffusion-3.5

Stable-Diffusion-3.5

图片生成
Stable-Diffusion

Stable Diffusion 3.5 (SD 3.5) 是由 Stability AI 推出的新一代文本到图像生成模型,相比 3.0 版本,它提升了图像质量、运行速度和硬件效率

import os import json import time import random import threading import datetime import pyautogui import keyboard from tkinter import * from tkinter import ttk, messagebox, filedialog from tkinter.font import Font class ActionRecorder: def __init__(self): self.recording = False self.playing = False self.actions = [] self.current_config = { "random_interval": 100, "loop_times": 1, "script_name": "未命名脚本" } self.configs = {} self.load_configs() # 创建日志目录 if not os.path.exists("logs"): os.makedirs("logs") # 初始化GUI self.init_gui() # 设置快捷键 self.setup_hotkeys() # 鼠标和键盘状态跟踪 self.mouse_state = { "left": False, "right": False, "middle": False } self.keyboard_state = {} # 鼠标和键盘监听器 self.keyboard_hook = None self.mouse_hook = None # 忽略的按键 self.ignored_keys = {'f1', 'f2'} def init_gui(self): self.root = Tk() self.root.title("动作录制器 v3.3") self.root.geometry("800x700") # 设置字体 bold_font = Font(family="微软雅黑", size=10, weight="bold") normal_font = Font(family="微软雅黑", size=9) # 配置区域 config_frame = LabelFrame(self.root, text="配置", padx=10, pady=10, font=bold_font) config_frame.pack(fill="x", padx=10, pady=5) # 脚本名称 Label(config_frame, text="脚本名称:", font=normal_font).grid(row=0, column=0, sticky="e", pady=5) self.script_name_entry = Entry(config_frame, font=normal_font) self.script_name_entry.grid(row=0, column=1, sticky="we", padx=5, pady=5) self.script_name_entry.insert(0, self.current_config["script_name"]) # 随机间隔 Label(config_frame, text="随机间隔(ms):", font=normal_font).grid(row=1, column=0, sticky="e", pady=5) self.interval_entry = Entry(config_frame, font=normal_font) self.interval_entry.grid(row=1, column=1, sticky="we", padx=5, pady=5) self.interval_entry.insert(0, str(self.current_config["random_interval"])) # 循环次数 Label(config_frame, text="循环次数:", font=normal_font).grid(row=2, column=0, sticky="e", pady=5) self.loop_entry = Entry(config_frame, font=normal_font) self.loop_entry.grid(row=2, column=1, sticky="we", padx=5, pady=5) self.loop_entry.insert(0, str(self.current_config["loop_times"])) # 按钮区域 button_frame = Frame(self.root) button_frame.pack(fill="x", padx=10, pady=10) self.record_btn = Button(button_frame, text="开始/停止录制 (F1)", command=self.toggle_recording, font=bold_font, bg="#4CAF50", fg="white") self.record_btn.pack(side="left", padx=5, ipadx=10, ipady=5) self.play_btn = Button(button_frame, text="开始/停止执行 (F2)", command=self.toggle_playing, font=bold_font, bg="#2196F3", fg="white") self.play_btn.pack(side="left", padx=5, ipadx=10, ipady=5) self.save_btn = Button(button_frame, text="保存脚本", command=self.save_script, font=bold_font, bg="#9C27B0", fg="white") self.save_btn.pack(side="right", padx=5, ipadx=10, ipady=5) self.delete_btn = Button(button_frame, text="删除脚本", command=self.delete_script, font=bold_font, bg="#607D8B", fg="white") self.delete_btn.pack(side="right", padx=5, ipadx=10, ipady=5) # 主内容区域 main_frame = Frame(self.root) main_frame.pack(fill="both", expand=True, padx=10, pady=5) # 脚本列表 script_frame = LabelFrame(main_frame, text="保存的脚本", padx=10, pady=10, font=bold_font) script_frame.pack(side="left", fill="y", padx=5, pady=5) self.script_listbox = Listbox(script_frame, font=normal_font, width=25, height=15) self.script_listbox.pack(fill="both", expand=True, padx=5, pady=5) self.script_listbox.bind("<Double-Button-1>", self.load_script) # 日志区域 log_frame = LabelFrame(main_frame, text="操作日志", padx=10, pady=10, font=bold_font) log_frame.pack(side="right", fill="both", expand=True, padx=5, pady=5) self.log_text = Text(log_frame, font=normal_font, wrap=WORD) scrollbar = Scrollbar(log_frame, command=self.log_text.yview) self.log_text.configure(yscrollcommand=scrollbar.set) scrollbar.pack(side="right", fill="y") self.log_text.pack(fill="both", expand=True, padx=5, pady=5) # 状态栏 self.status_var = StringVar() self.status_var.set("就绪") status_bar = Label(self.root, textvariable=self.status_var, bd=1, relief=SUNKEN, anchor=W, font=normal_font) status_bar.pack(fill="x", padx=10, pady=5) # 更新脚本列表 self.update_script_list() def setup_hotkeys(self): keyboard.add_hotkey('f1', self.toggle_recording, suppress=True) keyboard.add_hotkey('f2', self.toggle_playing, suppress=True) def toggle_recording(self): if self.recording: self.stop_recording() else: self.start_recording() def toggle_playing(self): if self.playing: self.stop_playing() else: self.start_playing() def log_message(self, message): timestamp = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S") log_entry = f"[{timestamp}] {message}\n" self.log_text.insert(END, log_entry) self.log_text.see(END) self.status_var.set(message) # 写入日志文件 today = datetime.datetime.now().strftime("%Y-%m-%d") log_file = f"logs/{today}.log" with open(log_file, "a", encoding="utf-8") as f: f.write(log_entry) def save_configs(self): with open("configs.json", "w", encoding="utf-8") as f: json.dump(self.configs, f, ensure_ascii=False, indent=2) def load_configs(self): try: if os.path.exists("configs.json"): with open("configs.json", "r", encoding="utf-8") as f: self.configs = json.load(f) except Exception as e: self.log_message(f"加载配置失败: {str(e)}") self.configs = {} def update_current_config(self): try: self.current_config["script_name"] = self.script_name_entry.get() self.current_config["random_interval"] = int(self.interval_entry.get()) self.current_config["loop_times"] = int(self.loop_entry.get()) return True except ValueError: messagebox.showerror("错误", "请输入有效的数字") return False def save_script(self): if not self.update_current_config(): return if not self.actions: messagebox.showwarning("警告", "没有录制的动作可以保存") return script_name = self.current_config["script_name"] self.configs[script_name] = { "config": self.current_config, "actions": self.actions } self.save_configs() self.update_script_list() self.log_message(f"脚本 '{script_name}' 已保存") def delete_script(self): selection = self.script_listbox.curselection() if not selection: messagebox.showwarning("警告", "请先选择一个脚本") return script_name = self.script_listbox.get(selection[0]) if messagebox.askyesno("确认", f"确定要删除脚本 '{script_name}' 吗?"): if script_name in self.configs: del self.configs[script_name] self.save_configs() self.update_script_list() self.log_message(f"脚本 '{script_name}' 已删除") def update_script_list(self): self.script_listbox.delete(0, END) for script_name in sorted(self.configs.keys()): self.script_listbox.insert(END, script_name) def load_script(self, event=None): selection = self.script_listbox.curselection() if not selection: return script_name = self.script_listbox.get(selection[0]) if script_name in self.configs: script_data = self.configs[script_name] self.current_config = script_data["config"] self.actions = script_data["actions"] # 更新UI self.script_name_entry.delete(0, END) self.script_name_entry.insert(0, self.current_config["script_name"]) self.interval_entry.delete(0, END) self.interval_entry.insert(0, str(self.current_config["random_interval"])) self.loop_entry.delete(0, END) self.loop_entry.insert(0, str(self.current_config["loop_times"])) self.log_message(f"已加载脚本 '{script_name}'") self.log_message(f"共 {len(self.actions)} 个动作") def start_recording(self): if self.recording or self.playing: return if not self.update_current_config(): return self.recording = True self.actions = [] self.record_btn.config(bg="#F44336", text="停止录制 (F1)") self.play_btn.config(state=DISABLED) self.save_btn.config(state=DISABLED) self.delete_btn.config(state=DISABLED) # 重置鼠标和键盘状态 self.mouse_state = { "left": False, "right": False, "middle": False } self.keyboard_state = {} # 设置键盘和鼠标钩子 self.keyboard_hook = keyboard.hook(self.on_key_event) self.mouse_hook = keyboard.hook(self.on_mouse_event) self.log_message("开始录制...") self.log_message("请开始您的操作,按F1停止录制") self.log_message("正在录制: 鼠标点击、滚轮和键盘操作") def stop_recording(self): if not self.recording: return self.recording = False self.record_btn.config(bg="#4CAF50", text="开始录制 (F1)") self.play_btn.config(state=NORMAL) self.save_btn.config(state=NORMAL) self.delete_btn.config(state=NORMAL) # 移除钩子 if self.keyboard_hook: keyboard.unhook(self.keyboard_hook) if self.mouse_hook: keyboard.unhook(self.mouse_hook) self.log_message(f"停止录制,共录制了 {len(self.actions)} 个动作") self.save_script() def on_mouse_event(self, event): if not self.recording: return current_pos = pyautogui.position() if event.event_type in ('down', 'up'): button_mapping = { "left": "left", "right": "right", "middle": "middle", "x1": "x1", "x2": "x2" } button = button_mapping.get(event.name, "left") # 默认使用左键 action_type = "mousedown" if event.event_type == 'down' else "mouseup" self.actions.append({ "type": action_type, "button": button, "x": current_pos.x, "y": current_pos.y, "time": time.time() }) action_desc = f"鼠标{'按下' if event.event_type == 'down' else '释放'}: {button}键" self.log_message(f"{action_desc} 位置: ({current_pos.x}, {current_pos.y})") elif event.event_type == 'wheel': direction = "上" if event.delta > 0 else "下" self.actions.append({ "type": "wheel", "delta": event.delta, "x": current_pos.x, "y": current_pos.y, "time": time.time() }) self.log_message(f"滚轮滚动: 方向 {direction} 位置: ({current_pos.x}, {current_pos.y})") def on_key_event(self, event): if not self.recording: return # 忽略F1/F2按键 if event.name.lower() in self.ignored_keys: return if event.event_type == "down": # 只记录第一次按下,不记录重复按下 if event.name not in self.keyboard_state: self.keyboard_state[event.name] = True self.actions.append({ "type": "keydown", "key": event.name, "time": time.time() }) self.log_message(f"按键按下: {event.name}") elif event.event_type == "up": if event.name in self.keyboard_state: del self.keyboard_state[event.name] self.actions.append({ "type": "keyup", "key": event.name, "time": time.time() }) self.log_message(f"按键释放: {event.name}") def start_playing(self): if self.playing or self.recording or not self.actions: return if not self.update_current_config(): return self.playing = True self.play_btn.config(bg="#FF9800", text="停止执行 (F2)") self.record_btn.config(state=DISABLED) self.save_btn.config(state=DISABLED) self.delete_btn.config(state=DISABLED) # 开始执行线程 threading.Thread(target=self.play_actions, daemon=True).start() self.log_message("开始执行脚本...") def stop_playing(self): if not self.playing: return self.playing = False self.play_btn.config(bg="#2196F3", text="开始执行 (F2)") self.record_btn.config(state=NORMAL) self.save_btn.config(state=NORMAL) self.delete_btn.config(state=NORMAL) self.log_message("停止执行脚本") def play_actions(self): loop_times = self.current_config["loop_times"] random_interval = self.current_config["random_interval"] / 1000.0 # 转换为秒 for loop in range(loop_times): if not self.playing: break self.log_message(f"开始第 {loop + 1} 次循环 (共 {loop_times} 次)") prev_time = None for i, action in enumerate(self.actions): if not self.playing: break # 计算延迟 if prev_time is not None: delay = action["time"] - prev_time # 添加随机间隔 if random_interval > 0: delay += random.uniform(0, random_interval) time.sleep(max(0, delay)) prev_time = action["time"] # 执行动作 try: if action["type"] == "mousedown": # 确保只使用有效的按钮参数 button = action["button"] if action["button"] in ('left', 'middle', 'right') else 'left' pyautogui.mouseDown(x=action["x"], y=action["y"], button=button) self.log_message( f"执行动作 {i + 1}/{len(self.actions)}: 在({action['x']}, {action['y']})按下 {button}键") elif action["type"] == "mouseup": button = action["button"] if action["button"] in ('left', 'middle', 'right') else 'left' pyautogui.mouseUp(x=action["x"], y=action["y"], button=button) self.log_message( f"执行动作 {i + 1}/{len(self.actions)}: 在({action['x']}, {action['y']})释放 {button}键") elif action["type"] == "wheel": pyautogui.scroll(action["delta"]) self.log_message( f"执行动作 {i + 1}/{len(self.actions)}: 滚轮滚动 {'上' if action['delta'] > 0 else '下'}") elif action["type"] == "keydown": keyboard.press(action["key"]) self.log_message(f"执行动作 {i + 1}/{len(self.actions)}: 按下 {action['key']}键") elif action["type"] == "keyup": keyboard.release(action["key"]) self.log_message(f"执行动作 {i + 1}/{len(self.actions)}: 释放 {action['key']}键") except Exception as e: self.log_message(f"执行动作时出错: {str(e)}") if loop < loop_times - 1 and self.playing: time.sleep(1) # 循环之间的间隔 self.stop_playing() def run(self): self.root.mainloop() if __name__ == "__main__": recorder = ActionRecorder() recorder.run() 请帮我检查这个键盘鼠标脚本录制器错误地方,并帮我修改!
最新发布
06-19
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值