XDOTOOL(1)
๐ XDOTOOL(1) ๐
Bestie, welcome to xdotool(1) โ command-line X11 automation tool. She is literally the main character of X11 scripting, no cap.
๐ธ NAME ๐ธ
xdotool โ command-line X11 automation tool. Thatโs the name, thatโs the vibe. Iconic.
โจ SYNOPSIS โจ
xdotool cmd args...
Quick notation check, bestie: some documentation uses [window] to denote an optional window argument. In this case it means the argument, if not present, will default to "%1". See WINDOW STACK for what "%1" means. Iykyk.
๐ฆ DESCRIPTION ๐ฆ
xdotool lets you programmatically (or manually) simulate keyboard input and mouse activity, move and resize windows, etc. It does this using X11's XTEST extension and other Xlib functions. Highkey magical.
There is some support for Extended Window Manager Hints (aka EWMH or NetWM). See the EXTENDED WINDOW MANAGER HINTS section for more information.
๐ KEYBOARD COMMANDS ๐
๐
key [options] keystroke [keystroke ...]
Okay so this is the command that sends keystrokes. Options first:
--window windowโ Send keystrokes to a specific window id. You can use WINDOW STACK references like%1and%@here. If there is a window stack, then%1is the default, otherwise the current window is used.
See also: SENDEVENT NOTES and WINDOW STACK.
--clearmodifiersโ Clear modifiers before sending keystrokes. See CLEARMODIFIERS below.--delay millisecondsโ Delay between keystrokes. Default is12ms.
Type a given keystroke. Examples being alt+r, Control_L+J, ctrl+alt+n, BackSpace.
Generally, any valid X Keysym string will work. Multiple keys are separated by +. Aliases exist for alt, ctrl, shift, super, and meta which all map to Foo_L, such as Alt_L and Control_L, etc.
In cases where your keyboard doesn't actually have the key you want to type, xdotool will automatically find an unused keycode and use that to type the key. Bestie behavior fr fr.
With respect to COMMAND CHAINING, this command consumes the remainder of the arguments or until a new xdotool command is seen, because no xdotool commands are valid keystrokes.
Example: Send the keystroke F2
xdotool key F2
Example: Send 'a' with an accent over it (not on English keyboards, but still works with xdotool)
xdotool key Aacute
Example: Send ctrl+l and then BackSpace as separate keystrokes:
xdotool key ctrl+l BackSpace
Example: Send ctrl+c to all windows matching title 'gdb' (See COMMAND CHAINING)
xdotool search --name gdb key ctrl+c
keydown [options] keystroke
Same as above, except only keydown (press) events are sent. Just the down half of the keystroke energy.
keyup keystroke
Same as above, except only keyup (release) events are sent. Just the release, periodt.
type [options] something to type
Options, bestie:
--window windowidโ Send keystrokes to a specific window id. See SENDEVENT NOTES below. The default, if no window is given, depends on the window stack. If the window stack is empty the current window is typed at using XTEST. Otherwise, the default is"%1"(see WINDOW STACK).--delay millisecondsโ Delay between keystrokes. Default is12ms.--clearmodifiersโ Clear modifiers before sending keystrokes. See CLEARMODIFIERS below.
Types as if you had typed it. Supports newlines and tabs (ASCII newline and tab). Each keystroke is separated by a delay given by the --delay option.
With respect to COMMAND CHAINING, this command consumes the remainder of the arguments and types them. That is, no commands can chain after 'type'.
Example: to type 'Hello world!' you would do:
xdotool type 'Hello world!'
๐ญ MOUSE COMMANDS ๐ญ
mousemove [options] x y OR 'restore'
Move the mouse to the specific X and Y coordinates on the screen. Very demure, very mindful.
You can move the mouse to the previous location if you specify 'restore' instead of an X and Y coordinate. Restoring only works if you have moved previously in this same command invocation. Further, it does not work with the --window option.
For example, to click the top-left corner of the screen and move the mouse to the original position before you moved it, use this:
xdotool mousemove 0 0 click 1 mousemove restore
--window WINDOWโ Specify a window to move relative to. Coordinates0,0are at the top left of the window you choose.
WINDOW STACK references are valid here, such as %1 and %@. Though, using %@ probably doesn't make sense.
--screen SCREENโ Move the mouse to the specified screen to move to. This is only useful if you have multiple screens and ARE NOT using Xinerama.
The default is the current screen. If you specify --window, the --screen flag is ignored.
--polarโ Use polar coordinates. This makesxan angle (in degrees, 0-360, etc) andythe distance.
Rotation starts at 'up' (0 degrees) and rotates clockwise: 90 = right, 180 = down, 270 = left.
The origin defaults to the center of the current screen. If you specify a --window, then the origin is the center of that window.
--clearmodifiersโ See CLEARMODIFIERS.--syncโ After sending the mouse move request, wait until the mouse is actually moved. If no movement is necessary, we will not wait. This is useful for scripts that depend on actions being completed before moving on.
Note: We wait until the mouse moves at all, not necessarily that it actually reaches your intended destination. Some applications lock the mouse cursor to certain regions of the screen, so waiting for any movement is better in the general case than waiting for a specific target.
mousemove_relative [options] x y
Move the mouse x,y pixels relative to the current position of the mouse cursor.
--polarโ Use polar coordinates. This makesxan angle (in degrees, 0-360, etc) andythe distance.
Rotation starts at 'up' (0 degrees) and rotates clockwise: 90 = right, 180 = down, 270 = left.
--syncโ After sending the mouse move request, wait until the mouse is actually moved. If no movement is necessary, we will not wait. This is useful for scripts that depend on actions being completed before moving on.
Note that we wait until the mouse moves at all, not necessarily that it actually reaches your intended destination. Some applications lock the mouse cursor to certain regions of the screen, so waiting for any movement is better in the general case than waiting for a specific target.
--clearmodifiersโ See CLEARMODIFIERS.
click [options] button
Send a click, that is, a mousedown followed by mouseup for the given button with a short delay between the two (currently 12ms).
Buttons generally map this way: Left mouse is 1, middle is 2, right is 3, wheel up is 4, wheel down is 5.
--clearmodifiersโ Clear modifiers before clicking. See CLEARMODIFIERS below.--repeat REPEATโ Specify how many times to click. Default is1. For a double-click, use--repeat 2.--delay MILLISECONDSโ Specify how long, in milliseconds, to delay between clicks. This option is not used if the--repeatflag is set to1(default).--window WINDOWโ Specify a window to send a click to. See SENDEVENT NOTES below for caveats. Uses the current mouse position when generating the event.
The default, if no window is given, depends on the window stack. If the window stack is empty the current window is typed at using XTEST. Otherwise, the default is "%1" (see WINDOW STACK).
mousedown [options] button
Same as click, except only a mouse down is sent.
mouseup [options] button
Same as click, except only a mouse up is sent.
getmouselocation [--shell]
Outputs the x, y, screen, and window id of the mouse cursor. Screen numbers will be nonzero if you have multiple monitors and are not using Xinerama.
This command updates the window stack with the window id of the window directly underneath the mouse. Love that for us.
--shellโ This makesgetmouselocationoutput shell data you caneval.
Example:
% xdotool getmouselocation --shell
X=880
Y=443
SCREEN=0
WINDOW=16777250
% eval $(xdotool getmouselocation --shell)
% echo $X,$Y
714,324
behave_screen_edge [options] where command ...
Bind an action to events when the mouse hits the screen edge or corner. This is lowkey one of the coolest ones, bestie.
Options are:
--delay MILLISECONDSโ Delay in milliseconds before running the command. This allows you to require a given edge or corner to be held for a short period before your command will run. If you leave the edge or corner before the delay expires then the time will reset.--quiesce MILLISECONDSโ Delay in milliseconds before the next command will run. This helps prevent accidentally running your command extra times; especially useful if you have a very short--delay(like the default of0).
โณ Event timeline โณ
- Mouse hits an edge or corner.
- If delay is nonzero, the mouse must stay in this edge or corner until delay time expires.
- If still in the edge/corner, trigger.
- If quiesce is nonzero, then there is a cool-down period where the next trigger cannot occur.
Valid 'where' values are:
lefttop-lefttoptop-rightrightbottom-leftbottombottom-right
Examples:
# Activate google-chrome when you move the mouse to the bottom-left corner:
xdotool behave_screen_edge bottom-left \
search --class google-chrome windowactivate
# Go to the next workspace (right). Known to work in GNOME (metacity and compiz)
xdotool behave_screen_edge --delay 500 bottom-right key XF86Forward
# Activate firefox and do a web search in a new tab for text in your clipboard
xdotool behave_screen_edge --delay 1000 top-left \
search --classname Navigator \
windowactivate --sync key --delay 250 ctrl+t ctrl+k ctrl+v Return
โจ WINDOW COMMANDS โจ
search [options] patternโ bestie this is THE one. It hunts down windows whose titles, names, or classes match a regular expressionpattern, and spits out a line-delimited list of X window identifiers. So like, one window id per line, very demure. ๐ If you're doing COMMAND CHAINING, thesearchcommand will only write window ids to stdout if it's the last (or only) command in the chain โ otherwise it stays silent. Sneaky but iconic.
The result gets saved to the window stack for future chained commands. Peep WINDOW STACK and COMMAND CHAINING for the deets.
Patterns are POSIX extended regular expressions (ERE), e.g. Chrom(e|ium)$ for windows ending in "Chrome" or "Chromium". See regex(7) for syntax details. Matches are case-insensitive โ no cap, it does not care about your caps lock. ๐ซถ
The default options are --name --class --classname --role (unless you specify one or more of --name, --class, --classname, or --role).
The options available are:
--classโ match against the window class.--classnameโ match against the window classname.--roleโ match against the window role.--maxdepth Nโ set the recursion/child search depth. Default is-1, meaning infinite (go off, queen).0means no depth, only root windows will be searched. If you only want toplevel windows, set a maxdepth of1(or2, depending on how your window manager does decorations โ some WMs are extra like that ๐).--nameโ match against the window name. This is the same string that's displayed in the window titlebar.--onlyvisibleโ show only visible windows in the results. That means ones with map stateIsViewable. No ghosts allowed, periodt. ๐ป--pid PIDโ match windows that belong to a specific process id. Ngl this may not work for some X applications that don't set this metadata on their windows โ not their fault, they're just built different.--screen Nโ select windows only on a specific screen. Default is to search all screens. Only meaningful if you have multiple displays and aren't using Xinerama.--desktop Nโ only match windows on a certain desktop. 'N' is a number. The default is to search all desktops.--limit Nโ stop searching after findingNmatching windows. Specifying a limit will help speed up your search if you only want a few results. Speedrun strats fr fr. The default is no search limit (which is equivalent to--limit 0).--titleโ DEPRECATED. See--name. She's retired, let her rest ๐.--allโ require that all conditions be met. For example:
xdotool search --all --pid 1424 --name "Hello World"
This will match only windows that have "Hello World" as a name and are owned by pid 1424.
--anyโ match windows that match any condition (logically, 'or'). This is on by default. For example:
xdotool search --any --pid 1424 --name "Hello World"
This will match any windows owned by pid 1424 or windows with name "Hello World".
--syncโ block until there are results. This is useful when you're launching an application and want to wait until the application window is visible. Like waiting for your friend to finally show up to the plans. For example:
google-chrome &
xdotool search --sync --onlyvisible --class "google-chrome"
selectwindowโ get the window id (for a client) by clicking on it. Super useful for having scripts query you humans for what window to act on (yes, the script needs your opinion, main character energy ๐). For example, killing a window by clicking on it:
xdotool selectwindow windowkill
behave window action command ...โ bind an action to an event on a window. This lets you run additionalxdotoolcommands whenever a matched event occurs. Set it and forget it, the automation slays. โจ
The command run as a result of the behavior is run with %1 being the window that was acted upon. Examples follow after the event list.
The following are valid events:
mouse-enterโ fires when the mouse enters a window. This is similar to 'mouse over' events in javascript, if that helps (it does, it so does).mouse-leaveโ fires when the mouse leaves a window. This is the opposite of 'mouse-enter'. Duh, but we said it nicely. ๐mouse-clickโ fires when the mouse is clicked. Specifically, when the mouse button is released. Precision matters bestie.focusโ fires when the window gets input focus.blurโ fires when the window loses focus.
Examples:
# Print the cursor location whenever the mouse enters a currently-visible
# window:
xdotool search --onlyvisible . behave %@ mouse-enter getmouselocation
# Print the window title and pid whenever an xterm gets focus
xdotool search --class xterm behave %@ focus getwindowname getwindowpid
# Emulate focus-follows-mouse
xdotool search . behave %@ mouse-enter windowfocus
getwindowpid [window]โ output the PID owning a given window. This requires effort from the application owning a window and may not work for all windows. It uses the_NET_WM_PIDproperty of the window. See EXTENDED WINDOW MANAGER HINTS below for more info.
If no window is given, the default is %1. If no windows are on the stack, then this is an error. See WINDOW STACK for more details.
Example: find the PID for all xterms:
xdotool search --class xterm getwindowpid %@
getwindowname [window]โ output the name of a given window, also known as the title. This is the text displayed in the window's titlebar by your window manager. Her government name, if you will. ๐
If no window is given, the default is %1. If no windows are on the stack, then this is an error. See WINDOW STACK for more details.
getwindowgeometry [options] [window]โ output the geometry (location and position) of a window. The values include:x,y,width,height, and screen number. A whole little vibe check for your window. ๐--shellโ output values suitable for 'eval' in a shell. Fancy.
getwindowfocus [-f]โ prints the window id of the currently focused window. Saves the result to the window stack. See WINDOW STACK for more details.
If the current window has no WM_CLASS property, we assume it's not a normal top-level window and traverse up the parents until we find a window with a WM_CLASS set and return that window id. It's giving "we asked around the friend group until someone knew." ๐ญ
If you really want the window currently having focus and don't care if it has a WM_CLASS setting, then use getwindowfocus -f.
windowsize [options] [window] width heightโ set the window size of the given window. If no window is given,%1is the default. See WINDOW STACK and COMMAND CHAINING for more details.
Percentages are valid for width and height. They are relative to the geometry of the screen the window is on. For example, to make a window the full width of the screen, but half height:
xdotool windowsize <window> 100% 50%
Percentages are valid with --usehints and still mean pixel-width relative to the screen size. Yes, even then. Don't overthink it. ๐ง
The options available are:
--usehintsโ use window sizing hints (when available) to set width and height. This is useful on terminals for setting the size based on row/column of text rather than pixels. Text-mode girlies rise up. ๐--syncโ after sending the window size request, wait until the window is actually resized. If no change is necessary, we will not wait. This is useful for scripts that depend on actions being completed before moving on.
Note: because many window managers may ignore or alter the original resize request, we will wait until the size changes from its original size, not necessary to the requested size. So like, we're watching for a change, not the change. Big difference, no cap.
Example: to set a terminal to be 80x24 characters, you would use:
xdotool windowsize --usehints <some_windowid> 80 24
windowmove [options] [window] x yโ move the window to the given position. If no window is given,%1is the default. See WINDOW STACK and COMMAND CHAINING for more details.
If the given x coordinate is literally x, then the window's current x position will be unchanged. The same applies for y. Iconic little stay-in-your-lane behavior. ๐
Examples:
xdotool getactivewindow windowmove 100 100 # Moves to 100,100
xdotool getactivewindow windowmove x 100 # Moves to x,100
xdotool getactivewindow windowmove 100 y # Moves to 100,y
xdotool getactivewindow windowmove 100 y # Moves to 100,y
Percentages are valid for width and height. They are relative to the geometry of the screen the window is on. For example, to make a window the full width of the screen, but half height:
xdotool windowmove <window> 100% 50%
--syncโ after sending the window move request, wait until the window is actually moved. If no movement is necessary, we will not wait. This is useful for scripts that depend on actions being completed before moving on.--relativeโ make movement relative to the current window position. So like, nudge nudge instead of teleport. ๐ฆ
windowfocus [options] [window]โ focus a window. If no window is given,%1is the default. See WINDOW STACK and COMMAND CHAINING for more details.
Uses XSetInputFocus which may be ignored by some window managers or programs. Rude of them, but okay. ๐
--syncโ after sending the window focus request, wait until the window is actually focused. This is useful for scripts that depend on actions being completed before moving on.
windowmap [options] [window]โ map a window. In X11 terminology, mapping a window means making it visible on the screen. If no window is given,%1is the default. See WINDOW STACK and COMMAND CHAINING for more details. She has arrived. ๐--syncโ after requesting the window map, wait until the window is actually mapped (visible). This is useful for scripts that depend on actions being completed before moving on.
windowminimize [options] [window]โ minimize a window. In X11 terminology, this is called 'iconify.' If no window is given,%1is the default. See WINDOW STACK and COMMAND CHAINING for more details. Go to sleep bestie, you've done enough. ๐ด--syncโ after requesting the window minimize, wait until the window is actually minimized. This is useful for scripts that depend on actions being completed before moving on.
windowraise [window_id=%1]โ raise the window to the top of the stack. This may not work on all window managers. If no window is given,%1is the default. See WINDOW STACK and COMMAND CHAINING for more details. Main character moment: she's in front now. ๐windowlower [window_id=%1]โ lower the window to the bottom of the stack. This may not work on all window managers. If no window is given,%1is the default. See WINDOW STACK and COMMAND CHAINING for more details. Background character era, respectfully. ๐ซถwindowreparent [source_window] destination_windowโ Okay so this one literally moves a whole window into another window ๐ช. It takes source_window and makes it a child window of destination_window. No source given?%1is your default bestie. And here's the slay part: "WINDOW STACK" window references (like%1) are valid for both source_window and destination_window. Peep "WINDOW STACK" and "COMMAND CHAINING" for the full lore โจ.windowclose [window]โ Closes a window ๐. This destroys the window itself but does not try to kill the client controlling it โ so the app can keep living its truth. No window given?%1is the default. See "WINDOW STACK" and "COMMAND CHAINING" ๐ซถ.windowquit [window]โ The polite version ๐. Closes a window gracefully by sending a request, which lets the application do its close-confirmation thing (you know, the "are u sure bestie" popup). No window given?%1is the default. See "WINDOW STACK" and "COMMAND CHAINING" ๐.windowkill [window]โ No thoughts, just violence ๐ฅ. This destroys the window and kills the client controlling it. Rude, but sometimes necessary. No window given?%1is the default. See WINDOW STACK and "COMMAND CHAINING".windowunmap [options] [window_id=%1]โ Unmaps a window, which means it's no longer showing up on your screen ๐ซ๏ธ. It's still there, just not visible, main-character-invisible mode. No window given?%1is the default. See "WINDOW STACK" and "COMMAND CHAINING".--syncโ After requesting the window unmap, it waits until the window is actually unmapped (hidden). Iconic for scripts that depend on actions being completed before moving on โณ.
set_window [options] [windowid=%1]โ Sets properties about a window ๐จ. No window given?%1is the default. See "WINDOW STACK" and "COMMAND CHAINING".
Options, bestie:
--name newnameโ Sets the windowWM_NAME(that's the window title, usually ๐ ).--icon-name newiconnameโ Sets the windowWM_ICON_NAME(the window title when minimized, usually).--role newroleโ Sets the windowWM_WINDOW_ROLE.--classname newclassnameโ Sets the window class name. Do not confuse it with window class, they're different girlies, iykyk ๐.--class newclassโ Sets the window class. Again, not to be confused with window class name ๐.--urgency valueโ Sets the window urgency hint. If the value is1, the window gets marked urgent and the window manager will somehow highlight it to grab the user's attention ๐จ. If the value is0, the window gets marked non-urgent ๐.--overrideredirect valueโ Sets the window'soverride_redirectvalue. This is a hint to the window manager about whether it should be managed at all. If the redirect value is0, the window manager draws borders and treats the window normally ๐. If the value is1, the window manager straight-up ignores the window ๐.
Fr fr: if you change this value, your window manager may not notice the change until the window is mapped again. So you probably wanna issuewindowunmapandwindowmapto make the window manager take note ๐.
๐ DESKTOP AND WINDOW COMMANDS ๐
These commands follow the EWMH standard. See the section "EXTENDED WINDOW MANAGER HINTS" for more info, bestie ๐ง.
windowactivate [options] [window]โ Activates the window โจ. This is not the same aswindowfocus: if the window is chilling on another desktop, we will switch to that desktop for you ๐ฅ๏ธ. It also uses a different method for bringing the window up. Genuine rec: try this command before usingwindowfocus, because it will work on more window managers ๐ .
If no window is given, %1 is the default. See "WINDOW STACK" and "COMMAND CHAINING" for more deets.
--syncโ After sending the window activation, wait until the window is actually activated. Perfect for scripts that depend on actions being completed before moving on โณ.
getactivewindowโ Outputs the current active window ๐. This command is often more reliable thangetwindowfocus. The result is saved to the window stack โ see "WINDOW STACK" for the details ๐ซถ.windowstate [--add PROPERTY] [--remove PROPERTY] [--toggle PROPERTY] [window]โ Changes a property on a window ๐ง.
Heads up: some properties may have no effect on some windows, or in some window managers. Not every WM is on the same wavelength ๐ญ.
Properties can be any of:
MODALโ makes the window into a modalSTICKYโ makes the window appear on all workspacesMAXIMIZED_VERTโ sizes the window maximized verticallyMAXIMIZED_HORZโ sizes the window maximized horizontallyABOVEโ Show window above all others (always on top)BELOWโ Show window below all othersSKIP_TASKBARโ hides the window from the taskbarSKIP_PAGERโ hides the window from the window pagerFULLSCREENโ makes window fullscreenHIDDENโ unmaps the windowSHADEDโ rolls the window upDEMANDS_ATTENTIONโ marks window urgent or needing attention
This feature requires a window manager which supports EWMH. Most window managers probably support this :)
getwindowclassname [window]โ Prints the class name for the window ๐ท๏ธ.set_num_desktops numberโ Changes the number of desktops or workspaces ๐ข.get_num_desktopsโ Outputs the current number of desktops.get_desktop_viewport [--shell]โ Reports the current viewport's position ๐. If--shellis given, the output is friendly to shell eval ๐.
Viewports are sometimes used instead of 'virtual desktops' on some window managers. A viewport is simply a view on a very large desktop area, no cap.
set_desktop_viewport x yโ Moves the viewport to the given position ๐ธ. Not all requests will be obeyed โ some window managers only obey requests that align to workspace boundaries, such as the screen size. So like, don't take it personally ๐.
For example, if your screen is 1280x800, you can move to the 2nd workspace by doing:
xdotool set_desktop_viewport 1280 0
set_desktop [options] desktop_numberโ Changes the current view to the specified desktop ๐ป.--relativeโ Use relative movements instead of absolute. This lets you move relative to the current desktop.
Examples:
# Change to desktop #5
xdotool set_desktop 5
# Change to the previous desktop. (Note the use of "--")
xdotool set_desktop --relative -- -1
get_desktopโ Outputs the current desktop in view ๐๏ธ.set_desktop_for_window [window] desktop_numberโ Moves a window to a different desktop ๐. If no window is given,%1is the default. See "WINDOW STACK" and "COMMAND CHAINING" for more details.get_desktop_for_window [window]โ Outputs the desktop currently containing the given window. Move a window to a different desktop. If no window is given,%1is the default. See WINDOW STACK and "COMMAND CHAINING" for more details ๐.
๐ MISCELLANEOUS COMMANDS ๐
exec [options] command [...]โ Executes a program ๐. This is often super useful when combined withbehave_screen_edgeto do things like locking your screen ๐.
Options:
--syncโ Blocks until the child process exits. The child process exit status is then passed to the parent process (xdotool), which copies it ๐.
Examples:
# Lock the screen when the mouse sits in the top-right corner
xdotool behave_screen_edge --delay 1000 top-right \
exec gnome-screensaver-command --lock
# Substitute 'xscreensaver-command -lock' if you use that program.
# The following will fail to move the mouse because we use '--sync' and
# /bin/false exits nonzero:
xdotool exec --sync /bin/false mousemove 0 0
# This succeeds, though, since we do not use --sync on the exec command.
xdotool exec /bin/false mousemove 0 0
sleep secondsโ Sleeps for a specified period ๐ด. Fractions of seconds (like1.3, or0.4) are valid here, periodt โฑ๏ธ.
๐ฆ SCRIPTS ๐ฆ
xdotool can read a list of commands via stdin or a file if you want ๐. A script will fail when any command fails โ no silent failures, we don't do that here ๐
.
Truthfully, 'script' mode isn't fully fleshed out and may fall below your expectations ๐ฌ. If you have suggestions, please email the list or file a bug (See CONTACT) โ feedback is a love language ๐ซถ.
Scripts can use positional arguments (Represented by $1, $2, ...) and environment variables (like $HOME or $WINDOWID). Quoting arguments should work as expected โจ.
Scripts are processed for parameter and environment variable expansion and then run as if you had invoked xdotool with the entire script on one line (using COMMAND CHAINING).
- Read commands from a file:
xdotool filename
- Read commands from stdin:
xdotool -
- Read commands from a redirected file:
xdotool - < myfile
You can also write scripts that only execute xdotool. Example:
#!/usr/local/bin/xdotool
search --onlyvisible --classname $1
windowsize %@ $2 $3
windowraise %@
windowmove %1 0 0
windowmove %2 $2 0
windowmove %3 0 $3
windowmove %4 $2 $3
This script will take all windows matched by the classname query given by arg1 ($1) and sizes/moves them into a 2x2 grid with windows sized by the 2nd and 3rd parameters ๐ฒ๐ฒ.
Here's an example usage:
% ./myscript xterm 600 400
Running it like this will take 4 visible xterms, raise them, and move them into a 2x2 tile grid with each window 600x400 pixels in size. Iconic behavior honestly ๐.
๐ CLEARMODIFIERS ๐
Any command taking the --clearmodifiers flag will attempt to clear any active input modifiers during the command and restore them afterwards ๐งน.
For example, if you were to run this command:
xdotool key a
The result would be a or A depending on whether or not you were holding the shift key on your keyboard ๐ญ. Often it is undesirable to have any modifiers active, so you can tell xdotool to clear any active modifiers. So thoughtful fr fr ๐.
The order of operations if you hold shift while running xdotool key --clearmodifiers a is this:
- Query for all active modifiers (finds shift, in this case)
- Try to clear shift by sending 'key up' for the shift key
- Runs normal
xdotool key a - Restore shift key by sending 'key down' for shift
The --clearmodifiers flag can currently clear of the following:
- any key in your active keymap that has a modifier associated with it. (See
xmodmap(1)'sxmodmap -pmoutput) - mouse buttons (1, 2, 3, 4, and 5)
- caps lock
๐ฅ SENDEVENT NOTES ๐ฅ
okay bestie, this is the part where we talk about the โจfamousโจ "why is my typing not going anywhere" problem. Listen up ๐
So โ if you're trying to send key input to a specific window and it's justโฆ not working? It's probably not you. It's lowkey your app ignoring the events xdotool is generating. This is fairly common, ngl. ๐
Here's the tea ๐: sending keystrokes to a specific window uses a different API than just typing to the active window. Like, if you specify xdotool type --window 12345 hello, xdotool will generate key events and send them directly to window 12345. But โ and this is the plot twist โ X11 servers set a special flag on all events generated this way (see XEvent.xany.send_event in X11's manual). And lots of programs observe that flag and reject those events. Rude, honestly. ๐ญ
Key thing to remember, no cap: for key and mouse events, we only use XSendEvent when a specific window is targeted. Otherwise, we use XTEST. Periodt.
Some programs can be configured to accept events even if they're generated by xdotool โ so go read the docs of your app, bestie ๐ซถ
Specific application notes (from the author's testing, iykyk):
- Firefox 3 seems to ignore all input when it does not have focus.
- xterm can be configured while running with ctrl+leftclick, 'Allow SendEvents'
- gnome-terminal appears to accept generated input by default.
๐ช WINDOW STACK ๐ช
Certain commands (search, getactivewindow, getwindowfocus) will find windows for you โจ. These results are generally printed to stdout, but they're also saved to memory for future use during the lifetime of the xdotool process. See "COMMAND CHAINING" for more info ๐
Now, the only modification supported for the window stack is to replace it. Like, that's it. That's the whole feature. So if you run two sequential searches, only the last one's results will be the window stack. Sorry babes ๐
โ๏ธ COMMAND CHAINING โ๏ธ
xdotool supports running multiple commands on a single invocation ๐ Generally you'll start with a search command (peep "WINDOW STACK") and then perform a set of actions on those results.
To query the window stack, you can use the special notation %N where N is a number or the @ symbol. If %N is given, the Nth window will be selected from the window stack. Generally you'll only want the first window or all the windows ๐
Note that the order of windows in the window stack corresponds to the window stacking order, i.e. the bottom-most window will be reported first (see XQueryTree(3)). So yeah โ the order of the windows in the window stack may not be consistent across invocations. Vibe check your expectations accordingly ๐ธ
The notation described above is used as the window argument for any given command.
For example, to resize all xterms to 80x24:
xdotool search --class xterm -- windowsize --usehints %@ 80 24
Resize move the current window:
xdotool getactivewindow windowmove 0 0
In all cases, the default window argument, if omitted, will default to "%1". It is obviously an error if you omit the window argument and the window stack is empty ๐จ And if you try to use the window stack and it's empty, that's also an error. Double error. Maximum chaos. ๐ค
To activate the first firefox window found:
xdotool search --class firefox windowactivate
These would error:
xdotool windowactivate
xdotool windowactivate %1
xdotool windowactivate %@
When xdotool exits, the current window stack is lost. Gone. Poof. ๐ฆ
Also! Commands that modify the "WINDOW STACK" will not print the results if they are not the last command. For example:
# Output the active window:
% xdotool getactivewindow
20971533
# Output the pid of the active window, but not the active window id:
% xdotool getactivewindow getwindowpid
4686
๐๏ธ EXTENDED WINDOW MANAGER HINTS ๐๏ธ
The following pieces of the EWMH standard are supported, bestie โ this is the alphabet soup section, but it slaps ๐
_NET_SUPPORTED
Asks the window manager what is supported.
_NET_CURRENT_DESKTOP
Query and set the current desktop. Support for this enables these commands: set_desktop, get_desktop.
_NET_WM_DESKTOP
Query and set what desktop a window is living in. Support for this enables these commands: set_desktop_for_window, get_desktop_for_window.
_NET_ACTIVE_WINDOW
Allows you to query and set the active window by asking the window manager to bring it forward. Support for this enables these commands: windowactivate, getactivewindow.
_NET_WM_PID
This feature is application dependent, not window-manager dependent. Query the PID owning a given window. Support for this enables these commands: getwindowpid.
โจ SUPPORTED FEATURES โจ
xdotool (and libxdo) will try to function under all circumstances ๐ช. However, there may be some cases where functionality is justโฆ not provided by your X server or by your window manager. In these cases, xdotool will try to detect that and tell you if an action requires a feature that isn't currently supported by your system. Iconic behavior, honestly ๐
For window-manager specific features, see "EXTENDED WINDOW MANAGER HINTS".
XTEST
If your X server does not support XTEST, then some typing and mouse movement features may not work ๐ฌ Specifically, typing and mouse actions that act on the "current window" (window 0 in libxdo) are unlikely to work.
In most cases, XTEST is a feature you can enable on your X server if it isn't enabled by default.
You can see the list of supported X extensions by typing xdpyinfo and looking for the text number of extensions: ... ๐
๐ BUGS ๐
Typing unusual symbols under non-us keybindings is known to occasionally send the wrong character. That's it. That's the bug. It happens, we know, we're working on the vibe ๐
๐ SEE ALSO ๐
Project site: <http://www.semicomplete.com/projects/xdotool>
Source code and Issues: <https://github.com/jordansissel/xdotool>
EWMH specification: <http://standards.freedesktop.org/wm-spec/wm-spec-1.3.html>
๐ซถ CONTACT ๐ซถ
Please send questions to xdotool-users@googlegroups.com. File bugs and feature requests at the following URL:
<https://github.com/jordansissel/xdotool/issues>
Alternately, if you prefer email, feel free to file bugs by emailing the list. What works for you :) ๐
๐ AUTHOR ๐
xdotool was written by Jordan Sissel.
This manual page was written originally by Daniel Kahn Gillmor <dkg@fifthhorseman.net> for the Debian project (but may be used by others). It is maintained by Jordan Sissel.
Patches, ideas, and other contributions by many, nice folks. See the CHANGELIST file for who provided what ๐
okay that's the whole page bestie, we did it ๐ this one's the XDOTOOL(1) manual, dated 2026-03-04 โ and that's the footer, so consider it mentioned with love ๐ go forth and windowactivate responsibly, mwah ๐งโจ
๐ฆ where this page comes from
- alpine 3.24: xdotool-doc 4.20260303.1-r0 ยท BSD-3-Clause
- ๐ girlified by deepseek-ai/DeepSeek-V4.1-Flash-1017 on : a language model's rewrite of the original, under its terms