欢迎您访问 最编程 本站为您分享编程语言代码,编程技术文章!
您现在的位置是: 首页

Web Hid Api 浏览器读取 IC 卡号 Js 源代码,无需插件支持

最编程 2024-10-18 07:14:55
...

本示例使用的读卡器:https://item.taobao.com/item.htm?spm=a21dvs.23580594.0.0.52de2c1bW5eU3X&ft=t&id=615391857885

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Web HID Api IC卡读卡器Demo</title>

    <script language="javascript">
		var time1;
		let device;   // 需要连接或已连接的设备

		if ('hid' in navigator){
			
		}else{
		    alert('您的浏览器不支持 Web Hid API,暂无法使用以下功能!');
		}

		navigator.hid.onconnect = function event() {
		    console.log("hid device connected: ", event.target);
		}

		navigator.hid.ondisconnect = function event() {
		    console.log("hid device disconnected: ", event.target);
		}

		function ParsedReturnData(databuff){
		    var datahex="";
		    if(databuff[0]==0x78 && databuff[1]==0x68 && databuff.length>4){
		        switch ( databuff[3]) {
		            case 0x0f:
		                textarea.value="读卡器已接受响声指令!";
		                break;
		            case 0x1E:
		                textarea.value="读取设备编号成功!";
		                for (i=5;i<9;i++){datahex=datahex+databuff[i].toString(16).padStart(2, '0').toUpperCase();}
		                serialnumber.value=datahex;
		                break;
		            case 0xF0:
		                switch(databuff[4]){
		                    case 0x00:
		                        textarea.value="读取IC卡号成功!";
		                        for (i=5;i<9;i++){datahex=datahex+databuff[i].toString(16).padStart(2, '0').toUpperCase();}
		                        carduid.value=datahex;

		                        card8h10dz.value = parseInt("0x" + datahex).toString().padStart(10, '0');

		                        LHCode = datahex.substring(6, 8) + datahex.substring(4, 6) + datahex.substring(2, 4) + datahex.substring(0, 2);
		                        card8h10df.value = parseInt("0x" + LHCode).toString().padStart(10, '0');

		                        break;
		                    case 0x08:
		                        textarea.value="寻卡失败,请重新将卡片放在读卡器感应区!";
		                        break;
		                    case 0x09:
		                        textarea.value="寻卡失败,有多张卡在读卡器感应区!";
		                        break;
		                    default:
		                        textarea.value="寻卡失败,错误代码:"+databuff[4].toString();
		                        break;
		                }
		                break;
		            default:

		        }
		    }
		}

		async function selectdev() {
		    try{
		        const devices = await navigator.hid.requestDevice({
		            filters: [{
		                vendorId: 0x0801,    // 根据VID进行过滤
		                productId: 0x2011,   // 根据PID进行过滤
		            },],
		        });

		        device = devices[0];         // 选择列表中第一个设备
		        if (!device.opened) {        // 检查设备是否打开		            
		            await device.open();     // 打开设备
		        }
		        
		        device.oninputreport = (event) => {     // 电脑接收到来自设备的消息回调
		            console.log(event);                 // event中包含device、reportId、data等内容

		            let array = new Uint8Array(event.data.buffer); // event.data.buffer就是接收到的inputreport包数据了
		            ParsedReturnData(array);    
		        };
		    }
			catch (e){
		        console.log(e);
		    }
        }			

        function ButtonDisable() {  //删除按键的 onclick 事件,防止重复执行指令                 
            document.getElementById("butt_beep").setAttribute("onclick", null);
            document.getElementById("butt_getdevnum").setAttribute("onclick", null);
            document.getElementById("butt_piccrequest").setAttribute("onclick", null);
            //document.getElementById("butt_readloop").setAttribute("onclick", null);
        }

        async function beep() {				     //驱动发卡器响声令            
            if (!device?.opened) {
                alert("请先选择已连接的读卡器!");
                return;
            }
            textarea.value = "";

            const outputData = new Uint8Array(32);
            outputData[0]=0x78;     
            outputData[1]=0x68;   
            outputData[2]=0x04;
            outputData[3]=0x0f;
            outputData[4]=0x1e;
            outputData[5]=0x00;
            outputData[6]=0xe9;
            outputData[7]=0x00;            
            await device.sendReport(0, outputData); // 发送数据,第一个参数为reportId,填0表示不使用reportId
        }
		
        async function getdevicenumber() {         //读取发卡器唯一出厂序号,可以当加密狗使用			
            if (!device?.opened) {
                alert("请先选择已连接的读卡器!");
                return;
            }
            textarea.value = "";	
            serialnumber.value="";

            const outputData = new Uint8Array(32);
            outputData[0]=0x78;     
            outputData[1]=0x68;   
            outputData[2]=0x01;
            outputData[3]=0x1e;
            outputData[4]=0x00;
            outputData[5]=0x00;
            outputData[6]=0x00;
            outputData[7]=0x00;
		    
            await device.sendReport(0, outputData); // 发送数据,第一个参数为reportId,填0表示不使用reportId
        }			
		
        async function piccrequest() {
            if (!device?.opened) {
                alert("请先选择已连接的读卡器!");
                return;
            }
            textarea.value = "";		
            carduid.value="";
            card8h10dz.value="";
            card8h10df.value="";

            const outputData = new Uint8Array(32);
            outputData[0]=0x78;     
            outputData[1]=0x68;   
            outputData[2]=0x01;
            outputData[3]=0xf0;
            outputData[4]=0x00;
            outputData[5]=0x00;
            outputData[6]=0x00;
            outputData[7]=0x00;
		    
            await device.sendReport(0, outputData); // 发送数据,第一个参数为reportId,填0表示不使用reportId
        }
		
        function request_loop() {
            if (!device?.opened) {
                alert("请先选择已连接的读卡器!");
                return;
            }
            if (document.getElementById('butt_readloop').value == '轮询读取IC卡卡号') {
                document.getElementById('butt_readloop').value = '停止轮询';
                ButtonDisable();
                time1 = setInterval("piccrequest()", 500);             //开启间隔500毫秒寻一次卡
            } else {
                document.getElementById('butt_readloop').value = '轮询读取IC卡卡号';
                clearInterval(time1);
                ButtonEnabled();
            }
		}
						
		function ButtonEnabled() {  //恢复各button 的onclick事件            
		    document.getElementById("butt_beep").setAttribute("onclick", "beep()");
		    document.getElementById("butt_getdevnum").setAttribute("onclick", "getdevicenumber()");
		    document.getElementById("butt_piccrequest").setAttribute("onclick", "piccrequest()");
		    //document.getElementById("butt_readloop").setAttribute("onclick", "request_loop()");		    
		}
								
		window.onerror = function (e) {
		    ButtonEnabled();  //恢复按键的onclick事件
		    clearInterval(time1);
		    document.getElementById('butt_readloop').value = '轮询读取IC卡卡号';
            alert("不好意思,出错了!");
            return true;//屏蔽系统事件
        }


	</script>
    
	<style>
		th {
		  background-color:#F6FAFF;	
		  color: blue;
		  font-family:楷体;
		}
		td {
		  background-color:#F6FAFF;		
		  font-family:楷体;
		}  
    </style>    
        
</head>

<body>
<table width="866" height="346"  align="center">
    <tr>
        <th width="124" height="60" scope="row"><input style="width:120px" name="butt_selectdev" type="submit" id="butt_selectdev" onclick="selectdev()" value="选择连接的读卡器" /></th>
        <td width="716">
            
        </td>
    </tr>

  <tr>
    <th width="124" height="60" scope="row"><input style="width:120px" name="butt_beep" type="submit" id="butt_beep" onclick="beep()" value="驱动读卡器响声" /></th>
    <td width="716"><input name="butt_getdevnum" type="submit" id="butt_getdevnum" onclick="getdevicenumber()" value="获取读卡器唯一出厂序列号" />
      设备编号:
        <input style="color:red;text-align:center;" name="serialnumber" type="text" id="serialnumber" size="8" maxlength="8" /></td>
  </tr>
  
  <tr>
    <th height="80" scope="row">
        <input style="width:120px" name="butt_piccrequest" type="submit" id="butt_piccrequest" onclick="piccrequest()" value="读取IC卡卡号" />
      <br /><br />    
        <input name="butt_readloop" type="submit" id="butt_readloop" style="width:120px" onclick="request_loop()" value="轮询读取IC卡卡号" />
    </th>
    <td>原始16进制卡号:
      <input style="color:red;text-align:center;" name="carduid" type="text" id="carduid" size="8" maxlength="8" />
      ,转8H10D正码:
      <input style="color:red;text-align:center;" name="card8h10dz" type="text" id="card8h10dz" size="10" maxlength="10" />
      ,8H10D反码:
      <input style="color:red;text-align:center;" name="card8h10df" type="text" id="card8h10df" size="10" maxlength="10" /></td>
  </tr>

  <tr>
    <th height="120" scope="row"><p>&nbsp;</p>
      <p>操作提示</p>
    <p>&nbsp;</p></th>
    <td><textarea style="color:blue;" name="textarea" id="textarea" cols="100" rows="8" ></textarea></td>
  </tr>


</table>
</body>
</html>