Вызов метода по событию


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

Объект system содержит методы для реализации данного функционала

Давайте стразу перейдем к примеру. Привяжем вызов метода на клавишу 1

system.onKeyPress('hello','1');

function hello(){
    system.println('hello');
}

После выполнения данного скрипта, каждый раз когда мы будем нажимать клавишу 1 будет выводиться сообщение hello. Одна есть одна проблема. Если на долго зажать клавишу, то медот будет вызван множество рад, так как печатная клавиша начнет повторятся. Частота данного повторения зависит от настроек вашей системы.

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

system.onKeyPress('hello','1',' world');

function hello(text){
    system.println('hello'+text);
}

Изменим прошлый пример. Теперь при нажатие клавиши 1 будет вызван метод, который будет выводить в консоль не короткое сообщение, числа от 0 до 9 с некоторой перодичностью. Поскольку данный метод теперь выполняется достаточно медленно, что произойдет, если нажать неско раз подряд на клавишу 1?

system.onKeyPress('hello','1');

function hello(){
    for(i=0;i<10;i++){
        system.println(i);
        system.sleep(200);
    }
}

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

Обратите внимание, что вызов метода происходит в новом потоке, а значит он может конфликтовать в равной степени со всеми остальными потоками.

Однако, если все же необходимо чтобы данный метод мог вызывать более одного раза одновременно, существует метод setMaxThreads(String name, int maxThreads), он указывает системе максимальное количество потоков, которые могут одновременно войти в данный метод.

system.onKeyPress('hello','1');
system.setMaxThreads('hello',2);

function hello(){
    for(var i=0;i<10;i++){
        system.println(i);
        system.sleep(200);
    }
}

Теперь при повторном нажатии клавиши 1 метод будет вызван второй раз

Обратите внимение на то, что было изменено объявление переменной var i=0, было доблено ключевое слово var. Если этого не сделать, то переменная является общей для потоков и при повторном заходе ее значение будет установлено как 0 и уже два потока начнут совместно ее увеличивать. Попробуйте это сделать.

Существует еще одна проблема. Что если метод привязанный к клавише 1 сам будет содержать вызов клавиши 1? А произойдет то, событие будет сгенерированно как положенно и метод будет взван повторно.

system.onKeyPress('hello','1');
system.setMaxThreads('hello',2);

function hello(){
    system.sleep(100);
    key.perform('1','PRESS');
    system.sleep(100);
    key.perform('1','RELEASE');

    for(var i=0;i<10;i++){
        system.println(i);
        system.sleep(200);
    }
}

Чтобы избежать нежательных вызовов существуют методы для включения игнорирования событий клавиатуры и мыши

Где соответсвенно ignore - это метод для игнорирования событий, а resume восстанавливает работу.

Все вызовы клавитуры или мыши, которые будут вызваны между этими двумя методами, будут выполнятся как и прежде, но теперь никак не влияют на вызов методов из скрипта

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

Теперь изменив пример получим следующий скрипт

system.onKeyPress('hello','1');
system.setMaxThreads('hello',2);

function hello(){
    system.sleep(100);
    
    system.keyIgnore();
    key.perform('1','PRESS');
    system.keyResume();
    
    system.sleep(100);
    key.perform('1','RELEASE');

    for(var i=0;i<10;i++){
        system.println(i);
        system.sleep(200);
    }
}

Мы обернули данными методами только один проблемный вызов key.perform('1','PRESS'); что полностью решило проблему. Рекомендованно поступать так же, игнорировать события по минимуму. Можно, к примеру, обернуть и весь метод целиком, что опредленно будет работать, но сделает невозможным выхов его и других методов на время его работы.