Pane interaction
Send input to a pane and capture its screen to interact with a running program. Attach and send keys provides examples. Sending keys and Capturing output are task guides; this page covers input defaults, capture ranges, and completion handling.
Typing into a pane¶
Two questions come up every time you send something to a pane: should tmux
press Enter afterward, and should tmux interpret what you sent as key names
(Enter, C-c) rather than literal characters? Choose both explicitly when
a command depends on them.
Python¶
Type without Enter: pane.send_keys(text, enter=False)
Type + Enter (default): pane.send_keys(text)
How "literal" is chosen: literal=True flag on the same method
TypeScript¶
Type without Enter: pane.sendKeys(text, { enter: false })
Type + Enter (default): pane.sendKeys(text)
How "literal" is chosen: { literal: true } option
Go¶
Type without Enter: pane.SendKeys(ctx, SendKeysRequest{Command: &text, SkipEnter: true})
Type + Enter (default): pane.SendKeys(ctx, SendKeysRequest{Command: &text})
How "literal" is chosen: Literal: true field
Rust¶
Type without Enter: pane.send_keys(keys): always literal, key names
typed as text
Type + Enter (default): pane.send_line(text)
How "literal" is chosen: send_keys sends literal text; send_key_names
interprets tmux key names.
Java¶
Type without Enter: pane.send(keys)
Type + Enter (default): pane.sendLine(command)
How "literal" is chosen: Separate text and key-sending methods.
C#¶
Type without Enter: SendKeysAsync(new SendKeysRequest(text, enter: false))
Type + Enter (default): SendTextAsync(text) (defaults enter: true)
How "literal" is chosen: SendKeysRequest.Literal field;
SendTextAsync hardcodes it
C++¶
Type without Enter: pane->send_text(text)
Type + Enter: pane->send_text(text) then pane->send_key("Enter")
separately: no combined convenience exists
How "literal" is chosen: send_text is always literal; send_key is always
a key name
Swift¶
Type without Enter: server.sendKeys([text], to: pane)
Type + Enter (default): server.run(text, in: pane) (sugar for
sendKeys([text, "Enter"], to: pane))
How "literal" is chosen: literally: true option on sendKeys
Examples¶
send_keys sends literal text. Use send_key_names for tmux key names.
Passing "Enter" to send_keys types those characters. send_line appends a
carriage return and delivers it with the text in one tmux command.
sendLine appends a carriage return and delivers it with the text in one tmux
command.
Text and Enter can be separate tmux commands. If the second operation fails, the text may already be in the pane. Check the current state before retrying; repeating the whole request can duplicate input.
Send a command line and press Enter:
pane.send_keys("echo hi", enter=False) # type without pressing Enterpane.send_keys("echo hi") # default: presses Enter afterwardawait pane.sendKeys("echo hi", { enter: false });await pane.sendKeys("echo hi");text := "printf 'hello\\n'"if err := pane.SendKeys(ctx, tmux.SendKeysRequest{ Command: &text, Literal: true,}); err != nil { return fmt.Errorf("send command: %w", err)}pane.send_keys("echo hi").await?; // Always literal text.pane.send_line("echo hi").await?; // text and Enter in one send-keys -l callpane.send("echo hi"); // no Enterpane.sendLine("echo hi"); // text and \r in one send-keys -l callawait pane.SendKeysAsync(new SendKeysRequest("echo hi", enter: false));await pane.SendTextAsync("echo hi"); // defaults enter: truepane->send_text("echo hi");pane->send_key("Enter"); // separate command: no combined convenience existstry await server.sendKeys(["echo hi"], to: pane) // no Entertry await server.run("echo hi", in: pane) // sugar for sendKeys([text, "Enter"])Reading a pane back¶
Capture reads the pane's visible screen by default. Request scrollback when you need earlier output. A capture is a snapshot of terminal contents, including any input echoed by the application.
pane.Capture returns ([]string, error). Pass a context.Context with a
deadline and check the error before using the result. Set the start boundary to
tmux.CaptureBoundary to include scrollback. End: tmux.CaptureBoundary
includes the bottom of the visible pane.
pane.capture_pane()await pane.capture();lines, err := pane.Capture(ctx, tmux.CapturePaneRequest{})if err != nil { return fmt.Errorf("capture pane: %w", err)}for _, line := range lines { fmt.Println(line)}pane.capture().await?;pane.capture();await pane.CaptureAsync();pane->capture();try await server.capture(pane)Waiting for something to finish¶
A send call completes when input reaches tmux. It does not wait for the shell command to finish. Wait for expected output or a completion signal.
Poll capture output for a marker or use the wait_for signal channel when you
control the command. The test-support module provides
libtmux.test.retry_until(condition, ...) for arbitrary conditions.
server.waitForOutput(...) waits for a pattern in pane output and returns an
OutputWait. Give the wait a timeout.
Use server.WaitFor with a WaitForRequest when the command can signal tmux's
wait-for channel. For streaming output, open pane.OpenObservation(ctx)
before sending input so the observation includes the command's first bytes.
Both paths take a context; cancellation bounds how long the caller waits.
For a new command whose exit status matters, use session.Run and inspect its
result. Capturing screen text alone cannot establish the command's exit status.
Use TmuxWaitChannel when the command can signal a named tmux wait-for
channel. Use a cancellation token to bound the wait.
Capture pane output shows capture and waiting examples. Waiting and retrying explains completion conditions and timeouts.
tmux manual and source
The tmux manual defines key-name and literal input and screen and history capture. A send operation delivers input; it does not establish the program's exit status.