Java在后台獲取USB二維碼掃描槍掃描的內容


     項目需要在Web項目中獲取掃描槍掃描的內容,項目是Java Web項目,最后部署在Linux系統中的。

    拿到掃描槍后,連接在自己的Windows系統上試了下,插上后,不需要裝任何驅動,只要有個文本框,就能將掃描到的內容輸入到文本框里。反復測試后發現,當前窗口的焦點在哪里,掃描到的內容就顯示在哪里。

那么現在遇到一個問題,項目以后要跑起來,是沒有任何窗口的,是運行在后台的,那怎么拿到掃描槍輸入的內容呢?

先按照盒子上的廠家名稱找到官網,在官網上查到了技術支持電話,結果人家說人家也不知道,他只是硬件層面的技術支持,如何用編程語言拿到掃描到的東西,他不清楚。但是他說他們還有串口類型的掃描槍,可支持軟件編程。掛完電話看了下我們的工控機,是沒有串口的,只有USB接口。但是網上搜了一下,有用Java掃描系統的串口,然后根據串口號獲得串口輸入進來的東西,應該不難。既然我們沒有串口,我也沒深入研究。

然后就以Java 掃描槍為關鍵字搜索相關資料,以前還真有人做過這個,在開源中國找到一個前輩做的項目,是一個條形碼掃描槍,人家實現了。代碼那過來研究了一番,大致明白了。

掃描儀其實說白了對電腦來說就是個鍵盤, 掃描槍將掃描得到的內容解析,然后模擬鍵盤,一個一個敲入到電腦中,最后按一下回車鍵!怪不得焦點在哪個窗口就輸入到哪個窗口呢。

那就又遇到一個問題,Java代碼運行在Jvm虛擬機內,掃描槍或鍵盤輸入的東西,只有操作系統知道,Jvm虛擬機如何知道呢?那就是JNI編程,通過寫C/C++代碼,監聽操作系統的的輸入流,然后通過JNI調用。雖然我不會JNI,也不會C/C++,

但幸運的是,SUN公司已經實現了這個代碼,弄出一個叫JNA的東西(Java Native Access),給Java提供了訪問操作系統鍵盤鼠標的能力。

然后將人家的代碼完整拷貝,想跑一下,結果沒jar包,一直報錯,根據包名百度,在maven倉庫中找相關jar包,(想找官方的jar包和一些文檔,無奈,因為被收購的原因,有些鏈接已經掛了,找不到哇)找到幾個,放進去,編譯不報錯了,運行一直報錯,換了好幾個jar包,還是不行,真是可郁悶了。

最后在一個國內的倉庫網站找到一個清晰的分類,下載里面的大分類下面的一組jar包,運行成功了。網址是www.mvnjar.com。

運行的時候,人家的是條形碼掃描槍,只有0到9是個數字,我們的是二維碼掃描槍,輸入的文字中有字母數字符合,不夠用啊,只能自己再開發了。

當自己要實現字母鍵的時候,才發現,字母不是那么好實現的,因為有大小寫區分,還有!@#$%^這些字符需要按住shift鍵輸入。JNA提供的鈎子函數,我們能拿到的只有鍵盤的鍵控代碼,頓時覺得頭大了。

分析鍵控代碼值發現,監控代碼值跟ASCII代碼值中的字母鍵完全匹配,數字鍵差一些,字符只有極個別有點規律,於是自己按照鍵控代碼和ASCII碼對照了一遍,完整實現了所有字母和數字和字符的輸入。

 

注意,因為二維碼掃描槍只能輸入大小寫字母、數字、特殊字符,所以其他的鍵我沒管,類似於Ctrl、FN、Alt、F快捷鍵等。

下面貼上代碼,感覺只是為了實現功能,代碼寫得很Low。

運行需要的jar包在倉庫下,網址是:https://www.mvnjar.com/net.java.dev.jna/list.html,下載jna-5.2.0.jar和jna-platform-5.2.0.jar這兩個就可以。

import java.util.ArrayList;
import java.util.List;

import com.sun.jna.Pointer;
import com.sun.jna.platform.win32.Kernel32;
import com.sun.jna.platform.win32.User32;
import com.sun.jna.platform.win32.WinDef.HMODULE;
import com.sun.jna.platform.win32.WinDef.LPARAM;
import com.sun.jna.platform.win32.WinDef.LRESULT;
import com.sun.jna.platform.win32.WinDef.WPARAM;
import com.sun.jna.platform.win32.WinUser;
import com.sun.jna.platform.win32.WinUser.HHOOK;
import com.sun.jna.platform.win32.WinUser.KBDLLHOOKSTRUCT;
import com.sun.jna.platform.win32.WinUser.LowLevelKeyboardProc;
import com.sun.jna.platform.win32.WinUser.MSG;

public class WindowsKeybordListener {

    private static HHOOK hhk;
    private static LowLevelKeyboardProc keyboardHook;
    static List<Character> singleInput = new ArrayList<Character>();

    private static String caseCode() {
        StringBuffer buffer = new StringBuffer();
        for (Character i : singleInput) {
            buffer.append(i);
        }
        return buffer.toString();
    }

    public static void main(String[] args) {
        final User32 lib = User32.INSTANCE;
        HMODULE hMod = Kernel32.INSTANCE.GetModuleHandle(null);
        keyboardHook = new LowLevelKeyboardProc() {
            boolean isShiftUp = false;

            @Override
            public LRESULT callback(int nCode, WPARAM wParam, KBDLLHOOKSTRUCT info) {
                if (nCode >= 0) {
                    switch (wParam.intValue()) {
                    case WinUser.WM_KEYDOWN:// 只監聽鍵盤按下
                         //按下回車鍵,生成完整的字符串,並清空list
                         if(info.vkCode==13) {
                         String text = caseCode();
                         System.out.println(text);
                         singleInput.clear();
                         break;
                         }
                        
                        //按下的是shift鍵時,標記一下
                        if (info.vkCode == 160) {
                            isShiftUp = true;
                        }
                        if (!isShiftUp) {
                            if (info.vkCode >= 65 && info.vkCode <= 90) {//字母鍵
                                singleInput.add((char) (info.vkCode + 32));
                            } else if (info.vkCode >= 219 && info.vkCode <= 221) {//[\]
                                singleInput.add((char) (info.vkCode - 128));
                            } else if (info.vkCode >= 188 && info.vkCode <= 191) {//,-./
                                singleInput.add((char) (info.vkCode - 144));
                            } else if (info.vkCode >= 48 && info.vkCode <= 57) {//數字鍵
                                singleInput.add((char) info.vkCode);
                            }
                            if (info.vkCode == 186) {
                                singleInput.add(';');
                            }
                            if (info.vkCode == 187) {
                                singleInput.add('=');
                            }
                            if (info.vkCode == 192) {
                                singleInput.add('`');
                            }
                            if (info.vkCode == 222) {
                                singleInput.add('\'');
                            }
                        } else {
                            //大寫字母
                            if (info.vkCode >= 65 && info.vkCode <= 90) {
                                singleInput.add((char) info.vkCode );
                            }
                            
                            switch (info.vkCode) {
                            case 186:
                                singleInput.add(':');
                                break;
                            case 187:
                                singleInput.add('+');
                                break;
                            case 188:
                                singleInput.add('<');
                                break;
                            case 189:
                                singleInput.add('_');
                                break;
                            case 190:
                                singleInput.add('>');
                                break;
                            case 191:
                                singleInput.add('?');
                                break;
                            case 192:
                                singleInput.add('~');
                                break;
                            case 219:
                                singleInput.add('{');
                                break;
                            case 220:
                                singleInput.add('|');
                                break;
                            case 221:
                                singleInput.add('}');
                                break;
                            case 222:
                                singleInput.add('\"');
                                break;
                            case 48:
                                singleInput.add('!');
                                break;
                            case 49:
                                singleInput.add('@');
                                break;
                            case 50:
                                singleInput.add('#');
                                break;
                            case 51:
                                singleInput.add('$');
                                break;
                            case 52:
                                singleInput.add('%');
                                break;
                            case 53:
                                singleInput.add('^');
                                break;
                            case 54:
                                singleInput.add('&');
                                break;
                            case 55:
                                singleInput.add('*');
                                break;
                            case 56:
                                singleInput.add('(');
                                break;
                            case 57:
                                singleInput.add(')');
                                break;
                            }
                        }
                        break;
                    case WinUser.WM_KEYUP:// 按鍵起來
                        if (info.vkCode == 160) {
                            isShiftUp = false;
                        }
                        break;
                    }
                }
                Pointer ptr = info.getPointer();
                long peer = Pointer.nativeValue(ptr);
                return lib.CallNextHookEx(hhk, nCode, wParam, new LPARAM(peer));
            }
        };hhk=lib.SetWindowsHookEx(WinUser.WH_KEYBOARD_LL,keyboardHook,hMod,0);

    // This bit never returns from GetMessage
    int result;
    MSG msg = new MSG();while((result=lib.GetMessage(msg,null,0,0))!=0)
    {
        if (result == -1) {
            // System.err.println("error in get message");
            break;
        } else {
            // System.err.println("got message");
            lib.TranslateMessage(msg);
            lib.DispatchMessage(msg);
        }
    }lib.UnhookWindowsHookEx(hhk);
}

}

完整實現后,想在Linux下運行,需要改代碼,缺發現jar包中的Unix下面沒有像Windows一樣有很多類,想找官方文檔也找不到,苦逼啊,按理來說有Unix和Mac相關的類,應該是全平台支持的,就是不知道咋調用。

又在網上各種搜,最后整理了一下,有如下結論:

有個jintellitype項目,這個項目比較簡單,只能注冊熱鍵,比如設定一個Ctrl+S可以完成的功能,項目運行在后台,前台按這個組合鍵也可以執行自己設定的功能,這個項目只能在Windows上運行。

然后,有外國人,從上面那個項目中過得靈感,開發了Linux下的一個項目jxgrabkey,能注冊一些熱鍵在X11窗口中,也是使用C++的鈎子函數,通過JNI調用。

不過上面兩個項目都是只為注冊快捷鍵使用的,不適合用於我們這種需要輸入大量文字的模塊中。

現在還在找Linux下合適的監聽器,等實現了再開一篇帖子寫一下。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM