LINUX.ORG.RU

mc подвисает, если запускать его внутри tmux в консоли Linux (багрепорт и патч)

 , ,


1

5

Здрасти.

Имеем следующий сетап:

Консоль Linux. Запущен демон gpm. Запущен tmux. Внутри tmux мы запускаем mc.

Баг: при обработке ввода mc рандомно подвисает. Например, нажимаем три раза стрелку вниз. Первые два раза ничего не происходит на экране (приложение не обновляет интерфейс). На третье нажатие отрабатывают все три.

Общей закономерности не просматривается. Бывает, нажатия доходят сразу. Бывает, доходит только пачка из 2, 3 или даже 4 нажатий.

В других сетапах баг не проявляется.

Если запускать mc с ключами -d или -x, баг тоже не проявляется.

Я покопал исходники, и вот что накопал.

Переменная use_mouse_p может принимать следующие значения: MOUSE_NONE, MOUSE_DISABLED, MOUSE_GPM, MOUSE_XTERM_NORMAL_TRACKING, MOUSE_XTERM_BUTTON_EVENT_TRACKING. При запуске программы она инициализирована значением MOUSE_NONE.

Если мы указываем ключ -d, она переинициализируется значением MOUSE_DISABLED. Если мы указываем ключ -x, mc считает, что имеет дело с xterm, и переинициализирует её одним из значений MOUSE_XTERM_*.

Затем в функции init_mouse() производится проверка значения. Если значение равно MOUSE_NONE, оно заменяется на MOUSE_GPM.

Затем в enable_mouse(), если use_mouse_p == MOUSE_GPM, производится установка соединения с gpm. Таким образом, mc пытается использовать мышь gpm, будучи запущенным из-под псевдотерминала (что бессмысленно).

Подвисание при обработке ввода происходит где-то в tty_get_event() или в is_idle() — я не разбирался, в чём именно проблема. На поверхностный взгляд, всё выглядит нормально. Возможно, баги находятся в библиотеке gpm. (Учитывая, каким говнокодом она написана, это наиболее вероятно.)

Как бы то ни было, на мой взгляд, некорректно пытаться использовать gpm из псевдотерминала. Прежде чем устанавливать соединение с gpm, следует проверить, работаем ли мы в виртуальном терминале Linux или в псевдотерминале pts.

Также, я думаю, что проверка переменной TERM не является правильным вариантом решения. TERM указывает на возможности терминала и понимаемые им коды, а gpm не является фичей терминала, это отдельный демон с отдельным API. Проверка значения ttyname() представляется более правильным решением. Если ttyname() возвращает имя вида /dev/tty*, использование gpm имеет смысл. Иначе — не имеет.

Я внёс следующие исправления в функцию init_mouse:

diff --git a/lib/tty/mouse.c b/lib/tty/mouse.c
index 511f2dd..060480a 100644
--- a/lib/tty/mouse.c
+++ b/lib/tty/mouse.c
@@ -84,8 +84,15 @@ init_mouse (void)
     {
 #ifdef HAVE_LIBGPM
     case MOUSE_NONE:
-        use_mouse_p = MOUSE_GPM;
-        break;
+        {
+            char tname[64];
+            if (ttyname_r(0, tname, sizeof(tname)/sizeof(tname[0])) == 0 &&
+                strncmp(tname, "/dev/tty", sizeof("/dev/tty") - 1) == 0) /* check if stdin is a linux virtual terminal */
+            {
+                use_mouse_p = MOUSE_GPM;
+            }
+            break;
+        }
 #endif /* HAVE_LIBGPM */
 
     case MOUSE_XTERM_NORMAL_TRACKING:

После этого изменения баг не воспроизводится.

cast angel_il, Slavaz

Deleted

Вот он идеальный пост во всех отношениях. Учитесь, горе-линуксоиды. Зафрендил.

sizeof(tname)/sizeof(tname[0])

Можно просто sizeof(tname), по стандарту sizeof(char) всегда равен единице.

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

Можно просто sizeof(tname), по стандарту sizeof(char) всегда равен единице.

Привычка. :)) «Не забудь разделить на sizeof(x[0])» въелось в мозг.

Deleted
()

Ну вот, а я делал

set -g default-terminal "xterm"

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

Насколько я знаю, этот баг очень древний.

Я недавно встретился с ним на новом ноуте. Но уже не могу вспомнить, не встречал его раньше или пофиксил строчкой в конфиге и забыл)

С точки зрения идеологии, пользоваться мышью в чистоконсоли, конечно, не тру, но tmux умеет работать с gpm, поэтому практически mc тоже должен уметь с ней работать.

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

но tmux умеет работать с gpm

tmux не умеет работать с gpm. Это вообще утилита из мира BSD, она про местные костыли не в курсе.

То, что приложения «должны работать gpm» — это сломанный дизайн.

Mouse reporting-ом (который включается последовательностью ESC [?1000h ) должен заниматься модуль ядра, отвечающий за терминал. Именно так это сделано в FreeBSD, например. Именно так это и задумывалось изначально в linux, насколько я могу судить. Но фича сломана, и всем пофиг.

Поэтому приложения вынуждены обрастать костылями, линкуясь с libgpm и сосать лапу.

С точки зрения идеологии, пользоваться мышью в чистоконсоли, конечно, не тру

*повертел пальцем у виска*

Deleted
()
Ответ на: комментарий от Deleted

Не пофиг

В linux 2.0 drivers/char/console были:

oid mouse_report(struct tty_struct * tty, int butt, int mrx, int mry)
int mouse_reporting(void)
И я даже пользовался этим функционалом. Правда программа реагировала только на нвжвтия мыши, Перетащить что-то при нажатой клавише было невозможно. Какие ESC-коды должно слать ядро в таком случае?

PS: В текущих ядрах этот функционал остался (drivers/tty/vt/vt.c) Неужели перестало работать? Попробую проверить...

seyko2
()
Ответ на: Не пофиг от seyko2

Какие ESC-коды должно слать ядро в таком случае?

При включенном режиме 1000, ESC [M <action+32> <x+32> <y+32>

Вот тут есть описание: https://www.midnight-commander.org/ticket/2662

Неужели перестало работать?

Да, не работает. Набираю в cat ручками включение 1000-и. Ноль реакции.

Если тебе интересно починить эту фичу, можно скооперироваться. Я тут сижу рефакторю gpm. Ну вернее как рефакторю... удаляю целые страницы кода, а оставшееся переписываю в 3 раза короче и понятнее. Эту свалку старья из середины 90-х надо бы привести в человеческий вид.

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

Deleted
()
Ответ на: комментарий от Deleted

как появится время

Да, не работает. Набираю в cat ручками включение 1000-и. Ноль реакции.Если тебе интересно починить эту фичу, можно скооперироваться

Я для начала пытаюсь собрать программу, которая этой фичей пользовалась (клон TurboVision). Сейчас качаю Slackware 8.0, ибо для сборки нужен g++-2.95 (новые ругаются на синтаксис). Насколько я помню, эта фича использовалась для работы из-под MC. А так gpm более удобен.

Другие патчи, сделанные для ядра тогда были: -- чтоб можно было мышью выделять прямоугольные области экрвна. -- чтоб можно было выводить все символы фонта в диапазоне 0..255 -- экранный индикатор раскладки клавиатуры (цвет окантовки) Но их не приняли ;-)

Я тут сижу рефакторю gpm

Герой! Нужная работа. Там много лишнего. Только бы не поломать нужное.

Да, мне тоже нравится tmux. Только пока поизучать его никак не получается.

seyko2
()
Ответ на: как появится время от seyko2

Я для начала пытаюсь собрать программу, которая этой фичей пользовалась (клон TurboVision).

Эээ. Зачем? Простой тестовый скрипт, который отображает координаты щелчков в человекочитаемом виде:

#!/bin/sh

getc()
{
    stty raw
    dd bs=1 count=1 2>/dev/null
    stty cooked
}

handle_mouse()
{
	local c
	c="`getc`"
	[ "$c" = "[" ] || return
	c="`getc`"
	[ "$c" = "M" ] || return
	b="`getc`"
	x="`getc`"
	y="`getc`"
	b=`printf "%d" "'$b"`
	x=`printf "%d" "'$x"`
	y=`printf "%d" "'$y"`
	b=$(($b - 32))
	x=$(($x - 32))
	y=$(($y - 32))
	echo "$b $x $y"
}

stty -echo
printf '\033[?1000h'
ESC="`printf '\033'`"
while true ; do
	c="`getc`"
	if [ "$c" = "$ESC" ] ; then
		handle_mouse
	fi
	if [ "$c" = "q" ] ; then
		break
	fi
done
printf '\033[?1000l'
stty echo
echo

Я тут подумал. Ядро через TIOCLINUX-чего-то-там умеет сообщать, выставлен ли на терминале mouse reporting или нет. Можно воспользоваться этим знанием и послать координаты мыши в приложение прямо из gpm, без необходимости патчить ядро.

Посылать байты из gpm можно при помощи TIOCSTI.

Но с этим есть проблема: race condition. Если одновременно ядро отправляет в терминал мультибайтовую последовательность (UTF8-символ или ESC-код), и мы отправляем, получится винегрет.

Deleted
()
Ответ на: комментарий от Deleted

Я тут сижу рефакторю gpm. Ну вернее как рефакторю... удаляю целые страницы кода, а оставшееся переписываю в 3 раза короче и понятнее. Эту свалку старья из середины 90-х надо бы привести в человеческий вид.

Эм... Есть ещё какой-то gpm2: http://www.nico.schottelius.org/software/gpm2/ Он как, хуже/лучше gpm?

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

Он как, хуже/лучше gpm?

Он брошен. Последнее обновление 4 года назад.

* Support multiple mice
* Do not draw stuff, but write gpm2 client to do so (os/terminal specific stuff)
* Usable under different OS
* Modular design, easy way to add new mice protocols
* Allow hotplugging of mice (i.e. gpm2d can run without any mice at startup)

И автор ударился в оверинженеринг. Какие еще разные протоколы? Какая поддержка разных ОС? Это чисто линуксовый демон, который должен читать /dev/input/mice и отправлять сообщения. Всё.

Я за suckless код.

Deleted
()
Ответ на: комментарий от Deleted

скрипт

в 3.10 не работает. Позже проверю работу 2.6.9, 2.6.18 и 2.6.32 :-) А программу я давно хотел собрать, а тут такой повод....

Я тут подумал. Ядро через TIOCLINUX-чего-то-там умеет сообщать, выставлен ли на терминале mouse reporting или нет. Можно воспользоваться этим знанием и послать координаты мыши в приложение прямо из gpm, без необходимости патчить ядро. Посылать байты из gpm можно при помощи TIOCSTI.

То есть надо узнать, какой терминал активен, установлен ли на нём mouse reporting, а затем послать на него esc-последовательность ? Похоже что можно. В пакете kbd есть програмка, которая позволяет послать в буфер ввода ядра байтики, и они будут прочитаны из стандартного ввода. Вряд ли мы вклинимся в последовательность от ядра. Иначе такой програмки в kbd не было бы. И програмка это делает через TIOCSTI. Вопрос скорее в привелегиях, нужных для этого (но конкретно про узнавание mouse_reporting и номер активного терминала от ядра — не знаю)

А mouse reporting всё равно надо проверить... Да и починить его, скорее всего, нетрудно будет.

seyko2
()
Ответ на: комментарий от Deleted

Проверка и исходники

Поверил — скрипт не работает даже в 2.6.9. Полез в исходники програмки: там:

write( STDOUT_FILENO, "\x1B[?1001s\x1B[?1000l\x1B[?9h", 21 );
// save old hilit tracking, enable mouse tracking

write( STDOUT_FILENO, "\x1B[?1000l\x1B[?1001r", 16 );
// disable mouse tracking, restore old hilittracking

static char *Show_Mouse_Str = "\033[?1000h";
Всё же надо собрать :-) Она точно работала.

seyko2
()
Ответ на: комментарий от Deleted

Кстати...

gpm, по-моему, и посылает в ядро события о перемещении мыши, Больше некому :-) Может и так, как ты описал. Надо смотреть.

seyko2
()
Ответ на: Кстати... от seyko2

gpm, по-моему, и посылает в ядро события о перемещении мыши

Естественно.

Но обязанности ядра сводятся к рисованию положения мыши и выделенного текста. Еще ядро умеет выполнять (по приказам через ioctl) команды «поместить выделенную область экрана в отдельный буфер» и «отправить буфер через терминал как ввод пользователя».

(Ну и плюс к этому, ядро умеет помнить запрошенный приложением режим mouse reporting-а.)

Больше ядро ничего делать не научено.

А во фряхе модуль ядра syscons умеет посылать мышиные ESC-коды приложению. Если приложение говорит «режим 1000 включить», syscons все сообщения, получаемые от демона moused, превращает в ESC-коды и отправляет приложению. Если приложение говорит «режим 1000 выключить», ядро сообщения от moused никуда не пересылает, а реагирует на них само, позволяя выделять мышкой текст и делать копи-паст.

Соответственно, у нас два пути. Либо научить подсистему vt в ядре таким же фокусам, какие умеет фряховый syscons. Либо полностью задачи mouse reporting-а переложить на gpm.

Deleted
()
Ответ на: комментарий от Deleted

Не надо про syscons

Либо научить подсистему vt в ядре таким же фокусам, какие умеет фряховый syscons

Раньше Linux-ядро умело :-( То есть в 2.0, 2.2, а может, и в 2.4. Тут была новость, что во фряхе удалили возможность внешнему злодею сбросить её tcp-соединение. Причём это уже латали лет 10 назад. Но в 2008-2009 как-бы опять незаметно внедрили. Linux и в этом впереди фряхи :-) Ибо, как мы выяснмли, он уже успел поломать свои мышиные фичи! И во FreeBSD, кстати, они позже появились :-)

Собрал наконец програмку. Она не работает с нынешним gpm (вылетает), работает только при запуске gpm из Slackware 8. Ибо общается с /dev/gpm* сама, без использования библиотеки. Вывод — поменяли и протокол общения с /dev/gpm*

Да, в chroot mouse от host отсутствует. Запустил в нём свой gpm. Получил на всех терминалах два указателя мыши (в разных местах) :-) FreeBSD такое умеет?

А как быть с контейнерами? В них можно пробрасывать устройства, про pipe — не уверен.

seyko2
()
Ответ на: комментарий от Deleted

mouse reporting

Проверил включение с помощью запроса к ядру TIOCLINUX. Получаем ответ: 2. Типа включился. Но реально сообщений нет. Попробую поискать причину.

seyko2
()
Ответ на: комментарий от Deleted

gpm надо лечить

Ядро сообщает о перемещении мыши через ioctl(fd,TIOCLINUX,& (структура TIOCL_SETSEL)); если в 5м параметре структуры (mode) установлен флаг TIOCL_SELMOUSEREPORT. При просмотре исходников gpm я что-то не нашёл, чтоб этот флаг устанавливался. Попробую собрать ядро с выключенной проверкой этого флага.

seyko2
()
Ответ на: gpm надо лечить от seyko2

получил сообщения mouse_report

Пересобрал ядро с выключенной проверкой (и переместил mouse report перед clear selection в drivers/tty/vt/selection.c). В результате приведённый выше скрипт начал выдавать сообщения. Вывод: лечить надо gpm, а не ядро.

seyko2
()

давно мучает вопрос почему mc впадает в ступор когда распаковывает zip архивы

очень медленно это делает

anonymous
()
Ответ на: комментарий от anonymous

давно мучает вопрос

Какое отношение это мучение имеет к теме?

Ты хоть искать ответ пытался? Это легко. И не больно.

akk ★★★★★
()
Ответ на: gpm надо лечить от seyko2

О, супер! Сейчас похакаю сорцы gpm.

Я, видимо, не заметил сослепу строку «if (mouse_reporting() && (sel_mode & TIOCL_SELMOUSEREPORT))», когда грепал сорцы ядра.

Deleted
()
Ответ на: комментарий от akk

вот именно не искал давно забил на эту тему делаю все ручками но почему он так ведет ??

anonymous
()
Ответ на: gpm надо лечить от seyko2

Отлично, к gpm-у начерно прикрутил поддержку. В tmux-е заработало переключение вкладок мышью, и mc из-под tmux-а тоже стал видеть мышь.

Но дальше возникают следующие проблемы:

1. Информация о режимах, доступная gpm-у от ядра.

Ядро в курсе только про режим 1000 и про бесполезный режим 9. Для полноценной поддержки мыши нам нужны режимы 1002, 1003 и 1006.

2. Нехватка полей в при использовании TIOCL_SELMOUSEREPORT. Там биты с 0-го по 3-й отсылаются в mouse reporting. А для поддержки режимов 1002 и 1003 нужен бит 5. И кроме того, бит 4, который занят самим TIOCL_SELMOUSEREPORT-ом, испольхуется для отсылки модификатора Ctrl.

Поэтому, похоже, придётся патчить ядро и вводить новые TIOCL-ы.

Пойду думать над API.

Deleted
()
Ответ на: комментарий от Deleted

Думать надо вслух..

Я тоже в gpm поправил функцию selection_copy() на предмет возвращать ошибку, а не впадать в панику. Плюс в GPM_MOVE, который рисует указатель, добавил второй вызов для mouse reporting. Запускаю скрипт: он при больших значениях x-y выводит отрицательные числа. Это проблема режима 1000?

Другие проблемы: приложение типа turbo-vision захочет само отрабатывать drag. Соответственно selection от gpm должно срабатывать в этом случае только при нажатых модификаторах (ctrl или shift).

А добавить в ядро другие режимы, думаю, нетрудно. Вопрос: почему 4х битов недостаточно?

seyko2
()
Ответ на: Думать надо вслух.. от seyko2

SELBUTTON_MASK

Вообще у нас в распоряжении 15ть бит (один занят самим TIOCL_SELMOUSEREPORT). А раз мы хотим добавить режимы, то report_mouse() всё равно придётся править.

seyko2
()
Ответ на: Думать надо вслух.. от seyko2

Это проблема режима 1000?

Ага. Нужен 1006-й.

Другие проблемы: приложение типа turbo-vision захочет само отрабатывать drag. Соответственно selection от gpm должно срабатывать в этом случае только при нажатых модификаторах (ctrl или shift).

В xterm и vte соглашения такие: с зажатым шифтом терминал обрабатывает мышь сам. Если шифт не зажат, то срабатывает mouse reporting, если включён.

Логика в gpm должна быть такая:

* (получить от ядра модификаторы и состояние mouse reporting) если shift не нажат и mouse reporting включён, отправляем мышиные сообщения ядру для пересылки программе.

* иначе если shift не зажат, отправляем текущему клиенту, если есть.

* иначе исполняем дефолтный do_selection.

Но! Режим 1000 обеспечивает только пересылку информации о щелчках. Для того, чтобы приложение получало перетаскивания мыши, нужен 1002-й. (если правильно помню)

А добавить в ядро другие режимы, думаю, нетрудно. Вопрос: почему 4х битов недостаточно?

Могу наврать, перечисляю по памяти. В первом байте пакета передаётся такая информация: Биты 0 и 1 - номер нажатой клавиши. Бит 3 - модификатор Alt. Бит 4 - модификатор Ctrl. Бит 5 - модификатор движения мыши. Еще что-то там отвечает за колесико мыши.

Что сейчас делает ядро, получая запрос TIOCL_SETSEL: оно проверяет в поле mode бит TIOCL_SELMOUSEREPORT; если он установлен, берёт (mode & 0x0F) и считает это первым байтом пакета. Так что ни Ctrl, ни перетаскивание, ни прокрутку колесом, мы передать не можем.

Итак, нам надо два TIOCL-сервиса. Через первый gpm будет узнавать, какой набор сообщений запрошен приложением на активном vt. (щелчки, перетаскивания, обычные движения мыши, движения колеса). Можно расширить под это дело сервис TIOCL_GETMOUSEREPORTING, там еще 6 бит свободно в байте ответа.

Через второй сервис gpm будет посылать ядру пакеты с состоянием мыши в терминало-независимом формате. Ядро будет их конвертировать в ESC-последовательности и направлять приложению. Думаю, нужен полностью новый сервис с новым форматом пакета. TIOCL_SETSEL неудобен во-первых, потому что там воткнут этот 4-й бит. Во-вторых, потому что не предусмотрена передача сведений о колесе мыши.

Пусть TIOCL_SETSEL выполняет прямые обязанности: задаёт область выделения.

Deleted
()
Ответ на: комментарий от Deleted

SETSEL и mouse_reporting выполняет

4й бит никому не мешает. Интерфейc mouse_reporting можно переделать как угодно, ибо он предназначен только для gpm. А так как он не работал, то мы имеем 15 бит в запасе. Плюс код ответа. Более чем достаточно, чтоб реализовать все возможности. Кроме того, надо зарезервировать комбинацию модификаторов для выделения прямоугольной области. Если shift — стандарное выделение, то какая комбинация — для прямоугольной? ctrl-shit занят переключением раскладки. Ctrl-Alt — вроде свободен, ибо служебный (переключение vt, и много ещё). Поэтому можно в консоли shift и ctrl-alt. Или ctrl и ctrl-alt. (ctrl уже использовался в gpm как замена shift). Итого приложению остаются только: alt, ctrl или shift, и alt-shift. Всего три комбинации. А нажатие — отпускание вообще-то можно определить по предыдущему состоянию клавиш и кнопок

seyko2
()
Ответ на: SETSEL и mouse_reporting выполняет от seyko2

Хотя...

gpm может для приложения в режиме mouse reporting использовать скажем left-win вместо ctrl, Тогда, при использовании gpm клавиш ctrl и ctrl-alt для выделения в clipboard, приложению будет доступно три модификатора :-)

seyko2
()
Ответ на: комментарий от Deleted

TIOCL_GETMOUSEREPORTING

Вроде только как только для своего терминала. Мы можем узнать активный терминал, потом открыть его, и уж потом узнать mouse_reporting. Сложно, SELMOUSEREPORT может вернуть всю нужную информацию за один раз, заодно и выполнив, если можно, и полезную работу.

seyko2
()
Ответ на: SETSEL и mouse_reporting выполняет от seyko2

И ещё...

При наличии 4го бита мы можем считать сколько угодно дополнителных слов (то есть стуктура может быть больше 5 слов). Всё равно — эта функция _не_ использовалась.

seyko2
()
Ответ на: Хотя... от seyko2

Только вроде win-клавиши не модификаторы

То есть ядро о их состоянии не сообщает.

seyko2
()
Ответ на: И ещё... от seyko2

Ну хз, посмотрим. Мне не нравится идея ломать существующие API. Мало ли кем они «не использовалась» в каком-нибудь уголке планеты.

И кроме того, мне не нравится разводить бардак с этими битовыми флагами. «Если флаг такой, читать структуру так, если флаг сякой читать, структуру этак». Если SETSEL — это subrequest TIOCLINUX, то поле mode уже получается subsubrequest. Это усложняет код и делает его более склонным к ошибкам.

TIOCL_GETMOUSEREPORTING Вроде только как только для своего терминала.

Для активного терминала. Что и требуется.

Пойду допиливать свой урезанный gpm, чтобы выложить сорцы. Оттестим то, что есть, там видно будет.

Deleted
()
Ответ на: комментарий от Deleted

Надо бы патчи для существующкго

И да, хотелось бы, чтобы новая версия gpm со старыми (без расширения) ядрами всё же работала в пределах задуманного.

Да, давай твой урезанный. Потом сочиним патчи и для стандартного. Я вот пытаюсь найти исходники gpm 1998-2001 годов. Там

seyko2
()
Ответ на: комментарий от akk

Угу, спасибо

Скачал всё что нужно. Выводы дам в ответе к devzero

seyko2
()
Ответ на: комментарий от Deleted

Насчёт допиливания урезанного gpm

Просмотрел версии gpm с 0.9 до 1.9 и ядра 2.0, 2.2 и 2.4. Выводы такие: gpm с 0.9 до сегодняшнего дня по функционалу не изменилась. Она никогда не поддерживала mouse_report. Нынешний функционал ядра по mouse_report появился в 2.2 и тоже ни грамма не изменился.

mouse_report работал в модифицированной версии gpm 1.10 :-), доработанной мной для работы с turbo vision для Linux. Я пытался пропихнуть эти патчи, но не имел успеха. Были и небольшие модификации и для ядра: не гасить указатель мыши, когда программа выводит на экран. Но это не существенно. На google drive выложить не удалось: лимит по beeline закончился. Так что привожу сдесь:

# xterm like mouse events reporting on Linux console.
# Start `mc -x' from telnet session and use mouse.
#
# For gpm v1.10 (Sergey Korshunoff)

--- gpm.c.bak	Tue Feb 18 06:57:54 1997
+++ gpm.c	Sun Aug 17 22:57:58 1997
@@ -136,7 +136,7 @@
 }
 
 /*-------------------------------------------------------------------*/
-static inline void selection_copy(int x1, int y1, int x2, int y2, int mode)
+static inline void selection_copy(int fd, int x1, int y1, int x2, int y2, int mode)
 {
 /*
  * The approach in "selection" causes a bus error when run under SunOS 4.1
@@ -144,7 +144,6 @@
  */
 unsigned char buf[6*sizeof(short)];
 unsigned short *arg = (unsigned short *)buf + 1;
-int fd;
 
   buf[sizeof(short)-1] = 2;  /* set selection */
 
@@ -154,25 +153,52 @@
   arg[3]=(unsigned short)y2;
   arg[4]=(unsigned short)mode;
 
-  if ((fd=open_console(O_WRONLY))<0)
-    oops("open_console");
   PDEBUGG((stderr,"ctl %i, mode %i\n",(int)*buf,arg[4]));
   if (ioctl(fd, TIOCLINUX, buf+sizeof(short)-1) < 0)
     oops("ioctl(TIOCLINUX)");
-  close(fd);
 }
 
 
 /*-------------------------------------------------------------------*/
-static inline void selection_paste(void)
+static inline void selection_paste(int fd)
 {
 char c=3;
-int fd;
 
-  fd=open_console(O_WRONLY);
   if (ioctl(fd, TIOCLINUX, &c) < 0)
      oops("ioctl(TIOCLINUX)");
-  close(fd);
+}
+
+/*-------------------------------------------------------------------*/
+static inline void do_report_mouse(int fd, Gpm_Event *event, int x, int y)
+{
+  unsigned char buf[6*sizeof(short)];
+  unsigned short *arg = (unsigned short *)buf + 1;
+
+  const int type = event->type & (GPM_DOWN|GPM_UP);
+  int buttons = event->buttons;
+
+  if (type == 0)
+      return;
+
+  if (type==GPM_UP)
+    buttons = 0;
+
+  buf[sizeof(short)-1] = 2;  /* set selection */
+
+  arg[0]=arg[2]=(unsigned short)x;
+  arg[1]=arg[3]=(unsigned short)y;
+
+                                   arg[4] =16; /* report mouse case */
+  if (event->modifiers & 3)        arg[4]|=4;  /* shift */
+  if (event->modifiers & 8)        arg[4]|=8;  /* alt */
+
+  if (buttons & GPM_B_RIGHT)       arg[4]|=2;
+  else if (buttons & GPM_B_MIDDLE) arg[4]|=1;
+  else if (buttons & GPM_B_LEFT)   arg[4]|=0;
+  else                             arg[4]|=3;  /* UP */
+
+  if (ioctl(fd, TIOCLINUX, buf+sizeof(short)-1) < 0)
+    oops("do_report_mouse");
 }
 
 /*-------------------------------------------------------------------*/
@@ -181,52 +207,76 @@
 static int x1=1, y1=1, x2, y2;
 #define UNPOINTER() 0
 
+int fd;
+unsigned char report_mouse = 7;
+
+  if ((fd=open_console(O_WRONLY))<0)
+    oops("open_console");
+
+  if (ioctl(fd, TIOCLINUX, &report_mouse) < 0)
+    oops("get_report_mouse");
+
+  if (event->modifiers & 4) /* Ctrl, keep it for selection/paste */
+    report_mouse = 0;
+
+  if (report_mouse)
+    {
+    char kbd_flag = 0;
+    ioctl(fd,KDGKBLED,&kbd_flag);
+    if( kbd_flag & 1 )     /* Scroll Lock */
+      report_mouse = 0;
+    }
+
   x2=event->x; y2=event->y;
+  if (x2<1) x2=1; else if (x2>maxx) x2=maxx;
+  if (y2<1) y2=1; else if (y2>maxy) y2=maxy;
+
+  if (report_mouse)
+    do_report_mouse(fd,event,x2,y2);
+
   switch(GPM_BARE_EVENTS(event->type))
     {
     case GPM_MOVE:
-      if (x2<1) x2++; else if (x2>maxx) x2--;
-      if (y2<1) y2++; else if (y2>maxy) y2--;
-      selection_copy(x2,y2,x2,y2,3); /* just highlight pointer */
-      return 0;
+      selection_copy(fd,x2,y2,x2,y2,3); /* just highlight pointer */
+      break;
 
     case GPM_DRAG:
-      if (event->buttons==GPM_B_LEFT)
-	{
-	if (event->margin) /* fix margins */
-	  switch(event->margin)
-	    {
-	    case GPM_TOP: y2++; break;
-	    case GPM_BOT: y2--; break;
-	    case GPM_RGT: x2--; break;
-	    case GPM_LFT: x2++; break;
-	    }
-        selection_copy(x1,y1,x2,y2,event->clicks);
-	if (event->clicks>=opt_ptrdrag && !event->margin) /* pointer */
-	  selection_copy(x2,y2,x2,y2,3);
-	}
-      return 0;
+      if (event->buttons==GPM_B_LEFT && !report_mouse)
+          selection_copy(fd,x1,y1,x2,y2,event->clicks);
+      if ((event->clicks>=opt_ptrdrag && !event->margin) || report_mouse)
+        selection_copy(fd,x2,y2,x2,y2,3); /* pointer */
+      break;
 
     case GPM_DOWN:
       switch (event->buttons)
 	{
 	case GPM_B_LEFT:
-	  x1=x2; y1=y2;
-	  selection_copy(x1,y1,x2,y2,event->clicks);  /*  start selection */
-	  return 0;
+          if (!report_mouse)
+            {
+	    x1=x2; y1=y2;
+	    selection_copy(fd,x1,y1,x2,y2,event->clicks);  /*  start selection */
+            }
+	  break;
 
 	case GPM_B_MIDDLE:
-	  selection_paste();
-	  return 0;
+          if (!report_mouse)
+	    selection_paste(fd);
+	  break;
 
 	case GPM_B_RIGHT:
-	  if (opt_three==1)
-	    selection_copy(x1,y1,x2,y2,event->clicks);
-	  else
-	    selection_paste();
-	  return 0;
+          if (!report_mouse)
+	    if (opt_three==1)
+	      selection_copy(fd,x1,y1,x2,y2,event->clicks);
+	    else
+	      selection_paste(fd);
+	  break;
 	}
+      break;
+
+    case GPM_UP:
+      break;
     }
+  close(fd);
   return 0;
 }
 
@@ -456,7 +506,7 @@
   event->modifiers=6; /* code for the ioctl */
   if (ioctl(i,TIOCLINUX,&(event->modifiers))<0)
     oops("get_shift_state");
-  close(i);
+
   event->vc = stat.v_active;
 
   if (oldB==event->buttons)
@@ -464,6 +514,14 @@
   else
     event->type = (event->buttons > oldB ? GPM_DOWN : GPM_UP);
 
+  if (ioctl(i,TIOCGWINSZ,&win)==0)
+    {
+    maxx=win.ws_col;
+    maxy=win.ws_row;
+    }
+
+  close(i);
+
   switch(event->type)                    /* now provide the cooked bits */
     {
     case GPM_DOWN:
@@ -901,7 +959,7 @@
 	     * or to the selection handler
 	     */ /* FIXME -- check event.vc */
 	    (cinfo[event.vc] && do_client(cinfo[event.vc], &event))
-	       || (cinfo[0]        && do_client(cinfo[0],        &event))
+	       || (cinfo[0]  && do_client(cinfo[0],        &event))
 	       ||  do_selection(&event);
 	  }
       }

seyko2
()
Ответ на: комментарий от Deleted

патч для нынешнего gpm

С помощью drive удалось выложить на google drive архив gpm-xterm.tar.xz https://googledrive.com/host/0B35PjbLHNzyqNS13R0M1aEctNDQ (имя drive поковеркал). В нём слегка модифицированный (в части логики) патч для нынешнего gpm, бинарник модифицированного gpm и статически собранная тестовая программа atvedit Для теста изменений запускать её из-под mc.

seyko2
()

Если ttyname() возвращает имя вида /dev/tty*, использование gpm имеет смысл. Иначе — не имеет.

Вроде бы для /dev/ttyS* и /dev/ttyUSB* тоже не имеет, но они подпадают под предложенную маску, не? Да и файл устройства можно назвать как угодно (не знаю, кому такое может прийти в голову, но возможность существует).

Нет ли более надёжного способа опознать консоль linux? (Может по каким-нибудь major и minor?)

unterwulf
()
Ответ на: комментарий от unterwulf

Нет ли более надёжного способа опознать консоль linux? (Может по каким-нибудь major и minor?)

По major можно.

Deleted
()
Ответ на: комментарий от Deleted

Насколько я могу судить, одного major недостаточно.

$ ls -ls /dev/tty? /dev/ttyS?
0 crw------- 1 root root    4,  0 Сен 22  2014 /dev/tty0
0 crw-rw---- 1 root tty     4,  1 Сен 22  2014 /dev/tty1
0 crw-rw---- 1 root tty     4,  2 Сен 22  2014 /dev/tty2
0 crw-rw---- 1 root tty     4,  3 Сен 22  2014 /dev/tty3
0 crw-rw---- 1 root tty     4,  4 Сен 22  2014 /dev/tty4
0 crw-rw---- 1 root tty     4,  5 Сен 22  2014 /dev/tty5
0 crw-rw---- 1 root tty     4,  6 Сен 22  2014 /dev/tty6
0 crw------- 1 root root    4,  7 Сен 22  2014 /dev/tty7
0 crw------- 1 root root    4,  8 Сен 22  2014 /dev/tty8
0 crw------- 1 root root    4,  9 Сен 22  2014 /dev/tty9
0 crw-rw---T 1 root dialout 4, 64 Сен 22  2014 /dev/ttyS0
0 crw-rw---T 1 root dialout 4, 65 Сен 22  2014 /dev/ttyS1
0 crw-rw---T 1 root dialout 4, 66 Сен 22  2014 /dev/ttyS2
0 crw-rw---T 1 root dialout 4, 67 Сен 22  2014 /dev/ttyS3

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