Подтвердить что ты не робот

Как различать несколько устройств ввода в С#

У меня есть сканер штрих-кода (который действует как клавиатура), и, конечно, у меня есть клавиатура, подключенная к компьютеру. Программное обеспечение принимает вход как от сканера, так и от клавиатуры. Мне нужно принять только вход сканера. Код написан на С#. Есть ли способ "отключить" ввод с клавиатуры и принимать входной сигнал от сканера?

Примечание: Клавиатура является частью ноутбука... поэтому его нельзя отключить. Кроме того, я попытался ввести следующий код   protected override Boolean ProcessDialogKey (System.Windows.Forms.Keys keyData)   {     return true;   } Но затем, игнорируя нажатия клавиш с клавиатуры, вход сканера штрих-кода также игнорируется.

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

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

Да, я читаю данные из потока.

Я пытаюсь следовать вместе со статьей: Отличительные сканеры штрих-кода от клавиатуры в WinForms. Однако у меня есть следующие вопросы:

  • Я получаю сообщение об ошибке. NativeMethods недоступен из-за уровня защиты. Кажется, мне нужно импортировать dll; это верно? Если да, то как мне это сделать?
  • Какое защищенное переопределение void WndProc (ref Message m) должно использоваться, есть две реализации в этой статье?
  • Возникает ошибка, связанная с ошибкой [SecurityPermission (SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.UnmanagedCode)] CS0246: Не удалось найти имя типа или пространства имен "SecurityPermission" (вам не хватает директивы using или ссылки на сборку?). Как устранить эту ошибку?
  • Также есть ошибка в строке, содержащей: if ((from hardwareId в hardwareIds, где deviceName.Contains(hardwareId) select hardwareId).Count() > 0) Ошибка - это ошибка CS1026:).
  • Должен ли я размещать весь код в статье в одном файле .cs с именем BarcodeScannerListener.cs?

Последующие вопросы о исходном коде С#, опубликованном Николасом Пиасекским, http://nicholas.piasecki.name/blog/2009/02/distinguishing-barcode-scanners-from-the-keyboard-in-winforms/:

  • Мне не удалось открыть решение в VS 2005, поэтому я загрузил Visual С# 2008 Express Edition и код работал. Однако после подключения сканера штрих-кодов и сканирования штрих-кода программа не распознала сканирование. Я поставил точку останова в методе OnBarcodeScanned, но он никогда не попадал. Я изменил App.config с идентификатором моего сканера штрих-кода, полученного с помощью диспетчера устройств. Кажется, что есть 2 имени устройства с HID # Vid_0536 & Pid_01c1 (который получен из диспетчера устройств при подключении сканера). Я не знаю, вызывает ли это сканирование, чтобы он не работал. Когда выполняется итерация над именами устройств, вот список найденных устройств (с помощью отладчика):

"\??\HID # Vid_0536 & Pid_01c1 & MI_01 # 9 & 25ca5370 & 0 & 0000 # {4d1e55b2-F16F-11cf-88cb-001111000030}"

"\??\HID # Vid_0536 & Pid_01c1 & MI_00 # 9 & 38e10b9 & 0 & 0000 # {884b96c3-56ef-11d1-bc8c-00a0c91405dd}"

"\??\HID # Vid_413c & Pid_2101 & MI_00 # 8 & 1966e83d & 0 & 0000 # {884b96c3-56ef-11d1-bc8c-00a0c91405dd}"

"\??\HID # Vid_413c & Pid_3012 # 7 & 960fae0 & 0 & 0000 # {378de44c-56ef-11d1-bc8c-00a0c91405dd}"
"\??\Root # RDP_KBD # 0000 # {884b96c3-56ef-11d1-bc8c-00a0c91405dd}" "\??\ACPI # PNP0303 # 4 & 2f94427b & 0 # {884b96c3-56ef-11d1-bc8c-00a0c91405dd}" "\??\Root # RDP_MOU # 0000 # {378de44c-56ef-11d1-bc8c-00a0c91405dd}" "\??\ACPI # PNP0F13 # 4 & 2f94427b & 0 # {378de44c-56ef-11d1-bc8c-00a0c91405dd}"

Таким образом, для HID # Vid_0536 & Pid_01c1 имеется 2 записи; может ли это заставить сканирование работать?

ОК, похоже, что мне нужно было выяснить способ не зависеть от символа ASCII 0x04, отправляемого сканером... поскольку мой сканер не отправляет этот символ. После этого происходит отсканированное событие штрих-кода и отображается всплывающее окно со штрих-кодом. Так что спасибо Николаю за вашу помощь.

4b9b3361

Ответ 1

Вы можете использовать API-интерфейс Raw Input, чтобы различать клавиатуру и сканер, как это было в последнее время. Неважно, сколько клавиатур или клавиатурные устройства, которые вы подключили; вы увидите WM_INPUT, пока нажатие клавиши не будет сопоставлено с независимым от устройства виртуальным ключом, который вы обычно видите в событии KeyDown.

Намного легче сделать то, что рекомендовали другие, и настроить сканер для отправки символов дозорного устройства до и после штрих-кода. (Обычно вы делаете это, сканируя специальные штрих-коды в конце руководства пользователя сканера.) Затем ваше основное событие формы KeyPreview может наблюдать за этим завершением ролика и проглатывать ключевые события для любого дочернего элемента управления, если оно находится в середине штрих-кода читать. Или, если вы хотите быть более привлекательным, вы можете использовать крючок с низким уровнем клавиатуры с помощью SetWindowsHookEx(), чтобы наблюдать за этими стражниками и проглатывать их там (преимущество этого вы все равно можете получить, даже если ваше приложение не имеет фокус).

Я не мог изменить значения дозорных средств на наших сканерах штрих-кодов, среди прочего, поэтому мне пришлось идти по сложному маршруту. Было определенно больно. Держите его простым, если вы можете!

-

Ваше обновление, семь лет спустя: Если ваш прецедент читается с помощью USB-сканера штрих-кода, Windows 10 имеет приятный, дружественный API для этого встроенного в Windows.Devices.PointOfService.BarcodeScanner. Это UWP/WinRT API, но вы также можете использовать его из обычного настольного приложения; что я сейчас делаю. Вот пример кода для него, прямо из моего приложения, чтобы дать вам суть:

{
    using System;
    using System.Linq;
    using System.Threading.Tasks;
    using System.Windows;
    using Windows.Devices.Enumeration;
    using Windows.Devices.PointOfService;
    using Windows.Storage.Streams;
    using PosBarcodeScanner = Windows.Devices.PointOfService.BarcodeScanner;

    public class BarcodeScanner : IBarcodeScanner, IDisposable
    {
        private ClaimedBarcodeScanner scanner;

        public event EventHandler<BarcodeScannedEventArgs> BarcodeScanned;

        ~BarcodeScanner()
        {
            this.Dispose(false);
        }

        public bool Exists
        {
            get
            {
                return this.scanner != null;
            }
        }

        public void Dispose()
        {
            this.Dispose(true);
            GC.SuppressFinalize(this);
        }

        public async Task StartAsync()
        {
            if (this.scanner == null)
            {
                var collection = await DeviceInformation.FindAllAsync(PosBarcodeScanner.GetDeviceSelector());
                if (collection != null && collection.Count > 0)
                {
                    var identity = collection.First().Id;
                    var device = await PosBarcodeScanner.FromIdAsync(identity);
                    if (device != null)
                    {
                        this.scanner = await device.ClaimScannerAsync();
                        if (this.scanner != null)
                        {
                            this.scanner.IsDecodeDataEnabled = true;
                            this.scanner.ReleaseDeviceRequested += WhenScannerReleaseDeviceRequested;
                            this.scanner.DataReceived += WhenScannerDataReceived;

                            await this.scanner.EnableAsync();
                        }
                    }
                }
            }
        }

        private void WhenScannerDataReceived(object sender, BarcodeScannerDataReceivedEventArgs args)
        {
            var data = args.Report.ScanDataLabel;

            using (var reader = DataReader.FromBuffer(data))
            {
                var text = reader.ReadString(data.Length);
                var bsea = new BarcodeScannedEventArgs(text);
                this.BarcodeScanned?.Invoke(this, bsea);
            }
        }

        private void WhenScannerReleaseDeviceRequested(object sender, ClaimedBarcodeScanner args)
        {
            args.RetainDevice();
        }

        private void Dispose(bool disposing)
        {
            if (disposing)
            {
                this.scanner = null;
            }
        }
    }
}

Конечно, вам понадобится сканер штрих-кодов, который поддерживает USB HID POS и не просто клин клавиатуры. Если ваш сканер - это просто клавиатурный клин, я рекомендую собрать что-то вроде используемого Honeywell 4600G с eBay за $25. Поверьте мне, ваше здравомыслие будет стоить того.

Ответ 2

То, что я делал в подобной ситуации, - это различие между сканированием и пользовательским вводом, если посмотреть на скорость ввода.

Множество символов очень близко, а затем пауза - это сканирование. Все остальное - ввод с клавиатуры.

Я точно не знаю ваших требований, поэтому, возможно, это не сработает для вас, но это лучшее, что у меня есть:)

Ответ 3

Это зависит от того, как вы взаимодействуете с устройством. В любом случае это не будет С# решение, это будет какая-то другая библиотека. Вы читаете данные из потока? Если вы просто выполняете нажатия клавиш, вы можете ничего не сделать с этим.

Ответ 4

Я успешно выполнил то, что вы ищете здесь. У меня есть приложение, которое получает все персональные данные штрих-кода от сканера штрих-кода Honeywell/Metrologic. Никакое другое приложение в системе не получает данные со сканера, и клавиатура продолжает нормально функционировать.

В моем приложении используется комбинация сырого ввода и страшной низкоуровневой клавиатуры. В отличие от того, что написано здесь, я обнаружил, что сообщение wm_input получено до вызова функции hook hook. Мой код для обработки сообщения wm_input в основном устанавливает логическую переменную, чтобы указать, является ли полученный символ из сканера. Функция перехвата клавиатуры, вызываемая сразу после обработки wm_input, проглатывает данные псевдо-клавиатуры сканеров, предотвращая прием данных другими приложениями.

Функция перехвата клавиатуры должна быть помещена в dll, так как вы хотите перехватить все сообщения системной клавиатуры. Кроме того, файл с отображением памяти должен использоваться для кода обработки wm_input для связи с dll.

Ответ 5

посмотрите на это: http://nate.dynalias.net/dev/keyboardredirector.rails (НЕ ДОСТУПНО ЛЮБОЙ) отлично работает!

Укажите клавиатуру и клавиши, которые вы хотите заблокировать, и это работает как шарм!

Ответ 6

Я думаю, что вы могли бы различать несколько клавиатур через DirectX API, или если это не сработает, через API исходных входных данных.

Ответ 7

Я знаю, что это старый поток, найденный в нем поиском сканирования штрих-кода в WIN10. Всего несколько примечаний, если кому-то это нужно.

Эти сканеры от Honeywell имеют несколько интерфейсов USB. Один из них - клавиатура + Скрытая точка продаж (композитное устройство). Также есть CDC-ACM (эмуляция ComPort) и Hid Point of sales (отдельно) + больше.

По умолчанию сканеры выставляют серийный номер, поэтому хост может различать многие устройства (я имел один раз +20 подключений). Есть команда отключить серийный номер, хотя!

Новые модели ведут себя одинаково в этом отношении. Если вы хотите увидеть его вживую, попробуйте мою терминальную программу yat3 (бесплатно на мой сайт). Он может открыть все интерфейсы, упомянутые выше, и предназначен для таких устройств.

Слово для использования интерфейсов клавиатуры:
Используйте их только в крайнем случае. Они медленные, менее надежные, когда дело доходит до экзотических персонажей. Единственное удобное использование - если вы хотите вводить данные в существующие приложения. Если вы все равно кодируете, то чтение из ComPort/HidPos-устройства проще.