2009-02-25 11 views
19

Ho uno scanner di codici a barre (che funziona come una tastiera) e ovviamente ho una tastiera troppo agganciata a un computer. Il software accetta input sia dallo scanner che dalla tastiera. Devo accettare solo l'input dello scanner. Il codice è scritto in C#. C'è un modo per "disabilitare" l'input dalla tastiera e accettare solo input dallo scanner?Come distinguere tra più dispositivi di input in C#

Nota: La tastiera fa parte di un laptop ... quindi non può essere scollegata. Inoltre, ho provato a inserire il seguente codice override Boolean ProcessDialogKey (System.Windows.Forms.Keys keyData) { return true; } Ma poi ignorando le sequenze di tasti dalla tastiera, anche l'ingresso del lettore di codici a barre viene ignorato.

Non è possibile che lo scanner invii caratteri tipografici, poiché lo scanner viene utilizzato da altre applicazioni e l'aggiunta di un flusso di caratteri sentinella significherebbe la modifica di altro codice.

Inoltre, non è possibile utilizzare il metodo di temporizzazione per determinare se l'input proviene da uno scanner di codici a barre (se è un gruppo di caratteri seguito da una pausa) poiché i codici a barre scansionati potrebbero potenzialmente essere codici a barre a carattere singolo.

Sì, sto leggendo i dati da un flusso.

Sto cercando di seguire l'articolo: Distinguere gli scanner di codici a barre dalla tastiera in WinForms. Tuttavia ho le seguenti domande:

  1. Ottengo un errore NativeMethods è inaccessibile a causa del suo livello di protezione. Sembra come se avessi bisogno di importare una DLL; è corretto? Se sì, come lo faccio?
  2. Quale definizione di override protetto WndProc (ref Message m) dovrei usare, ci sono due implementazioni nell'articolo?
  3. Mi viene restituito un errore relativo a [SecurityPermission (SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.UnmanagedCode)] errore CS0246: Impossibile trovare il nome del tipo o spazio dei nomi 'SecurityPermission' (manca una direttiva using o un riferimento assembly?). Come posso risolvere questo errore?
  4. C'è anche un errore sulla riga che contiene: if ((da hardwareId in hardwareId dove deviceName.Contains (hardwareId) seleziona hardwareId) .Count()> 0) Errore è errore CS1026:) previsto.
  5. Devo inserire tutto il codice nell'articolo in un file .cs denominato BarcodeScannerListener.cs?

domande Followup su C# codice sorgente soluzione postato da Nicholas Piasecki su http://nicholas.piasecki.name/blog/2009/02/distinguishing-barcode-scanners-from-the-keyboard-in-winforms/:

  1. non ero in grado di aprire la soluzione in VS 2005, così ho scaricato Visual C# 2008 Express Edition, e il codice corse. Tuttavia, dopo aver collegato il mio lettore di codici a barre e scansionato un codice a barre, il programma non ha riconosciuto la scansione. Ho inserito un punto di interruzione nel metodo OnBarcodeScanned ma non è mai stato colpito. Ho modificato App.config con l'ID del mio scanner di codici a barre ottenuto utilizzando Device Manager. Sembra esserci 2 nomi dispositivo con HID # Vid_0536 & Pid_01c1 (che viene ottenuto da Gestione periferiche quando lo scanner è collegato). Non so se questo sta facendo sì che la scansione non funzioni. Durante l'iterazione su deviceNames, ecco l'elenco dei dispositivi che ho trovato (utilizzando il debugger):

"\ ??\ HID # Vid_0536 & Pid_01c1 & MI_01 # 9 & 25ca5370 0000 # {4d1e55b2-f16f-11cf-88cb-001.111.000,03 mila} "

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

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

"\ ?? \ HID # Vid_413c & Pid_3012 # 7 & 960fae0 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}"

Quindi ci sono 2 voci per HID # Vid_0536 & Pid_01c1; potrebbe essere che la scansione non funzioni?

OK, così sembra che ho dovuto capire un modo per non dipendere dal carattere ASCII 0x04 inviato dallo scanner ... poiché il mio scanner non invia quel carattere. Dopodiché, viene attivato l'evento scannerizzato con codice a barre e viene visualizzato il popup con il codice a barre. Quindi grazie Nicholas per il tuo aiuto.

+0

Scollegare la tastiera. – TheTXI

+0

Ho aggiunto un codice di esempio in fondo alla fine dell'articolo. In bocca al lupo! –

+1

@NicholasPiasecki sono passati 6 anni, ma ancora - perché HTTP 410? – itsho

risposta

15

You could use the Raw Input API to distinguish between the keyboard and the scanner like I did recently. Non importa quanti dispositivi simili a tastiera o tastiera sono stati collegati; vedrai un WM_INPUT prima che il tasto venga mappato su una chiave virtuale indipendente dalla periferica che di solito vedi in un evento KeyDown.

Molto più facile è fare ciò che altri hanno raccomandato e configurare lo scanner per inviare i caratteri sentinella prima e dopo il codice a barre. (Di solito lo fai scansionando codici a barre speciali nella parte posteriore del manuale dell'utente dello scanner.) Quindi, l'evento KeyPreview del tuo modulo principale può vedere quei roll end e ingoiare gli eventi chiave per qualsiasi controllo figlio se si trova nel mezzo di un codice a barre letto.Oppure, se si desidera essere più appassionati, è possibile utilizzare un gancio per tastiera di basso livello con SetWindowsHookEx() per guardare quelle sentinelle e ingoiarle lì (il vantaggio è che si può ancora ottenere l'evento anche se la propria app non è stata messa a fuoco) .

Non sono riuscito a modificare i valori sentinella sui nostri scanner di codici a barre, tra le altre cose, quindi ho dovuto seguire il percorso complicato. Era decisamente doloroso. Rendilo semplice se puoi!

-

vostro aggiornamento, sette anni più tardi: Se il vostro caso d'uso è la lettura da uno scanner di codici a barre USB, Windows 10 ha una bella, accogliente API per questo built-in in Windows.Devices.PointOfService.BarcodeScanner. È un'API UWP/WinRT, ma puoi usarla anche da una normale app desktop; questo è quello che sto facendo ora. Ecco qualche esempio di codice per esso, direttamente dalla mia app, per darvi il senso:

{ 
    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; 
      } 
     } 
    } 
} 

Certo, avrete bisogno di uno scanner di codici a barre che supporta l'USB HID POS e non è solo un cuneo tastiera. Se il tuo scanner è solo un cuneo di tastiera, ti suggerisco di raccogliere qualcosa come un Honeywell 4600G usato su eBay per circa $ 25. Fidati di me, la tua sanità mentale ne varrà la pena.

+0

Sto cercando di seguire l'articolo. Tuttavia, ottengo un errore NativeMethods è inaccessibile a causa del suo livello di protezione. Sembra come se avessi bisogno di importare una DLL; è corretto? Se sì, come lo faccio? Inoltre, quale definizione di override void WndProc (ref Message m) protetta dovrei usare? –

+1

Viene visualizzato anche un errore relativo a [SecurityPermission ( SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.UnmanagedCode)] errore CS0246: Impossibile trovare il tipo o il nome dello spazio dei nomi 'SecurityPermission' (manca una direttiva using o un assembly riferimento) –

+0

Insieme con un errore sulla riga contenente: if ((da HardwareID in hardwareIds dove deviceName.Contains (HardwareID) \t \t \t selezionare HardwareID) Count()> 0) errore è errore CS1026:) expected –

0

Dipende dal modo in cui si interagisce con il dispositivo. Comunque non sarà una soluzione C#, sarà un'altra libreria. Stai leggendo i dati da un flusso? Se stai solo prendendo le sequenze di tasti, potrebbe non esserci nulla che tu possa fare al riguardo.

2

Quello che ho fatto in una situazione simile è distinguere tra una scansione e un utente digitando guardando la velocità dell'input.

Un sacco di caratteri molto vicini tra loro, quindi una pausa è una scansione. Qualsiasi altra cosa è l'input da tastiera.

Non so esattamente le vostre esigenze, in modo forse non lo farà per voi, ma è il migliore che ho :)

+0

Sì, trovare e leggere direttamente dal dispositivo non è banale. Dovresti essere in grado di impostare lo scanner in modo che dia le sequenze di avvio e di arresto - queste sequenze non si verificherebbero mai sulla tastiera. –

+0

Puoi fornire qualche esempio di codice su come hai ottenuto questo? Ho anche trovato la soluzione usando la velocità di input. Tuttavia, questa non è una buona opzione. A volte i margini tra le sequenze di tasti sono così grandi. Ad esempio: 15 15 16 180 13 15 15 15 (in millisecondi) –

-1

penso che si potrebbe essere in grado di distinguere più tastiere con DirectX API , o se non funziona, attraverso l'API di input raw.

+0

(nota: uno scanner di codici a barre appare come solo un'altra tastiera di Windows) –

0

Ho realizzato con successo quello che state cercando. Ho un'applicazione che riceve tutti i dati dei caratteri del codice a barre da uno scanner di codici a barre Honeywell/Metrologic. Nessuna altra applicazione sul sistema riceve i dati dallo scanner e la tastiera continua a funzionare normalmente.

La mia applicazione utilizza una combinazione di input raw e il temuto sistema di aggancio tastiera di basso livello. Contrariamente a quanto scritto qui, ho trovato che il messaggio wm_input è ricevuto prima che venga chiamata la funzione hook della tastiera. Il mio codice per elaborare il messaggio wm_input imposta fondamentalmente una variabile booleana per specificare se il carattere ricevuto proviene dallo scanner. La funzione hook della tastiera, chiamata immediatamente dopo l'elaborazione di wm_input, ingoia i dati della pseudo-tastiera dello scanner, impedendo che i dati vengano ricevuti da altre applicazioni.

La funzione di aggancio della tastiera deve essere inserita in una DLL poiché si desidera intercettare tutti i messaggi della tastiera di sistema. Inoltre, è necessario utilizzare un file mappato in memoria per il codice di elaborazione wm_input per comunicare con la dll.

+3

Cura di condividere parte del codice con noi? –

+0

niente di nuovo su questo? - sembra che il ragazzo abbia pubblicato diversi commenti su diverse pagine riguardo a questo problema .. – Mathias

-1

So che questo è un thread vecchio, lo ho trovato cercando la scansione del codice a barre in WIN10. Solo poche note nel caso qualcuno ne avesse bisogno.

Questi scanner Honeywell hanno diverse interfacce USB. Uno è una tastiera + Punto vendita nascosto (dispositivo composito). Inoltre ci sono CDC-ACM (emulazione ComPort) e Hid Point of sales (da soli) + altro.

Per impostazione predefinita, gli scanner espongono un numero seriale, in modo che l'host possa distinguere tra molti dispositivi (avevo una volta collegato +20). C'è un comando per disabilitare il numero seriale!

I modelli più recenti si comportano allo stesso modo a questo proposito. Se vuoi vederlo dal vivo, prova il mio programma terminale yat3 (gratuito su my site). Può aprire tutte le interfacce menzionate sopra ed è adattato per tali dispositivi.

Una parola per utilizzare le interfacce tastiera:
Utilizzarle solo come ultima risorsa. Sono lenti, meno affidabili quando si tratta di personaggi esotici. L'unico buon uso è se vuoi inserire dati in applicazioni esistenti. Se si codifica comunque, la lettura da ComPort/HidPos-Device è più semplice.

Problemi correlati