版博士V2.0程序
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

CodeScanner.cs 12 KiB

2 vuotta sitten
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Diagnostics;
  4. using System.Runtime.InteropServices;
  5. using System.Text;
  6. namespace ProductionControl.Device
  7. {
  8. public class CodeScanner
  9. {
  10. #region WIN32API
  11. //private const int WM_KEYDOWN = 0x100;//KEYDOWN       
  12. //private const int WM_KEYUP = 0x101;//KEYUP       
  13. //private const int WM_SYSKEYDOWN = 0x104;//SYSKEYDOWN       
  14. //private const int WM_SYSKEYUP = 0x105;//SYSKEYUP
  15. //private static int HookProc(int nCode, Int32 wParam, IntPtr lParam);
  16. private int hKeyboardHook = 0;//声明键盘钩子处理的初始值
  17. private ScanerCodes codes = new ScanerCodes();//13为键盘钩子
  18. //定义成静态,这样不会抛出回收异常
  19. private static HookProc hookproc;
  20. delegate int HookProc(int nCode, Int32 wParam, IntPtr lParam);
  21. [DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]     //设置钩子
  22. private static extern int SetWindowsHookEx(int idHook, HookProc lpfn, IntPtr hInstance, int threadId);
  23. [DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]     //卸载钩子
  24. private static extern bool UnhookWindowsHookEx(int idHook);
  25. [DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)] //继续下个钩子
  26. private static extern int CallNextHookEx(int idHook, int nCode, Int32 wParam, IntPtr lParam);
  27. [DllImport("user32", EntryPoint = "GetKeyNameText")]
  28. private static extern int GetKeyNameText(int IParam, StringBuilder lpBuffer, int nSize);
  29. [DllImport("user32", EntryPoint = "GetKeyboardState")]     //获取按键的状态
  30. private static extern int GetKeyboardState(byte[] pbKeyState);
  31. [DllImport("user32", EntryPoint = "ToAscii")]     //ToAscii职能的转换指定的虚拟键码和键盘状态的相应字符或字符
  32. private static extern bool ToAscii(int VirtualKey, int ScanCode, byte[] lpKeySate, ref uint lpChar, int uFlags);
  33. //int VirtualKey //[in] 指定虚拟关键代码进行翻译。      
  34. //int uScanCode, // [in] 指定的硬件扫描码的关键须翻译成英文。高阶位的这个值设定的关键,如果是(不压)      
  35. //byte[] lpbKeyState, // [in] 指针,以256字节数组,包含当前键盘的状态。每个元素(字节)的数组包含状态的一个关键。如果高阶位的字节是一套,关键是下跌(按下)。在低比特,如/果设置表明,关键是对切换。在此功能,只有肘位的CAPS LOCK键是相关的。在切换状态的NUM个锁和滚动锁定键被忽略。      //byte[] lpwTransKey, // [out] 指针的缓冲区收到翻译字符或字符。      //uint fuState); // [in] Specifies whether a menu is active. This parameter must be 1 if a menu is active, or 0 otherwise.
  36. [DllImport("kernel32.dll")]     //使用WINDOWS API函数代替获取当前实例的函数,防止钩子失效
  37. private static extern IntPtr GetModuleHandle(string name);
  38. #endregion
  39. public Action<int, string> log;
  40. //public Action<ScanerCodes> ScanerEvent;
  41. public Action<string> ScanerEvent;
  42. public CodeScanner()
  43. {
  44. }
  45. public bool start()
  46. {
  47. if (hKeyboardHook == 0)
  48. {
  49. hookproc = new HookProc(KeyboardHookProc);
  50. //GetModuleHandle 函数 替代 Marshal.GetHINSTANCE
  51. //防止在 framework4.0中 注册钩子不成功
  52. IntPtr modulePtr = GetModuleHandle(Process.GetCurrentProcess().MainModule.ModuleName);
  53. //WH_KEYBOARD_LL=13
  54. //全局钩子 WH_KEYBOARD_LL
  55. // hKeyboardHook = SetWindowsHookEx(13, hookproc, Marshal.GetHINSTANCE(Assembly.GetExecutingAssembly().GetModules()[0]), 0);
  56. hKeyboardHook = SetWindowsHookEx(13, hookproc, modulePtr, 0);
  57. }
  58. return (hKeyboardHook != 0);
  59. }
  60. public bool stop()
  61. {
  62. if (hKeyboardHook != 0)
  63. {
  64. bool retKeyboard = UnhookWindowsHookEx(hKeyboardHook);
  65. hKeyboardHook = 0;
  66. return retKeyboard;
  67. }
  68. return true;
  69. }
  70. private int KeyboardHookProc(int nCode, Int32 wParam, IntPtr lParam)
  71. {
  72. EventMsg msg = (EventMsg)Marshal.PtrToStructure(lParam, typeof(EventMsg));
  73. codes.Add(msg);
  74. if (msg.message == 13 && msg.paramH > 0 && !string.IsNullOrEmpty(codes.Result))
  75. {
  76. ScanerEvent?.Invoke(codes.Result);
  77. }
  78. return CallNextHookEx(hKeyboardHook, nCode, wParam, lParam);
  79. }
  80. public class ScanerCodes
  81. {
  82. private int ts = 100; // 指定输入间隔为300毫秒以内时为连续输入
  83. private List<List<EventMsg>> _keys = new List<List<EventMsg>>();
  84. private List<int> _keydown = new List<int>(); // 保存组合键状态
  85. private List<string> _result = new List<string>(); // 返回结果集
  86. private DateTime _last = DateTime.Now;
  87. private byte[] _state = new byte[256];
  88. private string _key = string.Empty;
  89. private string _cur = string.Empty;
  90. public EventMsg Event
  91. {
  92. get
  93. {
  94. if (_keys.Count == 0)
  95. {
  96. return new EventMsg();
  97. }
  98. else
  99. {
  100. return _keys[_keys.Count - 1][_keys[_keys.Count - 1].Count - 1];
  101. }
  102. }
  103. }
  104. public List<int> KeyDowns
  105. {
  106. get
  107. {
  108. return _keydown;
  109. }
  110. }
  111. public DateTime LastInput
  112. {
  113. get
  114. {
  115. return _last;
  116. }
  117. }
  118. public byte[] KeyboardState
  119. {
  120. get
  121. {
  122. return _state;
  123. }
  124. }
  125. public int KeyDownCount
  126. {
  127. get
  128. {
  129. return _keydown.Count;
  130. }
  131. }
  132. public string Result
  133. {
  134. get
  135. {
  136. if (_result.Count > 0)
  137. {
  138. return _result[_result.Count - 1].Trim();
  139. }
  140. else
  141. {
  142. return null;
  143. }
  144. }
  145. }
  146. public string CurrentKey
  147. {
  148. get
  149. {
  150. return _key;
  151. }
  152. }
  153. public string CurrentChar
  154. {
  155. get
  156. {
  157. return _cur;
  158. }
  159. }
  160. public bool isShift
  161. {
  162. get
  163. {
  164. return _keydown.Contains(160);
  165. }
  166. }
  167. public void Add(EventMsg msg)
  168. {
  169. #region 记录按键信息
  170. // 首次按下按键
  171. if (_keys.Count == 0)
  172. {
  173. _keys.Add(new List<EventMsg>());
  174. _keys[0].Add(msg);
  175. _result.Add(string.Empty);
  176. }
  177. // 未释放其他按键时按下按键
  178. else if (_keydown.Count > 0)
  179. {
  180. _keys[_keys.Count - 1].Add(msg);
  181. }
  182. // 单位时间内按下按键
  183. else if (((TimeSpan)(DateTime.Now - _last)).TotalMilliseconds < ts)
  184. {
  185. _keys[_keys.Count - 1].Add(msg);
  186. }
  187. // 从新记录输入内容
  188. else
  189. {
  190. _keys.Add(new List<EventMsg>());
  191. _keys[_keys.Count - 1].Add(msg);
  192. _result.Add(string.Empty);
  193. }
  194. #endregion
  195. _last = DateTime.Now;
  196. #region 获取键盘状态
  197. // 记录正在按下的按键
  198. if (msg.paramH == 0 && !_keydown.Contains(msg.message))
  199. {
  200. _keydown.Add(msg.message);
  201. }
  202. // 清除已松开的按键
  203. if (msg.paramH > 0 && _keydown.Contains(msg.message))
  204. {
  205. _keydown.Remove(msg.message);
  206. }
  207. #endregion
  208. #region 计算按键信息
  209. int v = msg.message & 0xff;
  210. int c = msg.paramL & 0xff;
  211. StringBuilder strKeyName = new StringBuilder(500);
  212. if (GetKeyNameText(c * 65536, strKeyName, 255) > 0)
  213. {
  214. _key = strKeyName.ToString().Trim(new char[] { ' ', '\0' });
  215. GetKeyboardState(_state);
  216. if (_key.Length == 1 && msg.paramH == 0)// && msg.paramH == 0
  217. {
  218. // 根据键盘状态和shift缓存判断输出字符
  219. _cur = ShiftChar(_key, isShift, _state).ToString();
  220. _result[_result.Count - 1] += _cur;
  221. }
  222. //判断是+ 强制添加+
  223. else if (_key.Length == 5 && msg.paramH == 0 && msg.paramL == 78 && msg.message == 107)
  224. {
  225. // 根据键盘状态和shift缓存判断输出字符
  226. _cur = Convert.ToChar('+').ToString();
  227. _result[_result.Count - 1] += _cur;
  228. }
  229. // 备选          
  230. else
  231. {
  232. _cur = string.Empty;
  233. }
  234. }
  235. #endregion
  236. }
  237. private char ShiftChar(string k, bool isShiftDown, byte[] state)
  238. {
  239. bool capslock = state[0x14] == 1;
  240. bool numlock = state[0x90] == 1;
  241. bool scrolllock = state[0x91] == 1;
  242. bool shiftdown = state[0xa0] == 1;
  243. char chr = (capslock ? k.ToUpper() : k.ToLower()).ToCharArray()[0];
  244. if (isShiftDown)
  245. {
  246. if (chr >= 'a' && chr <= 'z')
  247. {
  248. chr = (char)((int)chr - 32);
  249. }
  250. else if (chr >= 'A' && chr <= 'Z')
  251. {
  252. if (chr == 'Z')
  253. {
  254. string s = "";
  255. }
  256. chr = (char)((int)chr + 32);
  257. }
  258. else
  259. {
  260. string s = "`1234567890-=[];',./";
  261. string u = "~!@#$%^&*()_+{}:\"<>?";
  262. if (s.IndexOf(chr) >= 0)
  263. {
  264. return (u.ToCharArray())[s.IndexOf(chr)];
  265. }
  266. }
  267. }
  268. return chr;
  269. }
  270. }
  271. public struct EventMsg
  272. {
  273. public int message;
  274. public int paramL;
  275. public int paramH;
  276. public int Time;
  277. public int hwnd;
  278. }
  279. }
  280. }