Краткая предистория:
В свое время очень мучал вопрос сворачивания/разворачивания динамических списков. Ситуацию обостряло тысяча подобных вопросов в гугле и не одного толкового ответа (по крайней мере я не видел).
Проблема тогда была решена здоровенным костылем: запуском скомпилированного скрипта AHK на сочетание Ctrl+Shift+Num-/Num+
Душа терзалась столь неизящным решением и вот наконец дошли руки сделать это чуть лучше и вдобавок слегка расширить функционал 1с.
Функционал:
Не буду долго тянуть, вк использует функцию Win Api - SendInput() для симуляции нажатий клавиш клавиатуры/мыши по виртуальным кодам.
Также в вк для удобства добавлена функция паузы и свойство определяющее продолжительность зажатия клавиши.
Для удобства в 1с создана обертка над вк, позволяющая использовать её весьма интуитивно, понятно и максимально просто.
Можно вызывать нажатие клавиши по её имени. Тестировал на Win Server 2012 R2 с Qwerty клавиатурой на 1с 8.3.10.2561.
Примеры использования:
Передаваемые в функции параметры довольно подробно описаны в общем модуле в сопровождении к функциям.
Конфигуратор подскажет, что писать.
Клавиатура.Пауза()
Клавиатура.Свернуть()
Клавиатура.Развернуть()
Клавиатура.ВыполнитьНажатие()
// Пауза на секунду
&НаКлиенте
Процедура Пауза(Команда)
Клавиатура.Пауза(1000);
КонецПроцедуры // Пауза()
// Свернуть динамический список
&НаКлиенте
Процедура Свернуть(Команда)
ЭтаФорма.ТекущийЭлемент = Элементы.Список;
Клавиатура.Свернуть();
КонецПроцедуры // Свернуть()
// Развернуть динамический список
&НаКлиенте
Процедура Развернуть(Команда)
ЭтаФорма.ТекущийЭлемент = Элементы.Список;
Клавиатура.Развернуть();
КонецПроцедуры // Развернуть()
// Пример ввода в текстовое поле через
// симуляцию нажатия клавиш несколькими способами
&НаКлиенте
Процедура СимуляцияВвода(Команда)
ЭтаФорма.ТекущийЭлемент = Элементы.Строка;
// Ввод в текстовое поле через массив
МассивВвода = Новый Массив;
МассивВвода.Добавить(Новый Структура("Кнопка", "Enter"));
МассивВвода.Добавить(Новый Структура("Кнопка,Режим", "LSHIFT", Истина));
МассивВвода.Добавить(Новый Структура("Кнопка", "Р"));
МассивВвода.Добавить(Новый Структура("Кнопка,Режим", "LSHIFT", "ОТПУСТИТЬ"));
МассивВвода.Добавить(Новый Структура("Кнопка", "А"));
МассивВвода.Добавить(Новый Структура("Кнопка", "М", Неопределено));
МассивВвода.Добавить(Новый Структура("Кнопка", "У"));
// Ввод в текстовое поле через строку
Если Клавиатура.ВыполнитьНажатие("LCONTROL ВНИЗ;A;LCONTROL ВВЕРХ") // Ctrl + A
И Клавиатура.ВыполнитьНажатие("LSHIFT D;М;LSHIFT U;А;М;А;"+Символы.ПС+";LSHIFT PRESS;М;;Ы;;Л;;А;LSHIFT RELEASE") // Мама {След. строка} М Ы Л А
И Клавиатура.ВыполнитьНажатие(МассивВвода, 10) // Раму
Тогда Сообщить("Успех")
Иначе Сообщить("Неудача")
КонецЕсли;
КонецПроцедуры // СимуляцияВвода()
Листинг основного функционала общего модуля:
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
// !!!! МОДУЛЬ ТОЛЬКО ДЛЯ СИСТЕМ WINDOWS, НАЧИНАЯ С 2000 !!!!
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
// ~~~~~ ~~~~~ ~~~~~ ~~~~~ ~~~~~ ~~~~~ ~~~~~ ~~~~~ ~~~~~ ~~~~~
// Модуль использует внешнюю компоненту AddInKeyboardInput.dll
// У ВК 2 метода: Send() и Sleep()
// Send() - симуляция клавиатуры и мыши через WinApi SendInput.
// Sleep() - пауза на N мс.
//
// В Send() передается 2 параметра.
// 1 - [обязательный](2 символа строкой) hex код клавиши
// 2 - [не обязательный](булево) (True - зажать, False - отпустить)
// если не передать параметр, то клавиша нажмется и отпуститься
//
// В Sleep() передается 1 параметр.
// 1 - [обязательный](число) количество миллисекунд паузы.
//
// Функции возвращают true/false в зависимости от того, удалось
// ли им отработать.
//
// Расположите компоненту в папке C:\Program Files (x86)\1cv8\{A.B.CC.DDDD}\bin\
// Также стоит подправить функции ПодключитьKeyboardInput() и НаличиеKeyboardInput()
// на предмет загрузки компоненты пользователям у которых её нет в наличии.
// Для загрузки используется SAMBA сервер (стандартная виндовая общая папка).
// Альтернативой можно, например, загружать ДД из общего макета или из справочника файлов
// или по FTP или URL.
// ~~~~~ ~~~~~ ~~~~~ ~~~~~ ~~~~~ ~~~~~ ~~~~~ ~~~~~ ~~~~~ ~~~~~
#Область Основной_функционал
// ~~~~~ ~~~~~ ~~~~~ ВЫПОЛНИТЬ НАЖАТИЕ ~~~~~ ~~~~~ ~~~~~ ~~~~~
// Функция инициализирует внешнюю компоненту и последовательно
// "нажимает" переданные виртуальные клавиши через WinApi SendInput.
//
// Примеры вызова:
// МассивВвода = Новый Массив;
// МассивВвода.Добавить(Новый Структура("Кнопка,Режим", "LSHIFT", Истина));
// МассивВвода.Добавить(Новый Структура("Кнопка", "М"));
// МассивВвода.Добавить(Новый Структура("Кнопка,Режим", "LSHIFT", "ОТПУСТИТЬ"));
// МассивВвода.Добавить(Новый Структура("Кнопка", "а"));
// МассивВвода.Добавить(Новый Структура("Кнопка", "м", Неопределено));
// МассивВвода.Добавить(Новый Структура("Кнопка", "а"));
// Клавиатура.ВыполнитьНажатие(МассивВвода, 10);
//
// Клавиатура.ВыполнитьНажатие("LSHIFT D;м;LSHIFT U;а;м;а");
//
//
// Функция возвращает булево:
// Истина - Успешно и без ошибок отработаны все нажатия.
// Ложь - Неудача, возможно произошла ошибка при
// загрузке компоненты или неверно переданы параметры
// или функцию запустили не на OS Windows.
//
// Параметры:
// Нажатия - [обязательный](строка или структура или массив)
// параметром передаются клавиши на последовательное нажатие (регистр неважен).
// Нажатие определяется самое клавишей, определение которой задается
// её виртуальным кодом или мнемоническим значением, например
// клавиша Enter может быть определена как "Enter" так и "0D".
// Если вы определяете клавишу виртуальным кодом, убедитесь, что это
// число в 16-ричной системе счисления и состоит из двух символов!
// Также нажатие определяется опциональным "Режимом", который
// показывает, стоит зажать клавишу или отпустить или нажать и отпустить.
// Нажать: "НАЖАТЬ","DOWN","ИСТИНА","PRESS","ВНИЗ","D","P" или Истина
// Отпустить: "ОТПУСТИТЬ","UP","ЛОЖЬ","RELEASE","ВВЕРХ","U","R" или Ложь
// Нажать и отпустить: "" или Неопределено или просто опустить значение
// .
// Нажатия можно задать через строку с разделителями ";"
// Например: " LCONTROL ВНИЗ; A ; LCONTROL ВВЕРХ"
// .
// Также можно задать через структуру с двумя ключами: "Кнопка" и "Режим"
// Например: Новый Структура("Кнопка,Режим", "LSHIFT", Истина))
// .
// Также можно через массив подобных структур.
// В таком случае нажатия выполнятся последовательно.
//
// Зажатие - [необязательный](число)
// Время удерживания клавиши в мс если оно вызвано без "Режима" (нажать и отпустить).
// По умолчанию: 25 миллисекунд.
Функция ВыполнитьНажатие(Знач Нажатия, Знач Зажатие = 25) Экспорт
ki = ПодключитьKeyboardInput();
Если ki = Неопределено Тогда Возврат Ложь КонецЕсли;
ki.Cooldown = Зажатие;
// Действую согласно типу входных данных
МассивНажатий = Новый Массив;
Если ТипЗнч(Нажатия) = Тип("Строка") Тогда
МассивНажатий = СтрокуВМассивНажатий(Нажатия);
ИначеЕсли ТипЗнч(Нажатия) = Тип("Структура") И Нажатия.Свойство("Кнопка") Тогда
МассивНажатий.Добавить(Нажатия);
ИначеЕсли ТипЗнч(Нажатия) = Тип("Массив") Тогда
МассивНажатий = Нажатия;
Иначе
Возврат Ложь;
КонецЕсли; // Если ТипЗнч(Нажатия) = Тип("Строка")
// Перебираю массив и возвращаю с элементами в ожидаемом, для вк, виде
Если Не ПолучитьВиртуальныйКод(МассивНажатий) Тогда Возврат Ложь КонецЕсли;
// Выполняю запланированные нажатия
Результат = Истина;
Попытка
Для Каждого Нажатие Из МассивНажатий Цикл
Если Нажатие.Свойство("Режим")
И Нажатие.Режим <> Неопределено
Тогда Результат = ?(ki.Send(Нажатие.Кнопка, Нажатие.Режим), Результат, Ложь)
Иначе Результат = ?(ki.Send(Нажатие.Кнопка), Результат, Ложь)
КонецЕсли; // Выполняю запланированое нажатие
КонецЦикла;
Исключение
Сообщение = Новый СообщениеПользователю;
Сообщение.Текст = ("Во время симуляции нажатий произошла непредвиденная ошибка.
|Обратитесь к программистам!" + Символы.ПС + ОписаниеОшибки());
Сообщение.Сообщить();
Возврат Ложь;
КонецПопытки; // Что то пошло не так во время исполнения вк.
Возврат Результат;
КонецФункции // ВыполнитьНажатие() Экспорт
// ~~~~~ ~~~~~ ~~~~~ ~~~~~ ~~~~~ ~~~~~ ~~~~~ ~~~~~ ~~~~~ ~~~~~
// ~~~~~ ~~~~~ ~~~~~ П А У З А ~~~~~ ~~~~~ ~~~~~ ~~~~~
// Функция инициализирует внешнюю компоненту и ждет N мс.
//
// Примеры вызова:
// Клавиатура.Пауза(1000);
//
// Функция возвращает булево:
// Истина - Успешно и без ошибок отработана пауза.
// Ложь - Неудача, возможно произошла ошибка при
// загрузке компоненты или функцию запустили не на OS Windows.
//
// Параметры:
// Зажатие - [необязательный](число)
// Время паузы в мс.
// По умолчанию: 1000 мс (1 секунда).
Функция Пауза(Знач мс = 1000) Экспорт
ki = ПодключитьKeyboardInput();
Если ki = Неопределено Тогда Возврат Ложь КонецЕсли;
Попытка
Возврат ki.Sleep(мс);
Исключение
Сообщение = Новый СообщениеПользователю;
Сообщение.Текст = ("Во время попытки паузы произошла ошибка.
|Обратитесь к программистам!" + Символы.ПС + ОписаниеОшибки());
Сообщение.Сообщить();
Возврат Ложь;
КонецПопытки;
КонецФункции // Пауза() Экспорт
// ~~~~~ ~~~~~ ~~~~~ ~~~~~ ~~~~~ ~~~~~ ~~~~~ ~~~~~ ~~~~~ ~~~~~
// ~~~~~ ~~~~~ ~~~~~ СВЕРНУТЬ ~~~~~ ~~~~~ ~~~~~ ~~~~~
// Функция сворачивает динамический список сочетанием клавиш:
// Ctrl + Shift + Num-
// НЕ ЗАБУДЬТЕ ПРЕДВАРИТЕЛЬНО УСТАНОВИТЬ НА НЕМ ФОКУС!
//
// Примеры вызова:
// ЭтаФорма.ТекущийЭлемент = Элементы.Список;
// Клавиатура.Свернуть();
//
// Функция возвращает булево:
// Истина - Успешно и без ошибок отработана пауза.
// Ложь - Неудача, возможно произошла ошибка при
// загрузке компоненты или функцию запустили не на OS Windows.
Функция Свернуть() Экспорт
МассивНажатий = Новый Массив;
МассивНажатий.Добавить(Новый Структура("Кнопка,Режим","A2",Истина));
МассивНажатий.Добавить(Новый Структура("Кнопка,Режим","A0",Истина));
МассивНажатий.Добавить(Новый Структура("Кнопка,Режим","6D",Неопределено));
МассивНажатий.Добавить(Новый Структура("Кнопка,Режим","A0",Ложь));
МассивНажатий.Добавить(Новый Структура("Кнопка,Режим","A2",Ложь));
Попытка
Возврат ВыполнитьНажатие(МассивНажатий, 25);
Исключение
Сообщение = Новый СообщениеПользователю;
Сообщение.Текст = ("Произошла ошибка.
|Обратитесь к программистам!" + Символы.ПС + ОписаниеОшибки());
Сообщение.Сообщить();
Возврат Ложь;
КонецПопытки;
КонецФункции // Свернуть() Экспорт
// ~~~~~ ~~~~~ ~~~~~ ~~~~~ ~~~~~ ~~~~~ ~~~~~ ~~~~~ ~~~~~ ~~~~~
// ~~~~~ ~~~~~ ~~~~~ РАЗВЕРНУТЬ ~~~~~ ~~~~~ ~~~~~ ~~~~~
// Функция разворачивает динамический список сочетанием клавиш:
// Ctrl + Shift + Num+
// НЕ ЗАБУДЬТЕ ПРЕДВАРИТЕЛЬНО УСТАНОВИТЬ НА НЕМ ФОКУС!
//
// Примеры вызова:
// ЭтаФорма.ТекущийЭлемент = Элементы.Список;
// Клавиатура.Развернуть();
//
// Функция возвращает булево:
// Истина - Успешно и без ошибок отработана пауза.
// Ложь - Неудача, возможно произошла ошибка при
// загрузке компоненты или функцию запустили не на OS Windows.
Функция Развернуть() Экспорт
МассивНажатий = Новый Массив;
МассивНажатий.Добавить(Новый Структура("Кнопка,Режим","A2",Истина));
МассивНажатий.Добавить(Новый Структура("Кнопка,Режим","A0",Истина));
МассивНажатий.Добавить(Новый Структура("Кнопка,Режим","6B",Неопределено));
МассивНажатий.Добавить(Новый Структура("Кнопка,Режим","A0",Ложь));
МассивНажатий.Добавить(Новый Структура("Кнопка,Режим","A2",Ложь));
Попытка
Возврат ВыполнитьНажатие(МассивНажатий, 25);
Исключение
Сообщение = Новый СообщениеПользователю;
Сообщение.Текст = ("Произошла ошибка.
|Обратитесь к программистам!" + Символы.ПС + ОписаниеОшибки());
Сообщение.Сообщить();
Возврат Ложь;
КонецПопытки;
КонецФункции // Развернуть() Экспорт
// ~~~~~ ~~~~~ ~~~~~ ~~~~~ ~~~~~ ~~~~~ ~~~~~ ~~~~~ ~~~~~ ~~~~~
#КонецОбласти
Листинг вспомогательного функционала общего модуля:
#Область Вспомогательные_функции
Функция ПодключитьKeyboardInput()
// Отбрасываю мобильные приложения и веб клиенты
#Если МобильноеПриложениеКлиент Или ВебКлиент Тогда
Возврат Неопределено;
#КонецЕсли
// Проверяем, есть ли у нас необходимая библиотека AddInKeyboardInput.dll
Путь = КаталогПрограммы();
Библиотека = "AddInKeyboardInput.dll";
СетеваяПапка = "\\127.0.0.1\1s\";
// Если её нет - пробуем скачать из SMB шары
Если Не НаличиеKeyboardInput(Путь, Библиотека, СетеваяПапка) Тогда
Сообщение = Новый СообщениеПользователю;
Сообщение.Текст = ("Не выходит подключить библиотеку AddInKeyboardInput.dll.
|Обратитесь к программистам!");
Сообщение.Сообщить();
Возврат Неопределено;
КонецЕсли;
// Подключаю внешнюю компоненту
Если Не ПодключитьВнешнююКомпоненту(Путь+Библиотека, "ki", ТипВнешнейКомпоненты.Native)
Тогда Возврат Неопределено КонецЕсли;
ki = Новый("AddIn.ki.KeyboardInput");
Возврат ki;
КонецФункции // ПодключитьKeyboardInput()
// Проверяю наличие библиотеки в папке с 1с.
// Если её нет - скачиваю с SMB шары.
// Хотя альтернативой можно, например, загружать ДД
// из общего макета или из справочника файлов.
Функция НаличиеKeyboardInput(Знач Путь, Знач Библиотека, Знач СетеваяПапка)
// Проверяю на наличие dll
Папка = Новый Файл(Путь);
Если Не Папка.Существует() Тогда // Проверяю на наличие директории программы
Сообщение = Новый СообщениеПользователю;
Сообщение.Текст = (СтрШаблон("Папки (%1) не существует.
|Обратитесь к программистам!", Путь));
Сообщение.Сообщить();
Возврат Ложь;
КонецЕсли; // Если Не Папка.Существует()
Файл = Новый Файл(Путь+Библиотека);
ЕСЛИ Файл.Существует() ТОГДА
Возврат Истина;
Иначе // Надо скачать библиотеку.
// // // // // // // // // // // // // // // //
// // Скачиваем из сетевой SAMBA шары:
Папка = Новый Файл(СетеваяПапка);
Если Не Папка.Существует() Тогда // Проверяю на наличие сетевой папки
Сообщение = Новый СообщениеПользователю;
Сообщение.Текст = (СтрШаблон("Сетевой папки (%1) не существует.
|Обратитесь к программистам!", СетеваяПапка));
Сообщение.Сообщить();
Возврат Ложь;
КонецЕсли; // Если Не Папка.Существует()
Файл = Новый Файл(СетеваяПапка+Библиотека);
Если Файл.Существует() Тогда
ФайлИсточник = СетеваяПапка+Библиотека;
ФайлПриемник = Путь+Библиотека;
Попытка
КопироватьФайл(ФайлИсточник, ФайлПриемник);
Исключение
Сообщение = Новый СообщениеПользователю;
Сообщение.Текст = ("Не выходит подключить библиотеку AddInKeyboardInput.dll.
|Обратитесь к программистам!");
Сообщение.Сообщить();
Возврат Ложь;
КонецПопытки; // Попытка КопироватьФайл(ФайлИсточник, ФайлПриемник)
Если Не Файл.Существует() Тогда
Сообщение = Новый СообщениеПользователю;
Сообщение.Текст = ("Не выходит подключить библиотеку AddInKeyboardInput.dll.
|Обратитесь к программистам!");
Сообщение.Сообщить();
Возврат Ложь;
КонецЕсли;
Иначе
Возврат Ложь;
КонецЕсли; // Если Файл.Существует()
КОНЕЦЕСЛИ; // ЕСЛИ Файл.Существует()
Возврат Истина;
КонецФункции // НаличиеKeyboardInput()
// Привожу строку в массив действий
Функция СтрокуВМассивНажатий(Знач Строка)
МассивНажатий = Новый Массив;
Для Каждого Нажатие Из СтрРазделить(Строка, ";", Истина) Цикл
Нажатие = СокрПробелЛП(Нажатие);
Нажатие = СтрРазделить(Нажатие, " ", Истина);
МассивНажатий.Добавить(Новый Структура("Кнопка,Режим",
Нажатие[0],
?(Нажатие.Количество()>1, Нажатие[1], Неопределено)));
КонецЦикла; // Для Каждого Нажатие Из СтрРазделить(Строка, ";", Ложь)
Возврат МассивНажатий;
КонецФункции // СтрокуВМассивНажатий()
// Тут всячески проверяю валидность переданного массива.
// Заменяю мнемонические коды клавиш на виртуальные.
// Перевожу режимы в булево.
// По сути эта функция не нужна, если передавать верные данные сразу
// в виде структуры:
// Новый Структура("Кнопка,Режим",
// "5B", // Два HEX символа
// Неопределено) // Истина/Ложь/Неопределено
Функция ПолучитьВиртуальныйКод(МассивНажатий)
// Соотсветсвие кирилицы - латинице на qwerty клавиатуре
рРаскладка =
СтрРазделить(
"А;Б;В;Г;Д;Е;Ё;Ж;З;И;Й;К;Л;М;Н;О;П;Р;С;Т;У;Ф;Х;Ц;Ч;Ш;Щ;Ъ;Ы;Ь;Э;Ю;Я;ENTER;;" + Символы.НПП + ";" + Символы.ПС + ";" + Символы.Таб,
";", Истина);
аРаскладка =
СтрРазделить(
"F;OEM_COMMA;D;U;L;T;OEM_3;OEM_1;P;B;Q;R;K;V;Y;J;G;H;C;N;E;A;OEM_4;W;X;I;O;OEM_6;S;M;OEM_7;OEM_PERIOD;Z;RETURN;SPACE;SPACE;RETURN;TAB",
";", Истина);
// Соответсвие мнемонических обозначений - виртуальным кодам клавиатуры
// (Возможно в будующем добавлю и скан коды)
vkCodes = // ;Ключ:Код Должно начинаться с ";"
";ABNT_C1:0xC1;ABNT_C2:0xC2;ADD:0x6B;ATTN:0xF6;BACK:0x08;
|CANCEL:0x03;CLEAR:0x0C;CRSEL:0xF7;DECIMAL:0x6E;DIVIDE:0x6F;
|EREOF:0xF9;ESCAPE:0x1B;EXECUTE:0x2B;EXSEL:0xF8;
|ICO_CLEAR:0xE6;ICO_HELP:0xE3;0:0x30;1:0x31;2:0x32;3:0x33;
|4:0x34;5:0x35;6:0x36;7:0x37;8:0x38;9:0x39;A:0x41;B:0x42;
|C:0x43;D:0x44;E:0x45;F:0x46;G:0x47;H:0x48;I:0x49;J:0x4A;
|K:0x4B;L:0x4C;M:0x4D;N:0x4E;O:0x4F;P:0x50;Q:0x51;R:0x52;
|S:0x53;T:0x54;U:0x55;V:0x56;W:0x57;X:0x58;Y:0x59;Z:0x5A;
|MULTIPLY:0x6A;NONAME:0xFC;NUMPAD0:0x60;NUMPAD1:0x61;
|NUMPAD2:0x62;NUMPAD3:0x63;NUMPAD4:0x64;NUMPAD5:0x65;
|NUMPAD6:0x66;NUMPAD7:0x67;NUMPAD8:0x68;NUMPAD9:0x69;
|OEM_1:0xBA;OEM_102:0xE2;OEM_2:0xBF;OEM_3:0xC0;OEM_4:0xDB;
|OEM_5:0xDC;OEM_6:0xDD;OEM_7:0xDE;OEM_8:0xDF;OEM_ATTN:0xF0;
|OEM_AUTO:0xF3;OEM_AX:0xE1;OEM_BACKTAB:0xF5;OEM_CLEAR:0xFE;
|OEM_COMMA:0xBC;OEM_COPY:0xF2;OEM_CUSEL:0xEF;OEM_ENLW:0xF4;
|OEM_FINISH:0xF1;OEM_FJ_LOYA:0x95;OEM_FJ_MASSHOU:0x93;
|OEM_FJ_ROYA:0x96;OEM_FJ_TOUROKU:0x94;OEM_JUMP:0xEA;
|OEM_MINUS:0xBD;OEM_PA1:0xEB;OEM_PA2:0xEC;OEM_PA3:0xED;
|OEM_PERIOD:0xBE;OEM_PLUS:0xBB;OEM_RESET:0xE9;
|OEM_WSCTRL:0xEE;PA1:0xFD;PACKET:0xE7;PLAY:0xFA;
|PROCESSKEY:0xE5;RETURN:0x0D;SELECT:0x29;SEPARATOR:0x6C;
|SPACE:0x20;SUBTRACT:0x6D;TAB:0x09;ZOOM:0xFB;_none_:0xFF;
|ACCEPT:0x1E;APPS:0x5D;BROWSER_BACK:0xA6;
|BROWSER_FAVORITES:0xAB;BROWSER_FORWARD:0xA7;
|BROWSER_HOME:0xAC;BROWSER_REFRESH:0xA8;BROWSER_SEARCH:0xAA;
|BROWSER_STOP:0xA9;CAPITAL:0x14;CONVERT:0x1C;DELETE:0x2E;
|DOWN:0x28;END:0x23;F1:0x70;F10:0x79;F11:0x7A;F12:0x7B;
|F13:0x7C;F14:0x7D;F15:0x7E;F16:0x7F;F17:0x80;F18:0x81;
|F19:0x82;F2:0x71;F20:0x83;F21:0x84;F22:0x85;F23:0x86;
|F24:0x87;F3:0x72;F4:0x73;F5:0x74;F6:0x75;F7:0x76;F8:0x77;
|F9:0x78;FINAL:0x18;HELP:0x2F;HOME:0x24;ICO_00:0xE4;
|INSERT:0x2D;JUNJA:0x17;KANA:0x15;KANJI:0x19;
|LAUNCH_APP1:0xB6;LAUNCH_APP2:0xB7;LAUNCH_MAIL:0xB4;
|LAUNCH_MEDIA_SELECT:0xB5;LBUTTON:0x01;LCONTROL:0xA2;
|LEFT:0x25;LMENU:0xA4;LSHIFT:0xA0;LWIN:0x5B;MBUTTON:0x04;
|MEDIA_NEXT_TRACK:0xB0;MEDIA_PLAY_PAUSE:0xB3;
|MEDIA_PREV_TRACK:0xB1;MEDIA_STOP:0xB2;MODECHANGE:0x1F;
|NEXT:0x22;NONCONVERT:0x1D;NUMLOCK:0x90;OEM_FJ_JISHO:0x92;
|PAUSE:0x13;PRINT:0x2A;PRIOR:0x21;RBUTTON:0x02;RCONTROL:0xA3;
|RIGHT:0x27;RMENU:0xA5;RSHIFT:0xA1;RWIN:0x5C;SCROLL:0x91;
|SLEEP:0x5F;SNAPSHOT:0x2C;UP:0x26;VOLUME_DOWN:0xAE;
|VOLUME_MUTE:0xAD;VOLUME_UP:0xAF;XBUTTON1:0x05;XBUTTON2:0x06;";
vkCodes = СтрЗаменить(vkCodes, Символы.ПС, "");
ДЛЯ иНажатия = 0 ПО МассивНажатий.вГраница() ЦИКЛ
// Обрабатываю кнопки:
// Ленивым условием отбрасываю явные ошибки
Если ТипЗнч(МассивНажатий[иНажатия]) <> Тип("Структура")
Или Не МассивНажатий[иНажатия].Свойство("Кнопка")
Или ТипЗнч(МассивНажатий[иНажатия].Кнопка) <> Тип("Строка")
Тогда Возврат Ложь КонецЕсли;
// Привожу в ожидаемый вид
МассивНажатий[иНажатия].Кнопка = ВРег(СокрПробелЛП(МассивНажатий[иНажатия].Кнопка));
// Ищу русские символы и заменяю на латинские
Для нСимвола = 0 По рРаскладка.ВГраница() Цикл
Если МассивНажатий[иНажатия].Кнопка = рРаскладка[нСимвола] Тогда
МассивНажатий[иНажатия].Кнопка = аРаскладка[нСимвола];
КонецЕсли; // Если МассивНажатий[иНажатия].Кнопка = рРаскладка[иСимвола]
КонецЦикла; // ДЛЯ иНажатия = 0 ПО МассивНажатий.вГраница()
// Заменяю мнемонический код на виртуальный код
// (может в будующем добавлю и скан коды)
// ;key:0x
нСимвола = СтрНайти(vkCodes, СтрШаблон(";%1:0x", МассивНажатий[иНажатия].Кнопка));
Если нСимвола Тогда
МассивНажатий[иНажатия].Кнопка = Сред(vkCodes, (нСимвола + СтрДлина(МассивНажатий[иНажатия].Кнопка)+4), 2);
Иначе // Если был передан сразу виртуальный код, то надо проверить его на валидность
// Предпологается, что он будет длиной в 2 символа
Если СтрДлина(МассивНажатий[иНажатия].Кнопка) = 2
Тогда а=0;
ИначеЕсли (СтрДлина(МассивНажатий[иНажатия].Кнопка) = 4 И Лев(МассивНажатий[иНажатия].Кнопка, 2) = "0X")
Или (СтрДлина(МассивНажатий[иНажатия].Кнопка) = 3 И Лев(МассивНажатий[иНажатия].Кнопка, 1) = "X")
Тогда МассивНажатий[иНажатия].Кнопка = Прав(МассивНажатий[иНажатия].Кнопка, 2)
Иначе Возврат Ложь
КонецЕсли;
// Должен содержать только 0-1 и A-F
Для нСимвола = 1 По 2 Цикл
Символ = КодСимвола(МассивНажатий[иНажатия].Кнопка, нСимвола);
Если Не ((Символ>47 И Символ<58)
Или (Символ>64 И Символ<71))
Тогда Возврат Ложь КонецЕсли;
КонецЦикла; // Для нСимвола = 1 По 2
КонецЕсли; // Если нСимвола
// Обрабатываю режимы:
Если Не МассивНажатий[иНажатия].Свойство("Режим")
Тогда МассивНажатий[иНажатия].Вставить("Режим", Неопределено)
ИначеЕсли Не (МассивНажатий[иНажатия].Режим = Неопределено
Или ТипЗнч(МассивНажатий[иНажатия].Режим) = Тип("Булево")
Или ТипЗнч(МассивНажатий[иНажатия].Режим) = Тип("Строка"))
Тогда Возврат Ложь
ИначеЕсли ТипЗнч(МассивНажатий[иНажатия].Режим) = Тип("Строка")
И МассивНажатий[иНажатия].Режим = ""
Тогда МассивНажатий[иНажатия].Вставить("Режим", Неопределено)
ИначеЕсли ТипЗнч(МассивНажатий[иНажатия].Режим) = Тип("Строка")
И СтрНайти("'НАЖАТЬ','DOWN','ИСТИНА','PRESS','ВНИЗ','D','P'", СтрШаблон("'%1'",ВРег(МассивНажатий[иНажатия].Режим)))
Тогда МассивНажатий[иНажатия].Вставить("Режим", Истина)
ИначеЕсли ТипЗнч(МассивНажатий[иНажатия].Режим) = Тип("Строка")
И СтрНайти("'ОТПУСТИТЬ','UP','ЛОЖЬ','RELEASE','ВВЕРХ','U','R'", СтрШаблон("'%1'",ВРег(МассивНажатий[иНажатия].Режим)))
Тогда МассивНажатий[иНажатия].Вставить("Режим", Ложь)
КонецЕсли; // Обрабатываю режимы конец условия
КОНЕЦЦИКЛА; // Для Счетчик = 0 По МассивНажатий.вГраница()
Возврат Истина;
КонецФункции // ПолучитьВиртуальныйКод()
// Аналог СокрЛП(), но искючительно для пробелов.
// Также сокращает двойные пробелы
Функция СокрПробелЛП(Знач Строка)
// Убираю двойные пробелы
Пока СтрНайти(Строка, " ") Цикл Строка = СтрЗаменить(Строка, " ", " ") КонецЦикла;
// Убираю пробелы по бокам
Пока Лев(Строка, 1) = " " Цикл Строка = Сред(Строка, 2) КонецЦикла;
Пока Прав(Строка, 1) = " " Цикл Строка = Сред(Строка, 1, (СтрДлина(Строка)-1)) КонецЦикла;
Возврат Строка;
КонецФункции
#КонецОбласти
Послесловие:
Во вложении будет архив, в нем: тестовая конфигурация с примерами использования, утилитой для определения кодов клавиш, текстовый файл с ссылкой на вирустотал, xls документ с используемыми соответсвиями названиями и кодами клавиш, листинг общего модуля и собственно сама подключаемая библиотека. Надеюсь хоть комуто смог помочь, также прошу прощения за очепятки и абшибки. Повторюсь, компонента только для OS Windows начиная с 2000 , тоесть, по сути, должна работать только на любой современной Windows оси, в процессе использования она сама откидывает линь, мак, мобильное приложение и браузер, функции возвращают Ложь, вместо Истина. Возможно будет работать через Wine, такого Я не пробывал, не знаю.
ЕСЛИ У ВАС ВОЗНИКЛИ ВОПРОСЫ, С УДОВОЛЬСТВИЕМ ОТВЕЧУ В КОММЕНТАРИЯХ ИЛИ ЛС
UPD 17.10.19
Как мне подсказал в комментариях Сергей Лесовой, для сворачивания/разворачивания дин. списка можно применить более изящное решение:
// Развернуть
Элементы.дСписок.Развернуть(ПредопределенноеЗначение("Справочник.СпрИмя.ПустаяСсылка"), Истина);
// Свернуть
Элементы.дСписок.Свернуть(ПредопределенноеЗначение("Справочник.СпрИмя.ПустаяСсылка"));
Правда такой подход не работает с иерархическим дин. списком, в то время как компонента отрабатывает нормально.
Компонента, Я полагаю, имеет право продолжать жить для других задач по автоматизации.