Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 49 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,55 @@ sudo apt install xdotool
- Whip him 😩💢
- It sends an interrupt (Ctrl-C) and one of 5 encouraging messages!

## Linux Setup

### X11

```bash
# Debian/Ubuntu
sudo apt install xdotool

# Arch
sudo pacman -S xdotool
```

### Wayland (GNOME, etc.)

```bash
# Arch
sudo pacman -S ydotool

# Debian/Ubuntu
sudo apt install ydotool
```

Enable and start the ydotool daemon:

```bash
sudo systemctl enable --now ydotool
sudo usermod -aG input $USER
```

Log out and back in for the group change to take effect.

### GNOME Tray Icon

GNOME doesn't show tray icons by default. Install the AppIndicator extension:

```bash
# Arch
sudo pacman -S gnome-shell-extension-appindicator

# Debian/Ubuntu
sudo apt install gnome-shell-extension-appindicator
```

Enable it via GNOME Extensions app or:

```bash
gnome-extensions enable appindicatorsupport@rgcjonas.gmail.com
```

## Roadmap

- [x] Initial release! 🥳
Expand Down
Empty file modified bin/badclaude.js
100644 → 100755
Empty file.
59 changes: 42 additions & 17 deletions main.js
Original file line number Diff line number Diff line change
Expand Up @@ -53,11 +53,18 @@ function refocusPreviousApp() {
}
});
} else if (process.platform === 'linux') {
execFile('xdotool', ['key', '--clearmodifiers', 'alt+Tab'], err => {
if (err) {
console.warn('refocus previous app (Alt+Tab) failed. Install xdotool:', err.message);
}
});
if (process.env.XDG_SESSION_TYPE === 'wayland') {
// ydotool scancodes: 56=Alt, 15=Tab
execFile('ydotool', ['key', '56:1', '15:1', '15:0', '56:0'], err => {
if (err) console.warn('refocus (ydotool Alt+Tab) failed:', err.message);
});
} else {
execFile('xdotool', ['key', '--clearmodifiers', 'alt+Tab'], err => {
if (err) {
console.warn('refocus previous app (Alt+Tab) failed. Install xdotool:', err.message);
}
});
}
}
};
setTimeout(run, delayMs);
Expand Down Expand Up @@ -122,7 +129,9 @@ async function getTrayIcon() {

// ── Overlay window ──────────────────────────────────────────────────────────
function createOverlay() {
const { bounds } = screen.getPrimaryDisplay();
const cursor = screen.getCursorScreenPoint();
const display = screen.getDisplayNearestPoint(cursor);
const { bounds } = display;
overlay = new BrowserWindow({
x: bounds.x, y: bounds.y,
width: bounds.width, height: bounds.height,
Expand Down Expand Up @@ -260,19 +269,35 @@ function sendMacroMac(text) {
}

function sendMacroLinux(text) {
execFile(
'xdotool',
[
'key', '--clearmodifiers', 'ctrl+c',
'type', '--delay', '1', '--clearmodifiers', '--', text,
'key', 'Return',
],
err => {
if (process.env.XDG_SESSION_TYPE === 'wayland') {
// ydotool uses uinput — requires ydotoold service and user in 'input' group
// Scancodes: 29=LCtrl, 46=C, 28=Enter
execFile('ydotool', ['key', '29:1', '46:1', '46:0', '29:0'], err => {
if (err) {
console.warn('linux macro failed. Install xdotool:', err.message);
console.warn('ydotool failed (ensure ydotoold is running and user is in input group):', err.message);
return;
}
}
);
setTimeout(() => {
execFile('ydotool', ['type', '--', text], () => {
execFile('ydotool', ['key', '28:1', '28:0']);
});
}, 30);
});
} else {
execFile(
'xdotool',
[
'key', '--clearmodifiers', 'ctrl+c',
'type', '--delay', '1', '--clearmodifiers', '--', text,
'key', 'Return',
],
err => {
if (err) {
console.warn('linux macro failed. Install xdotool:', err.message);
}
}
);
}
}

// ── App lifecycle ───────────────────────────────────────────────────────────
Expand Down