А прилагающаяся обертка на 1С под нее позволяет делать это комфортно и просто.
Внешняя компонента была написана, прежде всего, для сворачивания/разворачивания группировок в динамических списках.
Краткая предистория:
В свое время очень мучал вопрос сворачивания/разворачивания динамических списков. Ситуацию обостряло тысяча подобных вопросов в гугле и не одного толкового ответа (по крайней мере я не видел).
Проблема тогда была решена здоровенным костылем: запуском скомпилированного скрипта 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}in\r
// Также стоит подправить функции Подключить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.11s";
// Если её нет - пробуем скачать из 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
Как мне подсказал в комментариях Сергей Лесовой, для сворачивания/разворачивания дин. списка можно применить более изящное решение:
// Развернуть
Элементы.дСписок.Развернуть(ПредопределенноеЗначение("Справочник.СпрИмя.ПустаяСсылка"), Истина);
// Свернуть
Элементы.дСписок.Свернуть(ПредопределенноеЗначение("Справочник.СпрИмя.ПустаяСсылка"));
Правда такой подход не работает с иерархическим дин. списком, в то время как компонента отрабатывает нормально.
Компонента, Я полагаю, имеет право продолжать жить для других задач по автоматизации.
Related Posts
Получение логина и пароля техподдержки 1С из базы
Класс для вывода отчета в Excel
Счет-фактура для УПП
Библиотека классов для создания внешней компоненты 1С на C#
Акт об оказании услуг (со скидками) — внешняя печатная форма для Управление торговлей 11.1.10.86
Прайс-лист с артикулом в отдельной колонке
Я за альтернативу и разнообразие.
Вот еще решение от 1С) (сценарное тестирование 2)
WshShellW = Новый COMОбъект(«WScript.Shell»);
WshShellW.AppActivate(ПолучитьЗаголовокСистемы());
// Команда может состоять из одной буквы
ПозицияОткрывающейСкобки = Найти(ПередаваемыеДанные.СочетаниеКлавиш, «{«);
ПозицияЗакрывающейСкобки = Найти(ПередаваемыеДанные.СочетаниеКлавиш, «}»);
Если ПозицияОткрывающейСкобки <> 0 Тогда
Если ПозицияЗакрывающейСкобки — ПозицияОткрывающейСкобки — 1 = 1 Тогда
Буква = Сред(ПередаваемыеДанные.СочетаниеКлавиш, ПозицияОткрывающейСкобки + 1, 1);
Буква = ИСТП_ПреобразоватьБуквуВСоответствииСРаскладкой(Буква);
Команда = Сред(ПередаваемыеДанные.СочетаниеКлавиш, 1,ПозицияОткрывающейСкобки) + Буква + Сред(ПередаваемыеДанные.СочетаниеКлавиш, ПозицияЗакрывающейСкобки);
Иначе
Команда =ПередаваемыеДанные.СочетаниеКлавиш;
КонецЕсли;
Иначе
// скобок может и не быть
Команда = ПередаваемыеДанные.СочетаниеКлавиш;
ЕстьКТРЛ = Ложь;
ЕстьАЛЬТ = Ложь;
ЕстьШИФТ = Ложь;
Если Найти(Команда, «#k8SjZc9Dxk») > 0 Тогда
Команда = СтрЗаменить(Команда, «#k8SjZc9Dxk», «»);
ЕстьКТРЛ = Истина;
КонецЕсли;
Если Найти(Команда, «%») > 0 Тогда
Команда = СтрЗаменить(Команда, «%», «»);
ЕстьАЛЬТ = Истина;
КонецЕсли;
Если Найти(Команда, «+») > 0 Тогда
Команда = СтрЗаменить(Команда, «+», «»);
ЕстьШИФТ = Истина;
КонецЕсли;
Если СтрДлина(Команда) = 1 Тогда
Команда = ИСТП_ПреобразоватьБуквуВСоответствииСРаскладкой(Команда);
Если ЕстьШИФТ Тогда
Команда = «+» + Команда;
КонецЕсли;
Если ЕстьАЛЬТ Тогда
Команда = «%» + Команда;
КонецЕсли;
Если ЕстьКТРЛ Тогда
Команда = «#k8SjZc9Dxk» + Команда;
КонецЕсли;
Иначе
Команда = ПередаваемыеДанные.СочетаниеКлавиш;
КонецЕсли;
КонецЕсли;
WshShellW.SendKeys(Команда);
Показать
(1) Как Num-/Num+ передать?)
(1)
WshShellW.SendKeys(Команда);
работает не на всех системах, увы.
(3)https://ru.wikipedia.org/wiki/Windows_Script_Host
Естественно. Его Я тоже пробывал, но писечка в том, что оно не подошло, тк не скумекал как им симулировать нажатия Num- и Num+, а значит и не смог свернуть динамический список.
Вполне допускаю, что это возможно и хотелось бы услышать ответ от разобравшихся.
Вообще у меня к 1с есть несколько основных притензий:
1) У динамических списков нет родной кнопки и метода для свернуть/развернуть группировки, хотя это можно делать сочетанием клавиш.
2) На управляемых формах можно строить неплохой адаптивный интерфейс, но нельзя нормально в процентном отношении задавать размер элементов.
3) Модуль объекта не существует на клиенте (уж хотяб для обработок можно былоб сделать).
4) У объектов нельзя создавать собственный конструктор и деструктор.
Приходиться делать так а = Обработка.Создать(); а.Конструктор(параметры);
5) Очень хотелось бы увидеть инкремент и декримент хотяб.
А то Счетчик = Счетчик + 1; — не комильфо писать :3
Это очень странно, тк С++ вполне позволяет использовать перегрузки.
6) Из общего модуля клиента нельзя нормально вызывать модуль сервера.
Прошу прощения, за то, что излил свою попаболь)))
Что-то не понял насчет сворачивания/разворачивания, чем вариант вызвать такой код не подошел:
Элементы.Список.Развернуть(Элементы.Список.ТекущаяСтрока,Истина);
Элементы.Список.Свернуть(Элементы.Список.ТекущаяСтрока);
(5)
Я может чего и упускаю, но это работает только для обычных таблиц, но никак не для динамических списков.
Если ошибаюсь или чегот добавили — был бы благодарен за предоставленный пример. Я не представляю, как можно получить «Идентификатор строки таблицы.» у динамического списка. У него же нельзя перебирать содержимое, а значит не выйдет перебрать все и все свернуть. Самый максимум, что позволяет — по клику сворачивать текущую группировку.
Опять же, поправьте если не прав и ошибаюсь.
Ставлю плюс за идею!
(6) ну вот те строки кода, которые написал в (5), это доработка для конфигурации ITIL, там список задач сделан через динамический список с запросом, и этот код позволяет сворачивать/разворачивать подчиненные задачи. Возможно не сработает если в динамическом списке не указана основная таблица, особо не ковырялся в этом направлении.
(8) Тоесть, чтоб свернуть такой список
— Задачи
— Помыть посуду
— Подстричь газон
— Заправить постель
— Постирать носки
Вам надо: (a) тыкнуть на «Задачи», а затем (б) нажать кнопку которая вызовет ваш код (ну или разместить код в «ПриАктивизацииСтроки/Поля/Ячейки») и это свернет только данную группировку. Это не есть очень удобно, к томуже у вас может быть не 1 родительская группировка, а несколько.
Попробуйте погуглить по «свернуть динамический список 1с», увидите насколько остро стоит проблема у многих людей.
(9) Ну если нужно свернуть все задачи, то достаточно передать пустую ссылку в метод Свернуть(), даже активизировать ничего не нужно. В принципе можно даже сворачивать на любое количество уровней вверх, при условии что у вас в динамическом списке основной назначена таблица с иерархией. Набросал пример для 1С:Документооборот ну или любой конфигурации, где есть справочник ПапкиФайлов, в нем продемонстрировано то, о чем писал.
(10)
Сейчас детально посмотрю, в коде не обязательно ломиться на сервер:
Элементы.ДинСписок.Развернуть(ПолучитьПустуСсылкуНаСервере(),Истина);
Должно быть достаточно:
Элементы.ДинСписок.Развернуть(ПредопределенноеЗначение(«Справочник.ПапкиФайлов.ПустаяСсылка»),Истина);
(12) ну я не парился с качеством, просто показал принцип 🙂
а так да, лучше лишний раз на сервер не нырять
(3) компонента автора так же работает не на всех системах , поэтому я и привел пример с сендкейсом, более того я не вчитывался какую проблему решал автор, каюсь.
(4) эх тоже хотелось бы всех этих ООП штучек в 1С, но тогда будет риск превращения 1С в Microsoft Dynamics AX. по слухам бизнес, что успел подсесть на аксапта избавляется от нее и переводят учет на 1С по причинам: 1. В Аксапте разработка фич ведется дольше чем в 1С. 2. Дорогостоящие и труднонаходимые специалисты по сравнению с адынесниками
Компонента по какой технологии написано, ответьте пожалуйста.
(15) Это внешняя компонента, написана на плюсах, за основу брал пример от 1с.
Использует Win Api.
Примеры использования в публикации, вроде, были.
Если вам очень хочется попробывать, но нет/жаль стартмани — пишите в ЛС, отдам за спасибо, Я не жадина)
Тоже касается и сорцев, если у Вас есть человек, который сечет во внешних компонентах и С++, там нет ничего сверхестественного.
Моя телега, на всякий: @FoxWithBox
Спасибо за ответ, изначально не увидел в текстах кода с инициализацией, потом нашел и вопрос отпал, она по технологии Native ) В компонентах сам секу, на C# могу писать, на C++ для меня трудно, времени нету изучить его, шаблон даже есть где-то внешней на C#, только вот по технологии com помоему, а мне Native нужна. ) Спасибо за отзывчивость.
Что-то не работают оба варианта… у меня динамический список документов… вставляю разворот в процедуру ПриОткрытии() а открывается все равно свернуто…
(18) Попробуй через обработчик ожидания.
«При открытии» подключи.
Но перед глазами сейчас 1с’ки нет.
(19) Да, получилось в итоге с помощью ВК и обработчика ожидания.
(20) Рад, что мои набитые шишки кому то помогают :3
Я разворачиваю все группы Динамического списка так
Для каждого стр из Элементы.ДинСписок.ВыделенныеСтроки цикл
Элементы.ДинСписок.Развернуть(стр, истина);
Конеццикла;
(22)
Спасибо, собственно проблема была в том, чтоб развернуть и свернуть корень, а не выделенные строки.
Это решается таким способом:
Собственно я тогда был мал, глуп и неопытен :3
(23) ну ВК написать — не так мал ))