Обрабатывать KeyboardInterrupt в оболочке, если скрипт не запущен

Можно ли обрабатывать KeyboardInterrupt в оболочке, если скрипт не запущен?

Предыстория моего вопроса следующая: я использую python для отправки команд на контроллер двигателя через соединение через сокет. Функция отправляет целевое положение двигателя в контроллер и немедленно возвращает значение, т. е. до того, как двигатель фактически достигнет своего целевого положения. Теперь может случиться так, что пользователь вводит неправильное положение и хочет прервать движение двигателя как можно быстрее. Это можно сделать, введя команду stop(), которая отправляет команду остановки контроллеру. Но было бы более интуитивно понятно и быстрее, если бы двигатель можно было остановить, нажав Ctrl+C. Есть ли способ позволить python выполнить функцию, нажав Ctrl + C, пока скрипт не запущен?

Я знаю, как обрабатывать исключение KeyboardInterrupt или signal.SIGINT в работающем скрипте, но не смог найти подсказок о том, как решить мою задачу.

Буду очень благодарен за любую помощь!


person Rolli    schedule 30.11.2018    source источник
comment
Добавление хука системного уровня, который переопределяет функциональность по умолчанию Ctrl+C, не является хорошей идеей. Вам было бы лучше изменить свой код Python таким образом, чтобы движение удерживало скрипт открытым до тех пор, пока движение не будет завершено. Вы можете использовать диспетчер контекста для захвата KeyboardInterrupt и выдачи stop().   -  person James    schedule 30.11.2018
comment
Я согласен, что изменение функциональности Ctrl+C по умолчанию — плохой вариант. Проблема с сохранением сценария открытым заключается в том, что я хочу иметь возможность выполнять другие функции во время движения двигателя.   -  person Rolli    schedule 30.11.2018
comment
вы на Linux, Mac или Windows?   -  person James    schedule 01.12.2018
comment
@James: я на Linux   -  person Rolli    schedule 01.12.2018


Ответы (2)


Если контроллер может обрабатывать несколько подключений к сокету, вы можете запустить совершенно новый процесс, который использует модуль keyboard для прослушивания ctrl+c, а затем заставить этот процесс отправить команду остановки контроллеру.

Сначала установите пакет клавиатуры из pypi

pip install keyboard

Создайте файл для прослушивания ctrl+c:

# file named 'wait_stop.py
##########################

import keyboard

# code here to establish connection to controller

def wait_stop():
    keyboard.wait('ctrl+c')
    print('sending stop signal')
    # function that sends stop signal here...
    # ...
    # call wait_stop again to continue listening.
    wait_stop()

if __name__ == '__main__':
    wait_stop()

Теперь вы можете запустить процесс в отдельной оболочке через:

python wait_stop.py

Пока оболочка процесса wait_stop НЕ является активным окном, нажатие ctrl+c приведет к отправке функции stop() в контроллер. Если окно активно, оно также уничтожит процесс wait_stop.py.

person James    schedule 30.11.2018
comment
Этот подход кажется наиболее перспективным на данный момент! К сожалению, контроллер может обрабатывать только одно сокетное соединение. Но я думаю, что могу поместить keyboard.wait(...) в поток, а затем использовать то же соединение сокета, что и в основном потоке. И насколько я понимаю, из-за использования GIL в многопоточности мне не нужно беспокоиться о том, что перекрывающиеся связи с контроллером все испортят. - person Rolli; 01.12.2018
comment
Я заметил, что для keyboard.wait() требуются привилегии root. Поэтому, чтобы использовать его в потоке, я думаю, мне нужно будет запустить основной поток от имени пользователя root, чего я не хочу. Есть ли альтернатива, которая не требует рута? - person Rolli; 02.12.2018
comment
Возможно, вы захотите изучить другой обработчик привязки клавиш, например Autokey [code.google.com/ архив/p/автоключ/] - person James; 02.12.2018

KeyboardInterrupt отправляет сигнал SIGINT (код 2).

Таким образом, вместо того, чтобы нажимать CTRL+C, вы можете отправить KeyboardInterrupt с помощью kill -2 <pid>.

Чтобы отобразить pid вашей программы, используйте os.getpid().

person Louis Saglio    schedule 30.11.2018
comment
На самом деле, я не хочу убивать программу. Я хочу иметь возможность вызывать какое-то действие в python (т.е. отправлять команду контроллеру), нажимая Ctrl+C - person Rolli; 30.11.2018