235 lines
7.2 KiB
Bash
Executable File
235 lines
7.2 KiB
Bash
Executable File
#!/bin/bash
|
|
|
|
# Enhanced Autoclicker script for Sway with improved antiban features
|
|
# Uses ydotool for Wayland/Sway environments
|
|
# Features human-like timing patterns and CSV logging for visualization
|
|
# Press Ctrl+C to stop (standard shell interrupt)
|
|
# Requires ydotool and ydotoold daemon running
|
|
|
|
# Configuration
|
|
MIN_DELAY=50 # Minimum delay in milliseconds
|
|
MAX_DELAY=700 # Maximum delay in milliseconds
|
|
MIN_CLICKS_BEFORE_BREAK=30 # Minimum clicks before break
|
|
MAX_CLICKS_BEFORE_BREAK=200 # Maximum clicks before break
|
|
MIN_BREAK=3 # Minimum break duration in seconds
|
|
MAX_BREAK=15 # Maximum break duration in seconds
|
|
|
|
# Human-like timing parameters
|
|
FASTIGUE_FACTOR=0.95 # Gradually slow down over time (0.95 = 5% slower)
|
|
REACTION_VARIATION=0.3 # 30% variation in reaction times
|
|
PATTERN_BREAK_CHANCE=0.05 # 5% chance to break pattern
|
|
|
|
# File paths
|
|
STATE_FILE="/tmp/autoclicker_running"
|
|
LOCK_FILE="/tmp/autoclicker_lock"
|
|
LOG_DIR="/tmp/autoclicker_logs"
|
|
LOG_FILE="$LOG_DIR/click_timings_$(date +%Y%m%d_%H%M%S).csv"
|
|
|
|
# Create log directory if it doesn't exist
|
|
mkdir -p "$LOG_DIR"
|
|
|
|
# Initialize CSV log file with header
|
|
echo "click_number,delay_ms,timestamp" > "$LOG_FILE"
|
|
|
|
# Check if ydotool is available
|
|
if ! command -v ydotool &> /dev/null; then
|
|
echo "Error: ydotool is not installed. Install it with: sudo pacman -S ydotool"
|
|
exit 1
|
|
fi
|
|
|
|
# Check if bc is available (needed for calculations)
|
|
if ! command -v bc &> /dev/null; then
|
|
echo "Error: bc is not installed. Install it with: sudo pacman -S bc"
|
|
exit 1
|
|
fi
|
|
|
|
# Check if script is already running (prevent multiple instances)
|
|
if [ -f "$LOCK_FILE" ]; then
|
|
echo "Autoclicker is already running!"
|
|
echo "Press Ctrl+C in the terminal where it's running to stop it."
|
|
# Clean up the incomplete log file that was just created
|
|
rm -f "$LOG_FILE"
|
|
exit 0
|
|
fi
|
|
|
|
# Create lock file
|
|
echo $$ > "$LOCK_FILE"
|
|
|
|
# Global exit flag
|
|
EXIT_REQUESTED=0
|
|
|
|
# Clean up on exit
|
|
cleanup() {
|
|
EXIT_REQUESTED=1
|
|
rm -f "$LOCK_FILE"
|
|
rm -f "$STATE_FILE"
|
|
echo ""
|
|
echo "Autoclicker stopped."
|
|
exit 0
|
|
}
|
|
|
|
# Set up traps for cleanup
|
|
trap cleanup INT TERM
|
|
|
|
# Check if ydotoold daemon is running
|
|
if ! pgrep -x "ydotoold" > /dev/null; then
|
|
echo "Starting ydotoold daemon..."
|
|
sudo ydotoold &
|
|
sleep 1
|
|
fi
|
|
|
|
# Create state file to indicate running
|
|
echo "running" > "$STATE_FILE"
|
|
|
|
# Function to log click timing to CSV
|
|
log_click_timing() {
|
|
local click_number=$1
|
|
local delay_ms=$2
|
|
local timestamp=$(date +%s%3N) # Milliseconds since epoch
|
|
echo "$click_number,$delay_ms,$timestamp" >> "$LOG_FILE"
|
|
}
|
|
|
|
# Function to generate random delay with human-like distribution
|
|
get_human_delay() {
|
|
local min=$1
|
|
local max=$2
|
|
local base_delay=$((min + RANDOM % (max - min + 1)))
|
|
|
|
# Apply reaction time variation (30% up or down)
|
|
local variation=$(echo "scale=3; $base_delay * $REACTION_VARIATION * (2 * $RANDOM / 32767 - 1)" | bc)
|
|
local varied_delay=$(echo "$base_delay + $variation" | bc)
|
|
|
|
# Ensure we stay within reasonable bounds
|
|
if (( $(echo "$varied_delay < $min" | bc -l) )); then
|
|
varied_delay=$min
|
|
elif (( $(echo "$varied_delay > $max" | bc -l) )); then
|
|
varied_delay=$max
|
|
fi
|
|
|
|
# Convert to seconds for sleep function
|
|
echo "scale=3; $varied_delay / 1000" | bc
|
|
}
|
|
|
|
# Function to generate random number of clicks before break
|
|
get_random_clicks() {
|
|
local min=$1
|
|
local max=$2
|
|
echo $((min + RANDOM % (max - min + 1)))
|
|
}
|
|
|
|
# Function to sleep with interrupt checking
|
|
interruptible_sleep() {
|
|
local duration=$1
|
|
local start_time=$(date +%s.%N)
|
|
local end_time=$(echo "$start_time + $duration" | bc)
|
|
|
|
while true; do
|
|
if [ $EXIT_REQUESTED -eq 1 ]; then
|
|
return 1 # Exit requested
|
|
fi
|
|
|
|
local current_time=$(date +%s.%N)
|
|
if (( $(echo "$current_time >= $end_time" | bc -l) )); then
|
|
return 0 # Sleep completed
|
|
fi
|
|
|
|
sleep 0.1
|
|
done
|
|
}
|
|
|
|
# Function to apply fatigue effect (gradually slow down)
|
|
apply_fatigue() {
|
|
local current_delay=$1
|
|
local click_count=$2
|
|
local fatigue_effect=$(echo "scale=3; $current_delay * (1 + $FASTIGUE_FACTOR * $click_count / 1000)" | bc)
|
|
echo "$fatigue_effect"
|
|
}
|
|
|
|
# Function to randomly break pattern (5% chance)
|
|
should_break_pattern() {
|
|
local threshold=$(echo "$PATTERN_BREAK_CHANCE * 32767" | bc | cut -d'.' -f1)
|
|
[ $RANDOM -lt $threshold ]
|
|
}
|
|
|
|
echo "=========================================="
|
|
echo "Enhanced Autoclicker started!"
|
|
echo "=========================================="
|
|
echo "Configuration:"
|
|
echo " - Click delay: ${MIN_DELAY}-${MAX_DELAY}ms (human-like variation)"
|
|
echo " - Break every: ${MIN_CLICKS_BEFORE_BREAK}-${MAX_CLICKS_BEFORE_BREAK} clicks (random)"
|
|
echo " - Break duration: ${MIN_BREAK}-${MAX_BREAK}s"
|
|
echo " - Fatigue factor: ${FASTIGUE_FACTOR} (gradual slowdown)"
|
|
echo " - Pattern break chance: ${PATTERN_BREAK_CHANCE} (5%)"
|
|
echo " - Logging to: $LOG_FILE"
|
|
echo ""
|
|
echo "Press Ctrl+C to stop"
|
|
echo "=========================================="
|
|
echo ""
|
|
|
|
click_count=0
|
|
total_clicks=0
|
|
clicks_before_break=$(get_random_clicks $MIN_CLICKS_BEFORE_BREAK $MAX_CLICKS_BEFORE_BREAK)
|
|
echo "Next break will be after $clicks_before_break clicks"
|
|
echo ""
|
|
|
|
while true; do
|
|
if [ $EXIT_REQUESTED -eq 1 ]; then
|
|
echo "Exit signal received!"
|
|
break
|
|
fi
|
|
|
|
# Generate base random delay
|
|
base_delay=$(get_human_delay $MIN_DELAY $MAX_DELAY)
|
|
|
|
# Apply fatigue effect (gradually slow down)
|
|
final_delay=$(apply_fatigue "$base_delay" "$click_count")
|
|
|
|
# Randomly break pattern (5% chance)
|
|
if should_break_pattern; then
|
|
# Add a longer, unpredictable delay
|
|
pattern_break_delay=$(echo "scale=3; ($MAX_DELAY * 2 + $RANDOM % 1000) / 1000" | bc)
|
|
echo "[Pattern Break] Adding unpredictable delay of $(echo "$pattern_break_delay * 1000" | bc | cut -d'.' -f1)ms"
|
|
|
|
if ! interruptible_sleep "$pattern_break_delay"; then
|
|
break
|
|
fi
|
|
fi
|
|
|
|
# Perform click (suppress ydotool output)
|
|
ydotool click 0xC0 2>/dev/null
|
|
click_count=$((click_count + 1))
|
|
total_clicks=$((total_clicks + 1))
|
|
|
|
# Convert delay to milliseconds for display
|
|
delay_ms=$(echo "$final_delay * 1000" | bc | cut -d'.' -f1)
|
|
|
|
# Log click timing to CSV
|
|
log_click_timing "$total_clicks" "$delay_ms"
|
|
|
|
# Show each click with its delay
|
|
echo "Click #$total_clicks (delay: ${delay_ms}ms, next break in $((clicks_before_break - click_count)) clicks)"
|
|
|
|
# Check if it's time for a break
|
|
if [ $click_count -ge $clicks_before_break ]; then
|
|
break_duration=$(get_human_delay $((MIN_BREAK * 1000)) $((MAX_BREAK * 1000)))
|
|
echo ""
|
|
echo "[Break] Completed $clicks_before_break clicks (total: $total_clicks). Taking a break for ${break_duration}s..."
|
|
|
|
if ! interruptible_sleep "$break_duration"; then
|
|
break
|
|
fi
|
|
|
|
click_count=0
|
|
# Generate new random click count for next cycle
|
|
clicks_before_break=$(get_random_clicks $MIN_CLICKS_BEFORE_BREAK $MAX_CLICKS_BEFORE_BREAK)
|
|
echo "[Resumed] Next break will be after $clicks_before_break clicks"
|
|
echo ""
|
|
else
|
|
# Wait the calculated delay before next click
|
|
if ! interruptible_sleep "$final_delay"; then
|
|
break
|
|
fi
|
|
fi
|
|
done
|
|
|
|
echo "Click timings saved to: $LOG_FILE" |