Безопасный «ctrl+v» в терминале

от автора

Думаю каждый хоть раз аккуратно выделив кусок кода\консольную команду из окна любимого браузера, нажав «ctrl +c», потом «ctrl+v» в активное окно эмулятора терминала очень удивился — "\n" случайно оказался выделенным, соответственно вы уже запустили команду.

Предлагаю легкий и простой вариант решения этой проблемы. Так как самый лучший язык программирования это python, это единственное что я как-то знаю, то будем его использовать.

Итого — нужно перехватить данные из буфера обмена при нажатии «ctrl+v», проверить наличие "\n" и дальше опять «вызвать» «ctrl+v». Делать проверку буфера для всех прикладных программ не совсем логично, и например в gnome-terminal «Paste» назначен по умолчанию на «Shift+Ctrl+V», то я заменил это на «Ctrl+V». Дальше нужно на привычную комбинацию «Shift+Ctrl+V» поставить проверку буфера.
Существует много вариантов это сделать, которые зависят от используемого рабочего окружения. Конкретно в моем случае это

~/.config/openbox/rc.xml

  <keyboard>     <keybind key="S-C-v">       <action name="Execute">         <command>/home/user/scripts/safe_paste.py</command>       </action>     </keybind>   </keyboard> 

Нужно не забыть chmod +x /home/user/scripts/safe_paste.py.

/home/user/scripts/safe_paste.py

#!/usr/bin/env python from paste_it import main   main() 

/home/user/scripts/paste_it.py

#!/usr/bin/env python import os from subprocess import Popen, PIPE   def main():     # берем текущие значение буффера, через вызов xsel     sys_exec = Popen('xsel', stdout=PIPE)      stdout = sys_exec.stdout.read()      #если количество строк в буфера не равно 1, то сообщим об это этом     if len(stdout.splitlines()) != 1:         n_detected = Popen('notify-send "\\n detected"', shell=True)         return False      #самое интересно, об этом чуть ниже     codes = map(ord, stdout)      for code in codes:         if code <= 31 or code == 127:             bad_code_detected = Popen('notify-send "bad code detected"',                  shell=True)             return False      paste = Popen('%s/pasteit &' %         os.path.dirname(__file__), shell=True)     return stdout  if __name__ == '__main__':     main() 

Разбиение кода на 2 файла даст небольшой прирост производительности, конечно же и можно сразу назначать paste_it.py.

Кроме "\n" к нам в буфер может попасть www.asciitable.com, а именно 0-31 и 127, которые тоже могут вызвать неожиданное поведение терминала, следовательно об это нужно проинформировать.

Дальше надо вызвать «crtl+v» для вставки безопасного текста. Ну а если содержание не безопасно то тут открыть текстовый редактор\выбросить некоторые символы\автоматом убрать "\n", тут уже кому как удобнее, реализация тоже будет не сложной. Лично для меня достаточно знать что я задел при выделении что-то лишние.

Способов вызвать «ctrl+v» из под линукса найдено было много:

  • xdotool — на взгляд замечательная вещь — в Centos 6.3 в репах нет, собрать не получилось
  • xvkbd — собирается imake’ом (Imake is a deprecated source code configuration and build system), но не собралось
  • python-uinput — из пушки по воробьям, эмуляция устройства, hal правило
  • python-virtkey — так же не собралось
  • xautomation — было в репах, но очень древние и работало ужасно, и залипало ctrl
  • под виндовс есть autohotkey, autoit, pywin32

Надо писать самому.
На с\с++ погулив я забил, так как с пол пинка не выйдет.

Было реализовано очень компактное решение на java:

PasteIt.java

import java.awt.AWTException; import java.awt.Robot; import java.awt.event.KeyEvent;  public class PasteIt{     public static void main(String[] args) {         try {             Robot robot = new Robot();             robot.keyPress(KeyEvent.VK_CONTROL);             robot.keyPress(KeyEvent.VK_V);             robot.delay(20);             robot.keyRelease(KeyEvent.VK_V);             robot.keyRelease(KeyEvent.VK_CONTROL);         } catch (AWTException e) {             e.printStackTrace();         }     } } 

javac PasteIt.java

На не совсем новом ноутбуке вызов этого класса занимал 1-2 сек, было очень не комфортно, но работало.

GCJ выглядит заброшенным, но

gcj -O2 —main=PasteIt PasteIt.java

и был создан бинарник a.out, который я переименовал в pasteit и он работает 0.1 сек.

Теперь я как обычно нажимаю «ctrl+shift+v», и если в буфере что-то не подходящие, то я получу уведомление, так же я могу использовать «ctrl+v» если мне нужно вставить данные без проверки.

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

Заменив xsel на решения с stackoverflow.com, с помощью mingw так же можно использовать GCJ, но я не совсем уверен в надобности всего этого для использования в powershell\cmd, но для putty может будет полезно.

ссылка на оригинал статьи http://habrahabr.ru/post/165317/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *