LINUX.ORG.RU

Получить координаты курсора, не испортив stdin

 


1

1

При помощи эскейп-кода \e[6n можно запросить координаты курсора у терминала и получить ответ в stdin. Готовый скрипт для этого можно взять тут.

Но такой способ плох тем, что портит stdin. Например, если вставить в терминал из буфера обмена

./get_cursor_position.sh
echo всё хорошо
, то всё сломается. Как быть?

#!/bin/bash

function f() {
    # Read it to a variable
    read -d R CURCOL

    # Extract the column from the variable
    CURCOL="${CURCOL##*;}"

    # We have the column in the variable
    echo $CURCOL
}

# Query the cursor position
echo -en '\033[6n' | f
anonymous
()

Если средствами баша, то никак. На самом деле команда '\e[6n' возвращает

the cursor position (CPR) to the application as (as though typed at the keyboard) ESC[n;mR

То есть после копирования

./get_cursor_position.sh
echo всё хорошо

у тебя считывается со стандартного ввода первая строка и выполняется. При выполнении она в конец стандартного ввода добавляет заветное 'ESC[n;mR', то есть stdin уже испорчен и в нём теперь находится

echo всё хорошо
ESC[n;mR

После чего выполняется команда 'read -d R VAR' которая считывает стандартный ввод вплоть до первого символа R, то есть полностью проглатывая 'echo всё хорошо'.

Эта проблема не специфична для получения координат курсора, а связана с любой обработкой ввода. Так если ты скопируешь себе в терминал такой текст:

read -d`echo -ne '\r'` N
qwerk
echo $N

то получишь такой вывод:

$ read -d`echo -ne '\r'` N
$ echo $N
qwerk
$

Возможный вариант костыльного обхода в твоём случае будет выглядеть так:

# Query the cursor position
echo -en '\033[6n'

# Read commands that come to stdin before cursor position
read -d`echo -ne '\e'` COMMANDS

# Read it to a variable
read -d R CURCOL

# Extract the column from the variable
CURCOL="${CURCOL##*;}"

# We have the column in the variable
echo $CURCOL

eval `echo -n $COMMANDS | sed 's,\r,;,g; s,;\+,;,g'`
kim-roader ★★
()
Ответ на: комментарий от kim-roader

Я понимаю, почему так происходит. А предложенный вариант покрывает только частный случай.

Возможно, какие-нибудь эмуляторы терминала позволяют сделать это не через stdin/stdout (например, через сокет).

NeXTSTEP ★★
() автор топика
Ответ на: комментарий от NeXTSTEP

Ну да, но то что ты хочешь тем способом как ты хочешь получить всё равно невозможно, без переработки кишок.

kim-roader ★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.