實現條碼槍的無焦點掃碼


????在上一家公司創業初期,我接觸的第一個項目是醫院的供應室消毒包管理系統,幾乎一人之力用了兩個多月的時間,完成了基本的開發工作。回想起來,當時有個設計印象深刻。趁著還有記憶,記錄下來,供大家一時之需。

當時開發的時候,對于物資的管理,自然離不開條碼槍的角色。設計的是無線條碼槍,讓工作人員可以自由的在作業現場走動。但是有個用戶體驗問題,就是一般情況下,條碼槍掃描的時候,都需要將輸入焦點放到文本框之中,這個限制會造成極為不好的用戶體驗。此外,在流程設計的時候,實際上一系列操作動作,是使用掃描不同命令條碼后,實現的。比如啟動某功能,掃碼后,確定繼續下一個動作等等,全程不用碰PC機。

當時工作現場的示意圖

所以問題的核心就在于是否可以接觸焦點必須放到文本框之中的限制。
此方法并不是原創,但是原始代碼是對WinForm平臺進行開發的,被我修改為支持WPF平臺。并且原文的鏈接已經失效,所以這段代碼還是很有價值的。


現在放出幾個關鍵點的代碼,加以說明,全部代碼在最后放出鏈接:
1.掃描監聽器BarcodeScannerListener

使用WindowInteropHelper獲取傳入窗體的句柄,并且綁定ThreadFilterMessage事件,達到從而可以觸發ProcessRawInputMessage方法

/// <summary>
/// 將監聽器附著到窗體上
/// </summary>
/// <param name="form">需要附著的窗體(WPF)</param>
public void Attach(Window form)
{
    var helper = new WindowInteropHelper(form);
    IntPtr hwnd = helper.Handle;
    form.KeyDown += (sender, args) =>
    {
        if (_ControlHandled)
        {
            args.Handled = true;
            _ControlHandled = false;
        }
    };
    DoAttach(hwnd);
}

/// <summary>
/// 監聽綁定
/// </summary>
/// <param name="hwnd">設備指針</param>
private void DoAttach(IntPtr hwnd)
{

    this.keystrokeBuffer = new StringBuilder();

    this.InitializeBarcodeScannerDeviceHandles();
    this.interopHelper.HookRawInput(hwnd);
    //this.HookHandleEvents(form);

    //this.AssignHandle(ptr);

    this.filter = new BarcodeScannerKeyDownMessageFilter();
    ComponentDispatcher.ThreadFilterMessage -= ComponentDispatcher_ThreadFilterMessage;
    ComponentDispatcher.ThreadFilterMessage += ComponentDispatcher_ThreadFilterMessage;
    //Application.AddMessageFilter(this.filter);
}

ProcessRawInputMessage方法中,判斷傳入的字符串是否是掃碼槍設置的結束字符(掃碼的字符串是一個一個傳入的),如果不是,就加入到Buffer中,如果是,則觸發FireBarcodeScanned方法

/// <summary>
/// 處理WM_INPUT消息
/// </summary>
/// <param name="rawInputHeader">rawInputHeader的指針</param>
/// <returns>按鍵是否被處理</returns>
private bool ProcessRawInputMessage(IntPtr rawInputHeader)
{
    BarcodeScannerDeviceInfo deviceInfo;
    bool handled;
    bool keystroke;
    string localBuffer;
    IntPtr rawInputDeviceHandle;

    handled = false;
    keystroke = false;
    localBuffer = string.Empty;
    rawInputDeviceHandle = IntPtr.Zero;

    this.interopHelper.GetRawInputInfo(
        rawInputHeader,
        ref rawInputDeviceHandle,
        ref keystroke,
        ref localBuffer);

    if (this.devices.TryGetValue(rawInputDeviceHandle, out deviceInfo) && keystroke)
    {
        handled = true;
        // 這里判斷的是Tab按鍵,可以更換為其他按鍵
        if (localBuffer.Length == 1 && (localBuffer[0] == 0x09 || localBuffer[0] == '\t'))
        {
            this.FireBarcodeScanned(deviceInfo);
        }
        else
        {
            this.keystrokeBuffer.Append(localBuffer);
        }
    }

    return handled;
}

FireBarcodeScanned方法中,則會調用界面初始化時,綁定的事件,傳入掃碼的字符串

/// <summary>
/// 觸發掃碼事件
/// </summary>
/// <param name="deviceInfo">掃碼設備信息</param>
private void FireBarcodeScanned(BarcodeScannerDeviceInfo deviceInfo)
{
    string barcode;
    EventHandler handler;

    barcode = this.keystrokeBuffer.ToString();

    if (barcode.Length > 0)
    {
        handler = this.BarcodeScanned;

        this.keystrokeBuffer = new StringBuilder();

        if (handler != null)
        {
            handler(this, new BarcodeScannedEventArgs(barcode, deviceInfo));
        }
    }
}

2.頁面調用

這里我使用的MVVM模式,所以在ViewModel層調用,但是只要能拿到View的對象,在那一層都沒有關系

BarcodeScannerListener = new BarcodeScannerListener();
BarcodeScannerListener.Attach((Window)GetView());
BarcodeScannerListener.BarcodeScanned += OnBarcodeScanned;

在傳入的事件中,獲取Barcode屬性即可得到掃描的值

private void OnBarcodeScanned(object sender, EventArgs e)
{
    string barcode = ((BarcodeScannedEventArgs)e).Barcode;
    DoBarcodeScanned(barcode);
}

3.配置條碼槍的硬件ID

需要在windows設備管理器中,找到掃碼槍的設備ID,我這沒有圖上網找了一個

設備ID

將這個設備ID保存在App.cofig中,可以是多個

<!--在上面先配置一下-->
<configSections>
  <section name="barcodeScanner" type="Huitai.Cssd.Common.Util.Barcode.BarcodeScannerListenerConfigurationSection, Huitai.Cssd.Common" />
</configSections>

<barcodeScanner>
  <hardwareIds>
    <add id="HID#VID_05FE&PID_1010" />
  </hardwareIds>
</barcodeScanner>

最后實現的效果還是十分不錯的,只要是系統處于前臺(不太確定處于后臺是否好用,有點記不住了),條碼槍隨意掃描,一竄操作下來,根本不用動鍵盤或鼠標,因為所有的靠鍵盤鼠標觸發的功能,也都是使用特定條碼定義了,用戶體驗十分不錯。可惜的是,最后這個系統因為商務原因,沒有上線,雖然完成度已經很高了,但是也廢棄了。

放個圖紀念一下吧

最后,掃碼關鍵源碼的下載鏈接

鏈接:https://306t.com/file/18510513-458449749

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

  • 發現 關注 消息 iOS 第三方庫、插件、知名博客總結 作者大灰狼的小綿羊哥哥關注 2017.06.26 09:4...
    肇東周閱讀 12,259評論 4 61
  • 臨近年終報最后幾天,年終考評牽人心緒,沒必要那么緊張,工作只是謀生的手段,并不是你的價值可以全部體現,不是說評為...
    海深深閱讀 372評論 0 1
  • 天哪,我要喊出來了,怎么可以這么好看!沒什么胃口但是覺得應該吃飯,所以做了番茄炒蛋。一邊看一邊吃,科塔薩爾對細節的...
    imissgr閱讀 394評論 0 0