web-dev-qa-db-ja.com

C#で複数の入力デバイスを区別する方法

私はバーコードスキャナー(キーボードのように機能します)を持っています、そしてもちろん私はキーボードもコンピューターに接続されています。ソフトウェアは、スキャナーとキーボードの両方からの入力を受け入れています。スキャナーの入力のみを受け入れる必要があります。コードはC#で記述されています。キーボードからの入力を「無効」にして、スキャナーからの入力のみを受け入れる方法はありますか?

注:キーボードはラップトップの一部です...したがって、プラグを抜くことはできません。また、次のコードで保護されたオーバーライドを配置してみましたBoolean ProcessDialogKey(System.Windows.Forms.Keys keyData){return true;ただし、キーボードからのキーストロークを無視するとともに、バーコードスキャナーの入力も無視されます。

スキャナーにセンチメンタル文字を送信させることはできません。スキャナーは他のアプリケーションで使用されており、センチメンタル文字ストリームを追加すると、他のコードを変更することになります。

また、スキャンされたバーコードは1文字のバーコードである可能性があるため、入力がバーコードスキャナーからのものかどうかを判断するタイミング方法を使用できません(文字の束の後に一時停止が続く場合)。

はい、ストリームからデータを読み取っています。

私は記事「WinFormsのキーボードからバーコードスキャナーを区別する」に沿って従おうとしています。ただし、次の質問があります。

  1. 保護レベルが原因でNativeMethodsにアクセスできないというエラーが表示されます。 dllをインポートする必要があるようです。これは正しいです?もしそうなら、どうすればいいですか?
  2. どの保護されたオーバーライドvoidWndProc(refメッセージm)定義を使用する必要がありますか?記事には2つの実装がありますか?
  3. [SecurityPermission(SecurityAction.LinkDemand、Flags = SecurityPermissionFlag.UnmanagedCode)]エラーCS0246に関連するエラーが発生します:タイプまたは名前空間名 'SecurityPermission'が見つかりませんでした(usingディレクティブまたはアセンブリ参照がありませんか?)。このエラーを解決するにはどうすればよいですか?
  4. 次を含む行にもエラーがあります:if((from hardwareId in hardwareIds where deviceName.Contains(hardwareId)select hardwareId).Count()> 0)エラーはエラーCS1026 :)が予想されます。
  5. 記事内のすべてのコードをBarcodeScannerListener.csという1つの.csファイルに配置する必要がありますか?

Nicholas Piaseckiによって投稿されたC#ソリューションのソースコードに関するフォローアップの質問 http://nicholas.piasecki.name/blog/2009/02/distinguishing-barcode-scanners-from-the-keyboard-in-winforms/ =:

  1. VS 2005でソリューションを開くことができなかったため、Visual C#2008 Express Editionをダウンロードして、コードを実行しました。しかし、バーコードスキャナーを接続してバーコードをスキャンした後、プログラムはスキャンを認識しませんでした。 OnBarcodeScannedメソッドにブレークポイントを設定しましたが、ヒットしませんでした。デバイスマネージャーを使用して取得したバーコードスキャナーのIDでApp.configを変更しました。 HID#Vid_0536&Pid_01c1(スキャナーが接続されたときにデバイスマネージャーから取得されます)を持つ2つのdeviceNameがあるようです。これがスキャンを機能させない原因であるかどうかはわかりません。 deviceNamesを反復処理するときに、(デバッガーを使用して)見つけたデバイスのリストを次に示します。

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

"\ ??\HIV#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つのエントリがあります。それがスキャンを機能させない原因になっている可能性がありますか?

OK、スキャナーから送信されるASCII 0x04文字...私のスキャナーはその文字を送信しないので、依存しない方法を考え出さなければならなかったようです。その後、バーコードスキャンイベントが発生し、バーコード付きのポップアップが表示されます。ニコラスにご協力いただきありがとうございます。

22
Amar Patel

最近行ったように、Raw Input APIを使用して、キーボードとスキャナーを区別できます。 キーボードまたはキーボードのようなデバイスをいくつ接続してもかまいません。キーストロークが、通常KeyDownイベントで表示されるデバイスに依存しない仮想キーにマップされる前に、_WM_INPUT_が表示されます。

はるかに簡単なのは、他の人が推奨していることを実行し、バーコードの前後にセンチネル文字を送信するようにスキャナーを構成することです。 (通常、これはスキャナーのユーザーマニュアルの裏にある特別なバーコードをスキャンすることによって行います。)次に、メインフォームのKeyPreviewイベントはそれらのロールエンドを監視し、中間にある場合は子コントロールのキーイベントを飲み込むことができます読み取られたバーコードの。または、もっと凝ったものにしたい場合は、SetWindowsHookEx()を備えた低レベルのキーボードフックを使用して、それらの歩哨を監視し、そこで飲み込むことができます(これの利点は、アプリでもイベントを取得できることです焦点がありませんでした)。

バーコードスキャナーの番兵の値を変更できなかったため、複雑なルートをたどらなければなりませんでした。間違いなく苦痛でした。できればシンプルにしてください!

-

7年後の更新:ユースケースがUSBバーコードスキャナーからの読み取りである場合、Windows10にはこの組み込み用の優れたフレンドリーな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をサポートし、単なるキーボードウェッジではないバーコードスキャナーが必要です。スキャナーが単なるキーボードウェッジの場合は、中古のHoneywell4600GのようなものをeBayから25ドル程度で購入することをお勧めします。私を信じてください、あなたの正気はそれだけの価値があります。

18

同様の状況で私が行ったことは、入力の速度を見て、スキャンとユーザー入力を区別することです。

多くの文字が非常に接近している場合、一時停止はスキャンです。それ以外はキーボード入力です。

私はあなたの要件を正確に知らないので、多分それはあなたのためにはならないでしょう、しかしそれは私が持っている最高です:)

3

それはあなたがデバイスと相互作用している方法に依存します。とにかく、それはC#ソリューションではなく、他のライブラリになります。ストリームからデータを読み取っていますか?キーストロークをしているだけの場合は、何もできない可能性があります。

1
Karl

これは古いスレッドであることがわかっています。WIN10でバーコードスキャンを検索して見つけました。誰かがそれを必要とする場合に備えて、ほんの少しのメモ。

Honeywellのこれらのスキャナーには、いくつかのUSBインターフェースがあります。 1つは、キーボード+ Hid Point of Sales(複合デバイス)です。また、CDC-ACM(ComPortエミュレーション)およびHID販売時点管理(単独)などがあります。

デフォルトでは、スキャナーはシリアル番号を公開するため、ホストは多くのデバイスを区別できます(私はかつて+20を接続していました)。ただし、シリアル番号を無効にするコマンドがあります。

新しいモデルは、この点で同じように動作します。ライブで見たい場合は、私のターミナルプログラムyat3を試してください( 私のサイト で無料)。上記のすべてのインターフェイスを開くことができ、そのようなデバイス用に調整されています。

キーボードインターフェイスを使用するための単語:
最後の手段としてのみ使用してください。エキゾチックなキャラクターに関しては、速度が遅く、信頼性が低くなります。唯一の良い使用法は、既存のアプリケーションにデータを入力する場合です。とにかくコーディングすると、ComPort/HidPos-Deviceからの読み取りが簡単になります。

1
DieterF

これを見てください: http://nate.dynalias.net/dev/keyboardredirector.Railsもう利用できません)はうまく機能します!

ブロックしたいキーボードとキーを指定すれば、チャームのように機能します!

これも見てください: http://www.oblita.com/interception.html C#ラッパーを作成できます-それはチャームのようにも機能します。

1
MMM

DirectX APIを使用して、またはそれが機能しない場合は、生の入力APIを使用して、複数のキーボードを区別できる可能性があると思います。

0
anon

私はあなたたちがここで探していることを首尾よく達成しました。 Honeywell/Metrologicバーコードスキャナーからすべてのバーコード文字データを受信するアプリケーションがあります。システム上の他のアプリケーションはスキャナーからデータを受信せず、キーボードは引き続き正常に機能します。

私のアプリケーションは、生の入力と恐ろしい低レベルのキーボードフックシステムの組み合わせを使用しています。ここに書かれていることとは逆に、キーボードフック関数が呼び出される前にwm_inputメッセージが受信されることがわかりました。 wm_inputメッセージを処理する私のコードは、基本的にブール変数を設定して、受信した文字がスキャナーからのものであるかどうかを指定します。 wm_inputが処理された直後に呼び出されるキーボードフック関数は、スキャナーの疑似キーボードデータを飲み込み、他のアプリケーションがデータを受信できないようにします。

すべてのシステムキーボードメッセージをインターセプトするため、キーボードフック関数をdllに配置する必要があります。また、メモリマップトファイルは、wm_input処理コードがdllと通信するために使用する必要があります。

0
Greg Bergmann