blur-autoclicker-automation

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Blur AutoClicker Automation

Blur AutoClicker 自动化工具

Skill by ara.so — Devtools Skills collection.
Blur AutoClicker is a high-performance Windows auto-clicker built with TypeScript and Tauri that provides precise CPS (clicks per second) control up to 500 CPS, keyboard automation, position clicking, and advanced timing features. It combines a web-based UI with Rust backend for optimal performance while maintaining under 100MB RAM usage.
ara.so开发的工具 — 开发者工具技能合集。
Blur AutoClicker是一款基于TypeScript和Tauri构建的高性能Windows自动点击器,提供最高可达500次/秒(CPS,clicks per second)的精准点击控制、键盘自动化、定点点击以及高级定时功能。它结合了Web界面与Rust后端,在保持性能最优的同时,内存占用始终低于100MB。

Installation

安装

End User Installation

终端用户安装

Download the latest release from GitHub:
powershell
undefined
从GitHub下载最新版本:
powershell
undefined

Default installation location

默认安装路径

%localappdata%\BlurAutoClicker\BlurAutoClicker.exe
%localappdata%\BlurAutoClicker\BlurAutoClicker.exe

Config and stats location

配置文件及统计数据路径

%appdata%\BlurAutoClicker
undefined
%appdata%\BlurAutoClicker
undefined

Development Setup

开发环境搭建

Requirements:
  • Node.js 20 or newer
  • Rust via rustup
  • Microsoft C++ Build Tools / Visual Studio Build Tools
powershell
undefined
前置要求:
  • Node.js 20或更高版本
  • 通过rustup安装Rust
  • Microsoft C++构建工具 / Visual Studio构建工具
powershell
undefined

Clone the repository

克隆仓库

Install dependencies

安装依赖

npm install
npm install

Set up Rust toolchain

设置Rust工具链

rustup default stable-x86_64-pc-windows-msvc
undefined
rustup default stable-x86_64-pc-windows-msvc
undefined

Development Commands

开发命令

powershell
undefined
powershell
undefined

Run in development mode

启动开发模式

npm run dev
npm run dev

Build release bundle

构建发布包

npm run build
npm run build

Lint code

代码检查

npm run lint
npm run lint

Build frontend only

仅构建前端

npm run frontend:build
npm run frontend:build

Run Rust tests

运行Rust测试

cargo test --manifest-path src-tauri/Cargo.toml
cargo test --manifest-path src-tauri/Cargo.toml

Check Rust code

检查Rust代码

cargo check --manifest-path src-tauri/Cargo.toml

Built installer location: `src-tauri/target/release/bundle/nsis/`
cargo check --manifest-path src-tauri/Cargo.toml

生成的安装包路径:`src-tauri/target/release/bundle/nsis/`

Project Structure

项目结构

Blur-AutoClicker/
├── src/                    # TypeScript frontend (web UI)
├── src-tauri/             # Rust backend (Tauri)
│   ├── src/               # Rust source code
│   ├── Cargo.toml         # Rust dependencies
│   └── tauri.conf.json    # Tauri configuration
├── public/                # Static assets
└── package.json           # Node.js dependencies
Blur-AutoClicker/
├── src/                    # TypeScript前端(Web界面)
├── src-tauri/             # Rust后端(Tauri)
│   ├── src/               # Rust源代码
│   ├── Cargo.toml         # Rust依赖配置
│   └── tauri.conf.json    # Tauri配置文件
├── public/                # 静态资源
└── package.json           # Node.js依赖配置

Core Features

核心功能

1. Mouse Button Control

1. 鼠标按键控制

The application supports left, right, and middle mouse button clicking:
typescript
// Example configuration for mouse button selection
interface MouseConfig {
  button: 'left' | 'right' | 'middle';
  mode: 'hold' | 'toggle';
  cps: number; // Clicks per second (max 500)
}

const config: MouseConfig = {
  button: 'left',
  mode: 'toggle',
  cps: 50
};
应用支持左键、右键和中键点击:
typescript
// 鼠标按键选择配置示例
interface MouseConfig {
  button: 'left' | 'right' | 'middle';
  mode: 'hold' | 'toggle';
  cps: number; // 点击次数/秒(最高500)
}

const config: MouseConfig = {
  button: 'left',
  mode: 'toggle',
  cps: 50
};

2. Keyboard Key Automation

2. 键盘按键自动化

Automate keyboard key presses with case control:
typescript
interface KeyConfig {
  key: string;
  uppercase: boolean;
  mode: 'hold' | 'toggle';
  pressesPerSecond: number;
}

const keyConfig: KeyConfig = {
  key: 'a',
  uppercase: false,
  mode: 'hold',
  pressesPerSecond: 10
};
支持带大小写控制的键盘按键自动触发:
typescript
interface KeyConfig {
  key: string;
  uppercase: boolean;
  mode: 'hold' | 'toggle';
  pressesPerSecond: number;
}

const keyConfig: KeyConfig = {
  key: 'a',
  uppercase: false,
  mode: 'hold',
  pressesPerSecond: 10
};

3. Click Timing (Duty Cycle)

3. 点击时序(工作周期)

Control the timing between press and release:
typescript
interface TimingConfig {
  clickDuration: number; // milliseconds
  interval: number; // milliseconds between clicks
}

// For 50 CPS with 50% duty cycle
const timing: TimingConfig = {
  clickDuration: 10, // 10ms press
  interval: 20 // 20ms total (1000ms / 50 CPS)
};
控制按下与释放之间的时间间隔:
typescript
interface TimingConfig {
  clickDuration: number; // 毫秒
  interval: number; // 点击间隔毫秒数
}

// 50 CPS且工作周期50%的配置
const timing: TimingConfig = {
  clickDuration: 10, // 按下10毫秒
  interval: 20 // 总间隔20毫秒(1000ms / 50 CPS)
};

4. Speed Range Mode

4. 速度范围模式

Randomize CPS within a range:
typescript
interface SpeedRangeConfig {
  enabled: boolean;
  minCps: number;
  maxCps: number;
}

const speedRange: SpeedRangeConfig = {
  enabled: true,
  minCps: 40,
  maxCps: 60
};
在指定范围内随机化CPS:
typescript
interface SpeedRangeConfig {
  enabled: boolean;
  minCps: number;
  maxCps: number;
}

const speedRange: SpeedRangeConfig = {
  enabled: true,
  minCps: 40,
  maxCps: 60
};

5. Position Clicking

5. 定点点击

Click at specific screen coordinates:
typescript
interface PositionConfig {
  enabled: boolean;
  x: number;
  y: number;
  moveBeforeClick: boolean;
}

const positionClick: PositionConfig = {
  enabled: true,
  x: 1920,
  y: 1080,
  moveBeforeClick: true
};
在特定屏幕坐标处点击:
typescript
interface PositionConfig {
  enabled: boolean;
  x: number;
  y: number;
  moveBeforeClick: boolean;
}

const positionClick: PositionConfig = {
  enabled: true,
  x: 1920,
  y: 1080,
  moveBeforeClick: true
};

6. Click and Time Limits

6. 点击次数与时间限制

Stop after specific conditions:
typescript
interface LimitsConfig {
  clickLimit?: number; // Stop after X clicks
  timeLimit?: number; // Stop after X seconds
}

const limits: LimitsConfig = {
  clickLimit: 1000,
  timeLimit: 60 // 60 seconds
};
满足特定条件后自动停止:
typescript
interface LimitsConfig {
  clickLimit?: number; // 点击X次后停止
  timeLimit?: number; // 运行X秒后停止
}

const limits: LimitsConfig = {
  clickLimit: 1000,
  timeLimit: 60 // 60秒
};

7. Corner and Edge Stopping

7. 边角停止

Automatically stop when mouse reaches screen edges:
typescript
interface EdgeStoppingConfig {
  enabled: boolean;
  cornerThreshold: number; // pixels from corner
  edgeThreshold: number; // pixels from edge
}

const edgeStopping: EdgeStoppingConfig = {
  enabled: true,
  cornerThreshold: 50,
  edgeThreshold: 10
};
鼠标到达屏幕边缘时自动停止:
typescript
interface EdgeStoppingConfig {
  enabled: boolean;
  cornerThreshold: number; // 距离边角的像素数
  edgeThreshold: number; // 距离边缘的像素数
}

const edgeStopping: EdgeStoppingConfig = {
  enabled: true,
  cornerThreshold: 50,
  edgeThreshold: 10
};

Tauri Backend Integration

Tauri后端集成

Tauri Commands

Tauri命令

When developing features, interact with the Rust backend via Tauri commands:
typescript
import { invoke } from '@tauri-apps/api/tauri';

// Start clicking
async function startClicking(config: ClickConfig): Promise<void> {
  await invoke('start_clicking', { config });
}

// Stop clicking
async function stopClicking(): Promise<void> {
  await invoke('stop_clicking');
}

// Get click stats
async function getStats(): Promise<ClickStats> {
  return await invoke('get_stats');
}

interface ClickStats {
  totalClicks: number;
  currentCps: number;
  averageCps: number;
  uptime: number;
}
开发功能时,通过Tauri命令与Rust后端交互:
typescript
import { invoke } from '@tauri-apps/api/tauri';

// 开始点击
async function startClicking(config: ClickConfig): Promise<void> {
  await invoke('start_clicking', { config });
}

// 停止点击
async function stopClicking(): Promise<void> {
  await invoke('stop_clicking');
}

// 获取点击统计
async function getStats(): Promise<ClickStats> {
  return await invoke('get_stats');
}

interface ClickStats {
  totalClicks: number;
  currentCps: number;
  averageCps: number;
  uptime: number;
}

Rust Backend Example

Rust后端示例

rust
// src-tauri/src/main.rs
use tauri::State;
use std::sync::Mutex;

struct ClickerState {
    is_active: bool,
    total_clicks: u64,
}

#[tauri::command]
fn start_clicking(state: State<Mutex<ClickerState>>) -> Result<(), String> {
    let mut clicker = state.lock().unwrap();
    clicker.is_active = true;
    Ok(())
}

#[tauri::command]
fn stop_clicking(state: State<Mutex<ClickerState>>) -> Result<(), String> {
    let mut clicker = state.lock().unwrap();
    clicker.is_active = false;
    Ok(())
}

#[tauri::command]
fn get_stats(state: State<Mutex<ClickerState>>) -> Result<u64, String> {
    let clicker = state.lock().unwrap();
    Ok(clicker.total_clicks)
}
rust
// src-tauri/src/main.rs
use tauri::State;
use std::sync::Mutex;

struct ClickerState {
    is_active: bool,
    total_clicks: u64,
}

#[tauri::command]
fn start_clicking(state: State<Mutex<ClickerState>>) -> Result<(), String> {
    let mut clicker = state.lock().unwrap();
    clicker.is_active = true;
    Ok(())
}

#[tauri::command]
fn stop_clicking(state: State<Mutex<ClickerState>>) -> Result<(), String> {
    let mut clicker = state.lock().unwrap();
    clicker.is_active = false;
    Ok(())
}

#[tauri::command]
fn get_stats(state: State<Mutex<ClickerState>>) -> Result<u64, String> {
    let clicker = state.lock().unwrap();
    Ok(clicker.total_clicks)
}

Configuration Management

配置管理

Saving Configuration

保存配置

typescript
import { appDataDir } from '@tauri-apps/api/path';
import { writeTextFile, readTextFile } from '@tauri-apps/api/fs';

async function saveConfig(config: AppConfig): Promise<void> {
  const appData = await appDataDir();
  const configPath = `${appData}/config.json`;
  await writeTextFile(configPath, JSON.stringify(config, null, 2));
}

async function loadConfig(): Promise<AppConfig | null> {
  try {
    const appData = await appDataDir();
    const configPath = `${appData}/config.json`;
    const content = await readTextFile(configPath);
    return JSON.parse(content);
  } catch (error) {
    console.error('Failed to load config:', error);
    return null;
  }
}

interface AppConfig {
  mouseButton: 'left' | 'right' | 'middle';
  mode: 'hold' | 'toggle';
  cps: number;
  hotkey: string;
  advanced: AdvancedConfig;
}

interface AdvancedConfig {
  dutyCycle: number;
  speedRange?: SpeedRangeConfig;
  positionClick?: PositionConfig;
  limits?: LimitsConfig;
  edgeStopping?: EdgeStoppingConfig;
}
typescript
import { appDataDir } from '@tauri-apps/api/path';
import { writeTextFile, readTextFile } from '@tauri-apps/api/fs';

async function saveConfig(config: AppConfig): Promise<void> {
  const appData = await appDataDir();
  const configPath = `${appData}/config.json`;
  await writeTextFile(configPath, JSON.stringify(config, null, 2));
}

async function loadConfig(): Promise<AppConfig | null> {
  try {
    const appData = await appDataDir();
    const configPath = `${appData}/config.json`;
    const content = await readTextFile(configPath);
    return JSON.parse(content);
  } catch (error) {
    console.error('加载配置失败:', error);
    return null;
  }
}

interface AppConfig {
  mouseButton: 'left' | 'right' | 'middle';
  mode: 'hold' | 'toggle';
  cps: number;
  hotkey: string;
  advanced: AdvancedConfig;
}

interface AdvancedConfig {
  dutyCycle: number;
  speedRange?: SpeedRangeConfig;
  positionClick?: PositionConfig;
  limits?: LimitsConfig;
  edgeStopping?: EdgeStoppingConfig;
}

Hotkey Management

热键管理

typescript
import { register, unregister } from '@tauri-apps/api/globalShortcut';

async function setupHotkeys(hotkey: string): Promise<void> {
  // Unregister previous hotkey
  await unregister(hotkey).catch(() => {});
  
  // Register new hotkey
  await register(hotkey, async () => {
    // Toggle clicking state
    const isActive = await invoke('is_clicking_active');
    if (isActive) {
      await invoke('stop_clicking');
    } else {
      await invoke('start_clicking');
    }
  });
}

// Common hotkey combinations
const hotkeyExamples = [
  'F6',
  'F7',
  'F8',
  'Ctrl+Shift+A',
  'Alt+C'
];
typescript
import { register, unregister } from '@tauri-apps/api/globalShortcut';

async function setupHotkeys(hotkey: string): Promise<void> {
  // 注销之前的热键
  await unregister(hotkey).catch(() => {});
  
  // 注册新热键
  await register(hotkey, async () => {
    // 切换点击状态
    const isActive = await invoke('is_clicking_active');
    if (isActive) {
      await invoke('stop_clicking');
    } else {
      await invoke('start_clicking');
    }
  });
}

// 常见热键组合
const hotkeyExamples = [
  'F6',
  'F7',
  'F8',
  'Ctrl+Shift+A',
  'Alt+C'
];

Performance Optimization

性能优化

Timer Resolution

定时器精度

rust
// src-tauri/src/timer.rs
use std::time::{Duration, Instant};
use std::thread;

pub struct PrecisionTimer {
    interval: Duration,
    last_tick: Instant,
}

impl PrecisionTimer {
    pub fn new(cps: u32) -> Self {
        let interval = Duration::from_micros(1_000_000 / cps as u64);
        Self {
            interval,
            last_tick: Instant::now(),
        }
    }
    
    pub fn wait_for_next_tick(&mut self) {
        let elapsed = self.last_tick.elapsed();
        if elapsed < self.interval {
            thread::sleep(self.interval - elapsed);
        }
        self.last_tick = Instant::now();
    }
}

// Usage
let mut timer = PrecisionTimer::new(50); // 50 CPS
loop {
    // Perform click
    send_click();
    timer.wait_for_next_tick();
}
rust
// src-tauri/src/timer.rs
use std::time::{Duration, Instant};
use std::thread;

pub struct PrecisionTimer {
    interval: Duration,
    last_tick: Instant,
}

impl PrecisionTimer {
    pub fn new(cps: u32) -> Self {
        let interval = Duration::from_micros(1_000_000 / cps as u64);
        Self {
            interval,
            last_tick: Instant::now(),
        }
    }
    
    pub fn wait_for_next_tick(&mut self) {
        let elapsed = self.last_tick.elapsed();
        if elapsed < self.interval {
            thread::sleep(self.interval - elapsed);
        }
        self.last_tick = Instant::now();
    }
}

// 使用示例
let mut timer = PrecisionTimer::new(50); // 50 CPS
loop {
    // 执行点击
    send_click();
    timer.wait_for_next_tick();
}

Memory Management

内存管理

Keep RAM usage under 100MB:
typescript
// Clear click history periodically
let clickHistory: number[] = [];
const MAX_HISTORY_SIZE = 1000;

function recordClick(timestamp: number): void {
  clickHistory.push(timestamp);
  
  // Keep only recent clicks
  if (clickHistory.length > MAX_HISTORY_SIZE) {
    clickHistory = clickHistory.slice(-MAX_HISTORY_SIZE);
  }
}

function calculateCps(): number {
  const now = Date.now();
  const recentClicks = clickHistory.filter(t => now - t < 1000);
  return recentClicks.length;
}
保持内存占用低于100MB:
typescript
// 定期清理点击历史
let clickHistory: number[] = [];
const MAX_HISTORY_SIZE = 1000;

function recordClick(timestamp: number): void {
  clickHistory.push(timestamp);
  
  // 仅保留最近的点击记录
  if (clickHistory.length > MAX_HISTORY_SIZE) {
    clickHistory = clickHistory.slice(-MAX_HISTORY_SIZE);
  }
}

function calculateCps(): number {
  const now = Date.now();
  const recentClicks = clickHistory.filter(t => now - t < 1000);
  return recentClicks.length;
}

Building for Release

构建发布版本

Windows Release Process

Windows发布流程

powershell
undefined
powershell
undefined

1. Update version in package.json and Cargo.toml

1. 更新package.json和Cargo.toml中的版本号

2. Clean previous builds

2. 清理之前的构建产物

Remove-Item -Recurse -Force src-tauri/target/release/bundle -ErrorAction SilentlyContinue
Remove-Item -Recurse -Force src-tauri/target/release/bundle -ErrorAction SilentlyContinue

3. Build release

3. 构建发布版本

npm run build
npm run build

4. Installer location

4. 安装包路径

src-tauri/target/release/bundle/nsis/Blur-AutoClicker_X.X.X_x64-setup.exe

src-tauri/target/release/bundle/nsis/Blur-AutoClicker_X.X.X_x64-setup.exe

5. Test installer

5. 测试安装包

Start-Process "src-tauri\target\release\bundle\nsis*.exe"
undefined
Start-Process "src-tauri\target\release\bundle\nsis*.exe"
undefined

Code Signing (Optional)

代码签名(可选)

powershell
undefined
powershell
undefined

Note: Windows Authenticode signing is separate from Tauri updater signing

注意:Windows Authenticode签名与Tauri更新器签名是分开的

See docs/windows-release-trust.md for complete signing instructions

完整签名说明请查看docs/windows-release-trust.md

Environment variables needed for signing

签名所需环境变量

WINDOWS_CERTIFICATE (base64 certificate)

WINDOWS_CERTIFICATE(base64格式证书)

WINDOWS_CERTIFICATE_PASSWORD (certificate password)

WINDOWS_CERTIFICATE_PASSWORD(证书密码)

undefined
undefined

Common Development Patterns

常见开发模式

Creating a Custom Click Mode

创建自定义点击模式

typescript
// src/lib/modes/customMode.ts
interface CustomModeConfig {
  pattern: number[]; // Array of delays in milliseconds
  repeat: boolean;
}

class CustomClickMode {
  private config: CustomModeConfig;
  private patternIndex: number = 0;
  
  constructor(config: CustomModeConfig) {
    this.config = config;
  }
  
  getNextDelay(): number {
    const delay = this.config.pattern[this.patternIndex];
    this.patternIndex = (this.patternIndex + 1) % this.config.pattern.length;
    return delay;
  }
  
  async executePattern(): Promise<void> {
    do {
      for (const delay of this.config.pattern) {
        await invoke('send_click');
        await new Promise(resolve => setTimeout(resolve, delay));
      }
    } while (this.config.repeat);
  }
}

// Usage: Click with pattern [100ms, 200ms, 100ms, 500ms]
const customMode = new CustomClickMode({
  pattern: [100, 200, 100, 500],
  repeat: true
});
typescript
// src/lib/modes/customMode.ts
interface CustomModeConfig {
  pattern: number[]; // 毫秒级延迟数组
  repeat: boolean;
}

class CustomClickMode {
  private config: CustomModeConfig;
  private patternIndex: number = 0;
  
  constructor(config: CustomModeConfig) {
    this.config = config;
  }
  
  getNextDelay(): number {
    const delay = this.config.pattern[this.patternIndex];
    this.patternIndex = (this.patternIndex + 1) % this.config.pattern.length;
    return delay;
  }
  
  async executePattern(): Promise<void> {
    do {
      for (const delay of this.config.pattern) {
        await invoke('send_click');
        await new Promise(resolve => setTimeout(resolve, delay));
      }
    } while (this.config.repeat);
  }
}

// 使用示例:按照[100ms, 200ms, 100ms, 500ms]的模式点击
const customMode = new CustomClickMode({
  pattern: [100, 200, 100, 500],
  repeat: true
});

Statistics Tracking

统计数据追踪

typescript
// src/lib/stats.ts
interface ClickStatistics {
  totalClicks: number;
  sessionClicks: number;
  averageCps: number;
  peakCps: number;
  uptime: number; // seconds
  startTime: number;
}

class StatsTracker {
  private stats: ClickStatistics;
  private clickTimestamps: number[] = [];
  
  constructor() {
    this.stats = {
      totalClicks: 0,
      sessionClicks: 0,
      averageCps: 0,
      peakCps: 0,
      uptime: 0,
      startTime: Date.now()
    };
  }
  
  recordClick(): void {
    const now = Date.now();
    this.stats.totalClicks++;
    this.stats.sessionClicks++;
    this.clickTimestamps.push(now);
    
    // Keep only last second of clicks
    const oneSecondAgo = now - 1000;
    this.clickTimestamps = this.clickTimestamps.filter(t => t > oneSecondAgo);
    
    const currentCps = this.clickTimestamps.length;
    if (currentCps > this.stats.peakCps) {
      this.stats.peakCps = currentCps;
    }
  }
  
  getStats(): ClickStatistics {
    this.stats.uptime = Math.floor((Date.now() - this.stats.startTime) / 1000);
    this.stats.averageCps = this.stats.uptime > 0 
      ? this.stats.sessionClicks / this.stats.uptime 
      : 0;
    return { ...this.stats };
  }
  
  async save(): Promise<void> {
    await saveConfig({ stats: this.stats });
  }
}
typescript
// src/lib/stats.ts
interface ClickStatistics {
  totalClicks: number;
  sessionClicks: number;
  averageCps: number;
  peakCps: number;
  uptime: number; // 秒
  startTime: number;
}

class StatsTracker {
  private stats: ClickStatistics;
  private clickTimestamps: number[] = [];
  
  constructor() {
    this.stats = {
      totalClicks: 0,
      sessionClicks: 0,
      averageCps: 0,
      peakCps: 0,
      uptime: 0,
      startTime: Date.now()
    };
  }
  
  recordClick(): void {
    const now = Date.now();
    this.stats.totalClicks++;
    this.stats.sessionClicks++;
    this.clickTimestamps.push(now);
    
    // 仅保留最近一秒的点击记录
    const oneSecondAgo = now - 1000;
    this.clickTimestamps = this.clickTimestamps.filter(t => t > oneSecondAgo);
    
    const currentCps = this.clickTimestamps.length;
    if (currentCps > this.stats.peakCps) {
      this.stats.peakCps = currentCps;
    }
  }
  
  getStats(): ClickStatistics {
    this.stats.uptime = Math.floor((Date.now() - this.stats.startTime) / 1000);
    this.stats.averageCps = this.stats.uptime > 0 
      ? this.stats.sessionClicks / this.stats.uptime 
      : 0;
    return { ...this.stats };
  }
  
  async save(): Promise<void> {
    await saveConfig({ stats: this.stats });
  }
}

Troubleshooting

故障排查

Windows SmartScreen Warning

Windows SmartScreen警告

The application shows SmartScreen warnings for unsigned installers:
  • This is normal for open-source GitHub releases
  • See
    docs/windows-release-trust.md
    for signing information
  • Users can click "More info" → "Run anyway"
未签名的安装包会触发SmartScreen警告:
  • 这对于GitHub开源发布的软件是正常现象
  • 签名相关信息请查看
    docs/windows-release-trust.md
  • 用户可以点击“更多信息”→“仍要运行”

CPS Accuracy Issues

CPS精度问题

If actual CPS doesn't match configured CPS:
typescript
// Enable debug logging
const DEBUG = true;

async function debugClickAccuracy(targetCps: number, duration: number): Promise<void> {
  const clicks: number[] = [];
  const startTime = Date.now();
  
  while (Date.now() - startTime < duration) {
    const clickTime = Date.now();
    await invoke('send_click');
    clicks.push(clickTime);
    
    if (DEBUG) {
      // Calculate actual CPS every second
      const recentClicks = clicks.filter(t => clickTime - t < 1000);
      console.log(`Target: ${targetCps} CPS, Actual: ${recentClicks.length} CPS`);
    }
  }
  
  // Final accuracy report
  const totalTime = (Date.now() - startTime) / 1000;
  const actualCps = clicks.length / totalTime;
  const accuracy = (actualCps / targetCps) * 100;
  console.log(`Accuracy: ${accuracy.toFixed(2)}%`);
}
如果实际CPS与配置值不符:
typescript
// 启用调试日志
const DEBUG = true;

async function debugClickAccuracy(targetCps: number, duration: number): Promise<void> {
  const clicks: number[] = [];
  const startTime = Date.now();
  
  while (Date.now() - startTime < duration) {
    const clickTime = Date.now();
    await invoke('send_click');
    clicks.push(clickTime);
    
    if (DEBUG) {
      // 每秒计算一次实际CPS
      const recentClicks = clicks.filter(t => clickTime - t < 1000);
      console.log(`目标CPS: ${targetCps}, 实际CPS: ${recentClicks.length}`);
    }
  }
  
  // 最终精度报告
  const totalTime = (Date.now() - startTime) / 1000;
  const actualCps = clicks.length / totalTime;
  const accuracy = (actualCps / targetCps) * 100;
  console.log(`精度: ${accuracy.toFixed(2)}%`);
}

High RAM Usage

内存占用过高

If RAM usage exceeds 100MB:
typescript
// Monitor memory usage
if (performance.memory) {
  const usedMemory = performance.memory.usedJSHeapSize / 1024 / 1024;
  console.log(`Memory usage: ${usedMemory.toFixed(2)} MB`);
  
  if (usedMemory > 80) {
    // Clear unnecessary data
    clickHistory = clickHistory.slice(-100);
    // Force garbage collection (if available)
    if (global.gc) global.gc();
  }
}
如果内存占用超过100MB:
typescript
// 监控内存使用情况
if (performance.memory) {
  const usedMemory = performance.memory.usedJSHeapSize / 1024 / 1024;
  console.log(`内存占用: ${usedMemory.toFixed(2)} MB`);
  
  if (usedMemory > 80) {
    // 清理不必要的数据
    clickHistory = clickHistory.slice(-100);
    // 强制垃圾回收(如果支持)
    if (global.gc) global.gc();
  }
}

Build Errors

构建错误

powershell
undefined
powershell
undefined

Clean install

重新安装依赖

Remove-Item -Recurse -Force node_modules Remove-Item package-lock.json npm install
Remove-Item -Recurse -Force node_modules Remove-Item package-lock.json npm install

Clean Rust build

清理Rust构建产物

cargo clean --manifest-path src-tauri/Cargo.toml
cargo clean --manifest-path src-tauri/Cargo.toml

Update Rust toolchain

更新Rust工具链

rustup update stable-x86_64-pc-windows-msvc
rustup update stable-x86_64-pc-windows-msvc

Rebuild

重新构建

npm run build
undefined
npm run build
undefined

Tauri Command Not Found

Tauri命令未找到

typescript
// Ensure proper Tauri API imports
import { invoke } from '@tauri-apps/api/tauri';

// Check Tauri configuration
// src-tauri/tauri.conf.json
{
  "tauri": {
    "allowlist": {
      "all": false,
      "fs": {
        "all": false,
        "readFile": true,
        "writeFile": true
      },
      "globalShortcut": {
        "all": true
      }
    }
  }
}
typescript
// 确保正确导入Tauri API
import { invoke } from '@tauri-apps/api/tauri';

// 检查Tauri配置
// src-tauri/tauri.conf.json
{
  "tauri": {
    "allowlist": {
      "all": false,
      "fs": {
        "all": false,
        "readFile": true,
        "writeFile": true
      },
      "globalShortcut": {
        "all": true
      }
    }
  }
}

Testing

测试

typescript
// Example test for click accuracy
describe('Click Accuracy', () => {
  it('should click at specified CPS within 5% tolerance', async () => {
    const targetCps = 50;
    const duration = 5000; // 5 seconds
    const tolerance = 0.05; // 5%
    
    const clicks = await testClickAccuracy(targetCps, duration);
    const actualCps = clicks.length / (duration / 1000);
    
    const lowerBound = targetCps * (1 - tolerance);
    const upperBound = targetCps * (1 + tolerance);
    
    expect(actualCps).toBeGreaterThanOrEqual(lowerBound);
    expect(actualCps).toBeLessThanOrEqual(upperBound);
  });
});
typescript
// 点击精度测试示例
describe('点击精度', () => {
  it('应在指定CPS的5%误差范围内点击', async () => {
    const targetCps = 50;
    const duration = 5000; // 5秒
    const tolerance = 0.05; // 5%
    
    const clicks = await testClickAccuracy(targetCps, duration);
    const actualCps = clicks.length / (duration / 1000);
    
    const lowerBound = targetCps * (1 - tolerance);
    const upperBound = targetCps * (1 + tolerance);
    
    expect(actualCps).toBeGreaterThanOrEqual(lowerBound);
    expect(actualCps).toBeLessThanOrEqual(upperBound);
  });
});

License

许可证

GPL-3.0 - See LICENSE.md
GPL-3.0 - 查看LICENSE.md