Каждый специалист, занимающийся автоматизацией торгового оборудования в среде 1С, рано или поздно сталкивается с классической проблемой: сканер штрихкодов подключен по USB в режиме эмуляции клавиатуры (USB HID). При сканировании в Блокнот (Notepad) штрихкод и последующий перенос строки (клавиша Enter) приходят стабильно в 100% случаев. Однако при попытке отсканировать тот же штрихкод в форму 1С платформа успешно считывает цифры, но автопереход на следующую строку (или подтверждение ввода) срабатывает лишь в 20% случаев. В остальных 80% случаев пользователю приходится вручную нажимать клавишу Enter на физической клавиатуре.
В этой статье мы подробно разберем, почему возникает этот сбой, проанализируем физику процесса взаимодействия сканера и платформы 1С, а также рассмотрим по шагам эффективные методы решения этой проблемы — как на аппаратном уровне самого сканера, так и на программном уровне конфигурации 1С.
Для того чтобы решить проблему, нам необходимо понять физиологию работы операционной системы Windows и платформы 1С при получении данных от USB HID-устройства. Выделим три основные технические причины сбоя:
CR (ASCII-код 13) не как полноценное нажатие физической клавиши Enter (Virtual Key Code 13), а через эмуляцию ALT-последовательности (так называемый Alt-код: последовательное быстрое нажатие клавиши Alt и цифр 0, 1, 3 на цифровой клавиатуре NumPad). Блокнот и стандартные приложения Windows отлично понимают этот трюк и переводят курсор. Но в 1С нажатие клавиши Alt зарезервировано под активацию главного меню программы или вызов горячих клавиш. Когда 1С перехватывает управляющий сигнал Alt в момент ввода, фокус с ячейки ввода может кратковременно сбиваться, из-за чего финальный Enter теряется в недрах интерфейса.Теперь, когда мы детально понимаем природу проблемы, рассмотрим методы борьбы с ней.
---
Если конфигурация закрыта для изменений, или у вас нет возможности переписывать код, мы можем заставить физический сканер работать медленнее и корректнее. Для этого используются настроечные штрихкоды из руководства пользователя конкретной модели сканера.
Шаг 1. Перевод суффикса CR в режим «честного» нажатия Enter.
Найдите в инструкции к вашему сканеру раздел настройки суффиксов (Suffix Configuration). Нам необходимо найти и отсканировать управляющий штрихкод, который переводит отправку символа CR из режима ALT-эмуляции в режим отправки стандартного кода клавиши. Данная опция в зависимости от производителя может называться:
После этого сканер начнет посылать системе полноценный сигнал нажатия клавиши Enter, что значительно повысит процент успешных срабатываний в 1С.
Шаг 2. Настройка задержки между символами (Inter-character delay).
Это самый эффективный способ подружить клавиатурный сканер с тяжелым интерфейсом 1С без программирования. По умолчанию сканер отправляет символы с нулевой задержкой. Нам нужно запрограммировать сканер так, чтобы он делал искусственную микропаузу между отправкой каждого символа штрихкода (включая суффикс). Рекомендуется установить задержку в диапазоне от 15 до 30 миллисекунд (Inter-key delay / Inter-character delay). Для глаза человека ввод штрихкода останется мгновенным, но платформа 1С получит необходимый запас времени на обработку каждого пришедшего символа и гарантированно распознает завершающий Enter.
Шаг 3. Использование суффикса TAB вместо ENTER.
В некоторых самописных конфигурациях логика перехода по ячейкам табличной части завязана на клавишу Tab. Попробуйте настроить сканер на отправку суффикса TAB (ASCII-код 09) вместо стандартного CR. Часто это решает проблему мгновенного перескока на соседнюю колонку или строку.
---
Ввод штрихкода «напрямую» в активную ячейку табличной части — это архитектурно неверный подход, который всегда будет нести в себе риски сбоев при изменении производительности компьютера или сети. Правильное решение — отказаться от ввода символов в активное поле и перехватывать данные от сканера асинхронно.
Для этого используется штатная внешняя компонента «1С:Сканеры штрихкода» (драйвер NativeAPI). Она поставляется в составе БСП (Библиотеки стандартных подсистем) или может быть загружена отдельно. Работает она по следующему принципу:
ВнешнееСобытие.Рассмотрим по шагам, как реализовать этот механизм в самописной конфигурации.
Сначала нам нужно подключить макет внешней компоненты драйвера. Драйвер NativeAPI поставляется в виде файла zip-архива. Мы можем загрузить его в общие макеты нашей конфигурации под именем Драйвер1ССканерШтрихкода. В модуле формы документа или рабочего места кассира пишем код инициализации:
&НаКлиенте
Процедура ПриОткрытии(Отказ)
// Инициализируем подключение внешней компоненты сканера
ИмяПутиККомпоненте = "ОбщийМакет.Драйвер1ССканерШтрихкода";
Попытка
РезультатПодключения = ПодключитьВнешнююКомпоненту(ИмяПутиККомпоненте, "СканерШК", ТипВнешнейКомпоненты.Native);
Если РезультатПодключения Тогда
ОбъектСканера = Новый("AddIn.СканерШК.BarcodeScanner");
// Настраиваем параметры сканера (в режиме клавиатуры)
ОбъектСканера.Порт = 0; // 0 обычно означает клавиатурный режим (Keyboard Wedge)
ОбъектСканера.Префикс = 0;
ОбъектСканера.Суффикс = 13; // Ожидаем Enter в качестве суффикса
ОбъектСканера.ВключитьУстройство();
ОтобразитьСостояние("Сканер штрихкодов успешно подключен.");
Иначе
Сообщить("Не удалось загрузить внешнюю компоненту сканера.");
КонецЕсли;
Исключение
ВызватьИсключение "Ошибка инициализации драйвера сканера штрихкодов: " + ОписаниеОшибки();
КонецПопытки;
КонецПроцедуры
Для того чтобы внешняя компонента не оставляла хуки в операционной системе после закрытия формы, обязательно освобождаем ресурсы в обработчике закрытия:
&НаКлиенте
Процедура ПриЗакрытии(ЗавершениеРаботы)
// Отключаем устройство и освобождаем компоненту
Попытка
Если ОбъектСканера <> Неопределено Тогда
ОбъектСканера.ВыключитьУстройство();
ОбъектСканера = Неопределено;
КонецЕсли;
Исключение
ЗаписатьЛогСобытий("Ошибка при отключении сканера: " + ОписаниеОшибки());
КонецПопытки;
КонецПроцедуры
Когда сканер считывает код, управление передается в предопределенную процедуру модуля формы ВнешнееСобытие. Обратите внимание: фокус ввода при этом может находиться абсолютно на любом элементе формы (или вообще отсутствовать) — данные не потеряются.
&НаКлиенте
Процедура ВнешнееСобытие(Источник, Событие, Данные)
// Проверяем, что событие пришло именно от нашей компоненты сканера
Если Источник = "СканерШК" ИЛИ Событие = "Barcode" Тогда
// Получаем штрихкод из параметров события
ШтрихкодДанные = СокрЛП(Данные);
Если ЗначениеЗаполнено(ШтрихкодДанные) Тогда
// Вызываем процедуру обработки штрихкода
ОбработатьПолученныйШтрихкод(ШтрихкодДанные);
КонецЕсли;
КонецЕсли;
КонецПроцедуры
Теперь реализуем логику автоматического добавления товара в табличную часть формы при успешном сканировании. Программа сама добавит строку, подставит штрихкод и переведет фокус интерфейса так, чтобы складской работник мог непрерывно продолжать сканирование.
&НаКлиенте
Процедура ОбработатьПолученныйШтрихкод(Знач ТекущийШтрихкод)
// Сначала ищем товар по штрихкоду (на сервере)
ДанныеНоменклатуры = НайтиНоменклатуруПоШтрихкодуНаСервере(ТекущийШтрихкод);
Если ДанныеНоменклатуры = Неопределено Тогда
ПоказатьПредупреждение(, "Штрихкод " + ТекущийШтрихкод + " не зарегистрирован в базе данных!");
Возврат;
КонецЕсли;
// Создаем новую строку в нашей табличной части "Товары"
НоваяСтрока = Объект.Товары.Добавить();
НоваяСтрока.Номенклатура = ДанныеНоменклатуры.Номенклатура;
НоваяСтрока.ЕдиницаИзмерения = ДанныеНоменклатуры.ЕдиницаИзмерения;
НоваяСтрока.Количество = 1;
НоваяСтрока.Цена = ДанныеНоменклатуры.Цена;
НоваяСтрока.Сумма = НоваяСтрока.Количество * НоваяСтрока.Цена;
// Программное позиционирование интерфейса:
// Активизируем строку, чтобы пользователь наглядно видел добавленный товар
Элементы.Товары.ТекущаяСтрока = НоваяСтрока.ПолучитьИдентификатор();
// Переносим фокус на колонку Количество, если требуется ручная корректировка,
// либо оставляем фокус свободным для мгновенного продолжения сканирования
Элементы.Товары.ТекущийЭлемент = Элементы.ТоварыКолонки.Количество;
// Оповещаем пользователя звуковым сигналом (опционально)
Сигнал();
КонецПроцедуры
&НаСервереБезКонтекста
Функция НайтиНоменклатуруПоШтрихкодуНаСервере(Штрихкод)
// Простой пример запроса для поиска по регистру сведений штрихкодов
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| Штрихкоды.Номенклатура КАК Номенклатура,
| Штрихкоды.Номенклатура.ЕдиницаИзмерения КАК ЕдиницаИзмерения,
| ЦеныНоменклатурыСрезПоследних.Цена КАК Цена
|ИЗ
| РегистрСведений.Штрихкоды КАК Штрихкоды
| ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.ЦеныНоменклатуры.СрезПоследних КАК ЦеныНоменклатурыСрезПоследних
| ПО Штрихкоды.Номенклатура = ЦеныНоменклатурыСрезПоследних.Номенклатура
|ГДЕ
| Штрихкоды.Штрихкод = &Штрихкод";
Запрос.УстановитьПараметр("Штрихкод", Штрихкод);
РезультатЗапроса = Запрос.Выполнить();
Если Не РезультатЗапроса.Пустой() Тогда
Выборка = РезультатЗапроса.Выбрать();
Выборка.Следующий();
СтруктураДанных = Новый Структура;
СтруктураДанных.Вставить("Номенклатура", Выборка.Номенклатура);
СтруктураДанных.Вставить("ЕдиницаИзмерения", Выборка.ЕдиницаИзмерения);
СтруктураДанных.Вставить("Цена", ?(Выборка.Цена = Неопределено, 0, Выборка.Цена));
Возврат СтруктураДанных;
КонецЕсли;
Возврат Неопределено;
КонецФункции
---
Для достижения максимальной отказоустойчивости мы рекомендуем комбинировать оба метода:
Использование внешней компоненты торгового оборудования превращает обычный клавиатурный сканер в профессиональное устройство считывания, гарантируя стабильную работу информационной системы на уровне 100% успешных транзакций.