Pull to refresh

Comments 46

Пока живы такие очумельцы — за нашу Родину можно не беспокоиться ;)
Ох, это мне надо пару недель не поспать :)
Отличный практикум на bash. И комменты исходнике просто отличные. Спасибо.
Со слепу принял сначала вашу картинку за это.
Видимо, стоит задуматься)
Кто подскажет, какой шрифт нужно поставить в Linux, чтобы это начало отображаться?
UFO just landed and posted this here
UFO just landed and posted this here
Если бы, пытаюсь расшевелить себе мозг :)
Круть! ;)

С кнопками я тоже как то бился помню… как то так:
#!/bin/bash
# Прочитать 1 символ. 
# -s отключить эхо, -n1 только один символ, -r считывать "\" не дожидаясь экранирования
while read -s -n1 key                      
do
...
done

Так не получится. Курсорные клавиши выдают по три символа за раз, курсорные с шифтом (на Маке) — шесть, так что надо какой-то определять конец комбинации :) Я придумал два выхода — либо найти все комбинации, которые генерируются и собрать их, либо замерять задержки между нажатиями. У меня используется гибрид — для того, чтобы понимать, что нашёлся конец я использую словарь, чтобы определить, что клавиша нажата в составе комбинации — меряю задержку.
Кстати да, для курсорных и прочих клавиш где передаются более одного символа, я делал счетчик их, и типа конечного автомата для их приема, обрабатывал только небходимые мне.
Вот и получается, что нужно либо знать все комбинации и как-то их хранить (каких только клавиш на компьютерах не бывает и что они только не шлют в консоль, хранить это накладно, обрабатывать — долго), либо делать как-то детектор конца комбинации.

Причём конечный автомат тоже не очень-то поможет — есть комбинации, не содержащие признака, что дальше может что-то идти, то есть есть комбинация abcd, а есть abcdef, их никак не различить, если делать конечный автомат.
Да, детектор по времени нужен. Я кстати был удивлен, когда писал код для работы с терминалом, ввод и вывод. Куча ESC последовательностей, причем разных для разных терминалов (я поддерживал только vt-100) и не придумали хотя бы признака конца последовательности! А если ты ее не обрабатываешь, то она вылазит левыми символами, т.к. само тело то в ASCII. Это создает массу сложностей.
Понятно конечно что все это тянется от печатных машинок и все это legacy и много рудиментов и обратная совместимость… Зоопарк короче :D Это уже не раз тут обсуждали…
У нас товарищ перед увольнением сделал сетевой морской бой на виндовых батниках. Хотели даже традицию такую ввести, перед увольнением писать морской бой на чем-нибудь экзотическом)
Я тоже годика полтора назад писал морской бой в консоли. Только упор делался как раз на наличие всех проверок, и умный АИ.
Но и «дизайн» тоже не оставил в стороне, все цвета и символы были хорошо подобраны (хотя у меня было только ASCII и 16 цветов).
Надо бы раскопать код…
У меня сразу не заработало. Вот фикс:

diff --git a/chess.sh b/chess.sh
index c992749..0d8ba9d 100644
— a/chess.sh
+++ b/chess.sh
@@ -12,7 +12,7 @@ for i in nc1 netcat ncat pnetcat; do
which $i &>/dev/null && NC=$i && break
done

-[ -z "$NC"] && echo 'Error: you have to install netcat to continue' && exit 1
+[ -z "$NC" ] && echo 'Error: you have to install netcat to continue' && exit 1

# Хост оппонента
HOST="$1"
там nc1 убрать надо, я для теста ставил, сейчас пофикшу
Ксоникс, шахматы… Что следующее? Неужто и вправду Doom? :D
Нет, наверное таки Diablo IV :-P
Повешусь я такое делать :)
Мы верим в тебя, падаван ))))
ну 3D и правда тут х.з., а вот что-то типа Rogue было бы посильно, наверное = )
Это отличный вариант ненормального программирования, но там блоки надо опускать вручную s+Debug-версия тетриса с выполнением по шагам.
Ээм, простите за занудство, но это не самый правильный способ — мерить задержку между нажатиями клавиш для выявления комбинации.
Сугубо говоря, он верен до тех пор, пока число циклов тактового генератора между обработками прерывания первой и второй клавиши последовательности больше единицы. (Сейчас-то это почти всегда так, но вот ранее… :-)
Итак, чтобы не быть болтолологом, предложу своё решение:
во-первых, я бы заменил явно указание кодов клавиш на их эскейп-аналоги, это решение получше, так как ориентируемся на коды клавиш для терминала(см пример из книги abs-guide):
# Коды клавиш.
arrowup='\[A'
arrowdown='\[B'
arrowrt='\[C'
arrowleft='\[D'
insert='\[2'
delete='\[3'
SUCCESS=0
далее, после считывания, сравниваем кодами:
read -n3 key # Прочитать 3 символа.
echo -n "$key" | grep "$insert"
if [ "$?" -eq $SUCCESS ]
then
  echo "Нажата клавиша \"Insert\"."
  exit $SUCCESS
fi

И теперь, комбинация клавишь в эскейп-последовательности выглядит так (для SHIFT+ARR_DOWN):
'\[1;2B', где '\[1;' — начало escape-последовательности, 2B — коды клавиш, 2 — SHIFT, B — ARR_DOWN
так что, читая по три символа это будет выглядеть как-то так:
seq='\[1'
shift_down=';2B'
read -n3 key # Прочитать 3 символа.
echo -n "$key" | grep "$arrowup"
[ "$?" -eq $SUCCESS ] && : # своя обработка
echo -n "$key" | grep "$arrowdown"
[ "$?" -eq $SUCCESS ] && :
echo -n "$key" | grep "$arrowrt"
[ "$?" -eq $SUCCESS ] && :
echo -n "$key" | grep "$arrowleft"
[ "$?" -eq $SUCCESS ] && :
echo -n "$key" | grep "$seq"
if [ "$?" -eq $SUCCESS ] ; then
  read -n3 key
  echo -n "$key" | grep "$shift_down"
  [ "$?" -eq $SUCCESS ] && echo "Pressed Shift-Down"
  #etc
fi
Что будет если пользователь нажал не курсорные клавиши?
тогда ведётся считывание (в моём примере по три символа), заменяя read -n3 key на read -n1 key можно вести обработку нажатия и печатных символов, затем, среди них обнаруживать escape-последовательности.
Ну то есть вы предлагаете один из способов, который я упоминал — искать известные последовательности. Как уже говорил, он не работает, так как есть последовательности разной длины, но с одним началом.
мм, а какие две последовательности в ваших комбинациях совпадают?
(я что-то не заметил, курсорные клавиши, курсорные с зажатой управляющей клавишей и обычные все различаются)
Если курсорную клавишу зажать с shift на «маке», будет последовательность ровно такая же как курсорная, только длиннее. Это только один пример.

Мне хотелось сделать обработку в которую я достаточно быстро смогу добавить любые новые клавиши, на длине и маске основываться нельзя — будут ложные нажатия.
ясно, хотя это странно, в bash под linux они различаются.
ладно, ваша взяла, хотя по мне это некий «костыль», извините уж.
Конечно костыль, ещё бы! Если бы в shell было какое-то нормальное встроенное средство для этого, было бы здорово.
Ещё пример, кстати, вспомнил. Любая длинная последовательность начинается с Esc (0x1B), если нажать клавишу Esc, то будет выдана именно она. Как различить это начало длинной последовательности или пользователь просто Esc нажал?
да, на счёт этого я в курсе, я предлагал решение к вашей конкретно задаче, где в используемые клавиши Esc не входит:)
ps
вообще, конечно, спасибо, тут вы придумали хоть какое-то решение. Как-то пытался найти функцию, возвращающую состояние буфера ввода, но, может, плохо искал, думаю, это решение было бы слегка красивей.
Забыл сказать: статья мне понравилась, сам когда-то, админя также развлекался с напарником; вывод был разве что на разные терминалы сервера, а не игра по сети, но уже был и таймер ходов, и лог, и чёрт вспомнит, что ещё!
Sign up to leave a comment.

Articles