本示例使用的读卡器: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> </p>
<p>操作提示</p>
<p> </p></th>
<td><textarea style="color:blue;" name="textarea" id="textarea" cols="100" rows="8" ></textarea></td>
</tr>
</table>
</body>
</html>