26

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

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

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

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

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

私は記事をフォローしようとしています: WinForms のキーボードからバーコード スキャナーを区別する。ただし、次の質問があります。

  1. 保護レベルが原因で、NativeMethods にアクセスできませんというエラーが表示されます。dll をインポートする必要があるようです。これは正しいです?もしそうなら、どうすればいいですか?
  2. どの protected override void WndProc(ref Message m) 定義を使用する必要がありますか?記事には 2 つの実装がありますか?
  3. [SecurityPermission( SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.UnmanagedCode)] エラー CS0246: The type or namespace name 'SecurityPermission' could not be found (using ディレクティブまたはアセンブリ参照がありませんか?) に関連するエラーが発生しています。このエラーを解決するにはどうすればよいですか?
  4. if ((from hardwareId in hardwareIds where deviceName.Contains(hardwareId) select hardwareId).Count() > 0) Error is error CS1026: ) expected を含む行にもエラーがあります。
  5. この記事のすべてのコードを BarcodeScannerListener.cs という 1 つの .cs ファイルに配置する必要がありますか?

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

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

"\??\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-00a0c91405""?dd} \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 文字に依存しない方法を見つけなければならなかったようです...私のスキャナーはその文字を送信しないためです。その後、バーコード スキャン イベントが発生し、バーコードを含むポップアップが表示されます。ニコラス、助けてくれてありがとう。

4

7 に答える 7

20

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

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

特にバーコード スキャナーのセンチネル値を変更できなかったため、複雑なルートをたどらなければなりませんでした。確かに痛かった。できればシンプルに!

--

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

于 2009-02-26T06:13:54.820 に答える
3

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

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

私はあなたの要件を正確に知らないので、それはあなたには合わないかもしれませんが、それは私が持っている最高のものです:)

于 2009-02-25T21:21:51.197 に答える
1

デバイスとのやり取りの方法によって異なります。とにかく、それはC#ソリューションではなく、他のライブラリになります。ストリームからデータを読み取っていますか? キーストロークを取っているだけの場合は、それについてできることは何もないかもしれません.

于 2009-02-25T21:10:37.513 に答える
1

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

Honeywell のこれらのスキャナには、複数の USB インターフェイスがあります。1つはキーボード+Hid POS(複合デバイス)です。また、CDC-ACM (ComPort エミュレーション) と Hid Point of sales (単体) などもあります。

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

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

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

于 2015-10-29T18:30:54.353 に答える
0

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

于 2009-02-25T23:24:38.593 に答える
0

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

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

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

于 2011-09-01T18:47:46.060 に答える