使用c#捕获usb扫描枪扫描二维码、条形码结果(支持中文版)
之前在18年写过一个使用c#捕获usb扫描枪扫描二维码、条形码结果,当时我是没有遇到需要使用中文的情况,因为二维码都是我自己控制生成的,如果遇到中文,我会提前进行编码编程unicode编码,所以,没有专门针对中文符号做支持
但一年多以来,不少人询问,或者在博客下留言,提出了中文扫码支持的需要,于是老顾就从新把程序从故纸堆里翻了出来,毕竟很久没弄这个了,还得自己重新读一遍代码,真晕。。。。。
好在,中文支持已经实现了
public class ScanerCodes
{
private int ts = 500; // 指定输入间隔为500毫秒以内时为连续输入
private List<List<EventMsg>> _keys = new List<List<EventMsg>>();
private List<int> _keydown = new List<int>(); // 保存组合键状态
private List<string> _result = new List<string>(); // 返回结果集
private List<string> _alt = new List<string>(); // 保存alt按下时的各键位
private DateTime _last = DateTime.Now;
private byte[] _state = new byte[256];
private string _key = string.Empty;
private string _cur = string.Empty;
public EventMsg Event
{
get
{
if (_keys.Count == 0)
{
return new EventMsg();
}
else
{
return _keys[_keys.Count - 1][_keys[_keys.Count - 1].Count - 1];
}
}
}
public List<int> KeyDowns
{
get
{
return _keydown;
}
}
public DateTime LastInput
{
get
{
return _last;
}
}
public byte[] KeyboardState
{
get
{
return _state;
}
}
public int KeyDownCount
{
get
{
return _keydown.Count;
}
}
public string Result
{
get
{
if (_result.Count > 0)
{
return _result[_result.Count - 1].Trim();
}
else
{
return null;
}
}
}
public string CurrentKey
{
get
{
return _key;
}
}
public string CurrentChar
{
get
{
return _cur;
}
}
public bool isShift
{
get
{
return _keydown.Contains(160) || _keydown.Contains(161);
}
}
public bool isAlt
{
get
{
return _keydown.Contains(164) || _keydown.Contains(165);
}
}
public bool isControl
{
get
{
return _keydown.Contains(162) || _keydown.Contains(163);
}
}
public void Clear()
{
_keys.Clear();
_result.Clear();
}
public void Add(EventMsg msg)
{
#region 记录按键信息
// 首次按下按键
if (_keys.Count == 0)
{
_keys.Add(new List<EventMsg>());
_keys[0].Add(msg);
_result.Add(string.Empty);
}
// 未释放其他按键时按下按键
else if (_keydown.Count > 0)
{
_keys[_keys.Count - 1].Add(msg);
}
// 单位时间内按下按键
else if (((TimeSpan)(DateTime.Now - _last)).TotalMilliseconds < ts)
{
_keys[_keys.Count - 1].Add(msg);
}
// 从新记录输入内容
else
{
_keys.Add(new List<EventMsg>());
_keys[_keys.Count - 1].Add(msg);
_result.Add(string.Empty);
}
if (_keys.Count > 10)
{
_keys.RemoveAt(0);
}
#endregion
_last = DateTime.Now;
#region 获取键盘状态
// 记录正在按下的按键
if (msg.paramH < 128 && !_keydown.Contains(msg.message))
{
_keydown.Add(msg.message);
}
// 清除已松开的按键
if (msg.paramH > 127 && _keydown.Contains(msg.message))
{
_keydown.Remove(msg.message);
}
#endregion
#region 计算按键信息
int v = msg.message & 0xff;
int c = msg.paramL & 0xff;
StringBuilder strKeyName = new StringBuilder(500);
if (GetKeyNameText(c * 65536, strKeyName, 255) > 0)
{
_key = strKeyName.ToString().Trim(new char[] { ' ', '\0' });
GetKeyboardState(_state);
if (_key.Length == 1 && msg.paramH < 128)
{
// 根据键盘状态和shift缓存判断输出字符
_cur = ShiftChar(_key, isShift, _state).ToString();
_result[_result.Count - 1] += _cur;
}
else if (msg.paramH < 128 && isAlt)
{
_alt.Add(_key);
}
else if (msg.paramH > 127 && (msg.message == 164 || msg.message == 165))
{
string composite = string.Empty;
for (int i = 0; i < _alt.Count; i++)
{
composite += _alt[i];
}
composite = Regex.Replace(composite, @"[^0-9]+", "");
string hex = Convert.ToInt32(composite).ToString("x");
if (hex.Length % 2 == 1)
{
hex = "0" + hex;
}
string str = Regex.Replace(hex, @"([0-9a-f]{2})", "%$1");
_cur = System.Web.HttpUtility.UrlDecode(str, Encoding.GetEncoding(936));
_result[_result.Count - 1] += _cur;
_alt.Clear();
}
else
{
_cur = string.Empty;
}
}
#endregion
}
private char ShiftChar(string k, bool isShiftDown, byte[] state)
{
bool capslock = state[0x14] == 1;
bool numlock = state[0x90] == 1;
bool scrolllock = state[0x91] == 1;
bool shiftdown = state[0xa0] == 1;
char chr = (capslock ? k.ToUpper() : k.ToLower()).ToCharArray()[0];
if (isShiftDown)
{
if (chr >= 'a' && chr <= 'z')
{
chr = (char)((int)chr - 32);
}
else if (chr >= 'A' && chr <= 'Z')
{
chr = (char)((int)chr + 32);
}
else
{
string s = "`1234567890-=[];',./";
string u = "[email protected]#$%^&*()_+{}:\"<>?";
if (s.IndexOf(chr) >= 0)
{
return (u.ToCharArray())[s.IndexOf(chr)];
}
}
}
return chr;
}
}
说起来,其实也没有修改很多东西,只对ScanerCodes这个类做了下微调,其他代码我就不再复制过来了,请参考原文
以下是中文支持的思路和尝试过程
首先,根据原文中不吃辣的阿银同学提出的问题,左右shift键paramH值不同的问题专门测试了一下,发现的确存在这种问题
那么第一步就是调整isShift,这里有个测试结果,有兴趣继续魔改的可以看一下
paramH,message
0,160 // Lshift down
128,160 // Lshift up
1,161 // Rshift down
129,161 // Rshift up
0,162 // Lctrl down
128,162 // Lctrl up
1,163 // Rctrl down
129,163 // Rctrl up
32,164 // Lalt down
128,164 // Lalt up
33,165 // Ralt down
129,165 // Ralt up
我这里使用的还是科密扫描枪,如果其他型号扫描枪有不同的结果,请自行尝试
isShift修改为判断已按下的键中,是否存在左右shift键对应的编号
然后,尝试进行中文扫码,直接一脸懵逼了。。。。所有的_key得到的结果都是长度大于1的内容,这都什么和什么啊,然后发现捕捉到了32,164的组合,这不是按alt键了吗?一脸疑惑中。。。。
然后通过调试发现,之后的键盘信息_key给我的是 Numpad 4,Numpad 5,Numpad 7,Numpad 9,Numpad 4。。。。。。
一脸惊讶!我是知道按住alt不送,直接在数字小键盘上输入数字可以出现任意符号的,难道扫描枪扫到中文也是这么搞得?
直接用数字小键盘尝试了下Alt+45794。。。。出现了一个“测”字,好吧。。。。这个是我生成的二维码。。。。。
那么有了这个结果,后边就相对简单了,直接加一个状态,isAlt,嗯,顺便支持左右Alt
然后重新定义一个数组_alt,用来记录alt键释放前的所有键盘信息
最后,在alt键释放的时候将_alt数组中的信息组合起来,得到小键盘数字顺序,并清空_alt数组,以便下一次继续获取中文符号
好了,得到了数字后就需要把数字转成中文了,然后当我使用(char)45794转出来的内容是个韩文字符的时候,我差点崩溃了。。。NND,扫描枪居然有字符集设置,而不是使用的unicode!
行吧,如果有人购买的扫描枪在数字转字符时不对,那一定是编码的锅,自己测试到底是什么编码吧!
于是,我就将数字转成16进制,然后补%,冒充urldecode的结果,然后使用gb2312进行urldecode,得到了正确结果,中文支持完成
上一篇: java 加解密(3DES)
下一篇: java 加解密(3DES)