CAD—Keyboard事件处理
在之前的博客随笔中提到过CAD中鼠标的悬浮功能,后来就一直在想可不可以在CAD中触发Key事件,之后在Kean的一篇博文中提到过关于捕捉键盘事件,可惜不太实用,比如想通过键盘的上下键来移动一个实体。效果就像下面这样
后来就想用钩子实现吧,然后在网上找KeyHook之类的信息,现成的代码真是太多了,现在贴出这部分网上找到的代码
代码
编译成dll,然后将其加载到你的CAD项目中,在CAD中要实现的代码很容易。
1 public class KeyboardHook
2 {
3 public event KeyEventHandler KeyDownEvent;
4
5 public delegate int HookProc(int nCode, Int32 wParam, IntPtr lParam);
6
7 static int hKeyboardHook = 0;//声明键盘钩子处理的初始值
8
9 public const int WH_KEYBOARD_LL = 13;
10
11 HookProc KeyboardHookProcedure;
12
13 [StructLayout(LayoutKind.Sequential)]
14 public class KeyboardHookStruct
15 {
16 public int vkCode;
17 public int scanCode;
18 public int flags;
19 public int time;
20 public int dwExtraInfo;
21 }
22
23 [DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
24 public static extern int SetWindowsHookEx(int idHook, HookProc lpfn, IntPtr hInstance, int threadId);
25
26 [DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
27 public static extern bool UnhookWindowsHookEx(int idHook);
28
29 [DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
30 public static extern int CallNextHookEx(int idHook, int nCode, Int32 wParam, IntPtr lParam);
31
32 public void Start()
33 {
34 if (hKeyboardHook == 0)
35 {
36 KeyboardHookProcedure = new HookProc(KeyboardHookProc);
37 hKeyboardHook = SetWindowsHookEx(WH_KEYBOARD_LL, KeyboardHookProcedure, Marshal.GetHINSTANCE(Assembly.GetExecutingAssembly().GetModules()[0]), 0);
38
39 if (hKeyboardHook == 0)
40 {
41 Stop();
42 throw new Exception("安装键盘钩子失败 ");
43 }
44 }
45 }
46
47 public void Stop()
48 {
49 bool retKeyboard = true;
50
51 if (hKeyboardHook != 0)
52 {
53 retKeyboard = UnhookWindowsHookEx(hKeyboardHook);
54 hKeyboardHook = 0;
55 }
56 if (!retKeyboard) throw new Exception("卸载钩子失败!");
57 }
58
59 [DllImport("user32")]
60 public static extern int ToAscii(int uVirtKey,
61 int uScanCode,
62 byte[] lpbKeyState,
63 byte[] lpwTransKey,
64 int fuState);
65
66 [DllImport("user32")]
67 public static extern int GetKeyboardState(byte[] pbKeyState);
68
69 private const int WM_KEYDOWN = 0x100;
70 private const int WM_KEYUP = 0x101;
71 private const int WM_SYSKEYDOWN = 0x104;
72 private const int WM_SYSKEYUP = 0x105;
73
74 private int KeyboardHookProc(int nCode, Int32 wParam, IntPtr lParam)
75 {
76 if ((nCode >= 0) && (KeyDownEvent != null || KeyUpEvent != null || KeyPressEvent != null))
77 {
78 KeyboardHookStruct MyKeyboardHookStruct = (KeyboardHookStruct)Marshal.PtrToStructure(lParam, typeof(KeyboardHookStruct));
79
80 //键盘压下事件
81 if (KeyDownEvent != null && (wParam == WM_KEYDOWN || wParam == WM_SYSKEYDOWN))
82 {
83 Keys keyData = (Keys)MyKeyboardHookStruct.vkCode;
84 KeyEventArgs e = new KeyEventArgs(keyData);
85 KeyDownEvent(this, e);
86 }
87 }
88
89 return CallNextHookEx(hKeyboardHook, nCode, wParam, lParam);
90 }
91
92 ~KeyboardHook()
93 {
94 Stop();
95 }
96 }
2 {
3 public event KeyEventHandler KeyDownEvent;
4
5 public delegate int HookProc(int nCode, Int32 wParam, IntPtr lParam);
6
7 static int hKeyboardHook = 0;//声明键盘钩子处理的初始值
8
9 public const int WH_KEYBOARD_LL = 13;
10
11 HookProc KeyboardHookProcedure;
12
13 [StructLayout(LayoutKind.Sequential)]
14 public class KeyboardHookStruct
15 {
16 public int vkCode;
17 public int scanCode;
18 public int flags;
19 public int time;
20 public int dwExtraInfo;
21 }
22
23 [DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
24 public static extern int SetWindowsHookEx(int idHook, HookProc lpfn, IntPtr hInstance, int threadId);
25
26 [DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
27 public static extern bool UnhookWindowsHookEx(int idHook);
28
29 [DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
30 public static extern int CallNextHookEx(int idHook, int nCode, Int32 wParam, IntPtr lParam);
31
32 public void Start()
33 {
34 if (hKeyboardHook == 0)
35 {
36 KeyboardHookProcedure = new HookProc(KeyboardHookProc);
37 hKeyboardHook = SetWindowsHookEx(WH_KEYBOARD_LL, KeyboardHookProcedure, Marshal.GetHINSTANCE(Assembly.GetExecutingAssembly().GetModules()[0]), 0);
38
39 if (hKeyboardHook == 0)
40 {
41 Stop();
42 throw new Exception("安装键盘钩子失败 ");
43 }
44 }
45 }
46
47 public void Stop()
48 {
49 bool retKeyboard = true;
50
51 if (hKeyboardHook != 0)
52 {
53 retKeyboard = UnhookWindowsHookEx(hKeyboardHook);
54 hKeyboardHook = 0;
55 }
56 if (!retKeyboard) throw new Exception("卸载钩子失败!");
57 }
58
59 [DllImport("user32")]
60 public static extern int ToAscii(int uVirtKey,
61 int uScanCode,
62 byte[] lpbKeyState,
63 byte[] lpwTransKey,
64 int fuState);
65
66 [DllImport("user32")]
67 public static extern int GetKeyboardState(byte[] pbKeyState);
68
69 private const int WM_KEYDOWN = 0x100;
70 private const int WM_KEYUP = 0x101;
71 private const int WM_SYSKEYDOWN = 0x104;
72 private const int WM_SYSKEYUP = 0x105;
73
74 private int KeyboardHookProc(int nCode, Int32 wParam, IntPtr lParam)
75 {
76 if ((nCode >= 0) && (KeyDownEvent != null || KeyUpEvent != null || KeyPressEvent != null))
77 {
78 KeyboardHookStruct MyKeyboardHookStruct = (KeyboardHookStruct)Marshal.PtrToStructure(lParam, typeof(KeyboardHookStruct));
79
80 //键盘压下事件
81 if (KeyDownEvent != null && (wParam == WM_KEYDOWN || wParam == WM_SYSKEYDOWN))
82 {
83 Keys keyData = (Keys)MyKeyboardHookStruct.vkCode;
84 KeyEventArgs e = new KeyEventArgs(keyData);
85 KeyDownEvent(this, e);
86 }
87 }
88
89 return CallNextHookEx(hKeyboardHook, nCode, wParam, lParam);
90 }
91
92 ~KeyboardHook()
93 {
94 Stop();
95 }
96 }
代码
1 private KeyboardHook k_hook;
2 Document doc = AsApp.DocumentManager.MdiActiveDocument;
3 Database db = AsApp.DocumentManager.MdiActiveDocument.Database;
4 Editor ed = AsApp.DocumentManager.MdiActiveDocument.Editor;
5 ObjectId entId = ObjectId.Null;
6
7 [CommandMethod("MoveEnt", CommandFlags.UsePickSet)]
8 public void MoveEnt()
9 {
10
11 PromptSelectionResult res = ed.SelectImplied();
12 if (PromptStatus.OK != res.Status) return;
13
14 ObjectIdCollection ids = new ObjectIdCollection(res.Value.GetObjectIds());
15 if (ids.Count <= 0) return;
16
17 //注册键盘事件
18 try
19 {
20 k_hook = new KeyboardHook();
21 k_hook.KeyDownEvent += new KeyEventHandler(hook_KeyDown);
22 k_hook.Start();
23 }
24 catch(System.Exception ex)
25 {
26 ed.WriteMessage("\n注册键盘事件错误信息:" + ex.Message);
27 return;
28 }
29
30 Transaction tr = db.TransactionManager.StartTransaction();
31 using (tr)
32 {
33 BlockTable bt = (BlockTable)tr.GetObject(db.BlockTableId, OpenMode.ForRead);
34 BlockTableRecord btr = (BlockTableRecord)tr.GetObject(db.CurrentSpaceId, OpenMode.ForRead);
35
36 //先仅考虑一个实体
37 entId = ids[0];
38 }
39 }
40
41 private void hook_KeyDown(object sender, KeyEventArgs e)
42 {
43 if (ObjectId.Null == entId) return;
44 Transaction tr = db.TransactionManager.StartTransaction();
45 try
46 {
47 using (tr)
48 {
49 using (DocumentLock docLock = doc.LockDocument())
50 {
51 BlockTable bt = (BlockTable)tr.GetObject(db.BlockTableId, OpenMode.ForRead);
52 BlockTableRecord btr = (BlockTableRecord)tr.GetObject(db.CurrentSpaceId, OpenMode.ForRead);
53 Entity ent = tr.GetObject(entId, OpenMode.ForWrite) as Entity; //待移动的实体
54
55 Point3d entPos = Point3d.Origin;
56 if (ent is Circle) //移动一个圆
57 {
58 Circle c = ent as Circle;
59 entPos = c.Center;
60 }
61 if (e.KeyCode == Keys.Up) //向上移
62 {
63 Matrix3d matrix = Matrix3d.Displacement(new Vector3d(0, 10, 0));
64 ent.TransformBy(matrix);
65 }
66 else if (e.KeyCode == Keys.Down)
67 {
68 Matrix3d matrix = Matrix3d.Displacement(new Vector3d(0, -10, 0));
69 ent.TransformBy(matrix);
70 }
71 else if (e.KeyCode == Keys.Left)
72 {
73 Matrix3d matrix = Matrix3d.Displacement(new Vector3d(-10, 0, 0));
74 ent.TransformBy(matrix);
75 }
76 else if (e.KeyCode == Keys.Right)
77 {
78 Matrix3d matrix = Matrix3d.Displacement(new Vector3d(10, 0, 0));
79 ent.TransformBy(matrix);
80 }
81 else if (e.KeyCode == Keys.Escape)
82 {
83 ed.WriteMessage("\n按键操作取消");
84 k_hook.Stop();
85 }
86 else
87 {
88 ed.WriteMessage("\n可以通过上下键来控制实体的移动!");
89 }
90
91 //提交
92 tr.Commit();
93 ed.UpdateScreen();
94 }
95 }
96 }
97 catch (Autodesk.AutoCAD.Runtime.Exception ex)
98 {
99 ed.WriteMessage(" \n异常:" + ex.Message);
100 }
101 }
102
103 ~KeyMoveEn()
104 {
105 k_hook.Stop();
106 }
2 Document doc = AsApp.DocumentManager.MdiActiveDocument;
3 Database db = AsApp.DocumentManager.MdiActiveDocument.Database;
4 Editor ed = AsApp.DocumentManager.MdiActiveDocument.Editor;
5 ObjectId entId = ObjectId.Null;
6
7 [CommandMethod("MoveEnt", CommandFlags.UsePickSet)]
8 public void MoveEnt()
9 {
10
11 PromptSelectionResult res = ed.SelectImplied();
12 if (PromptStatus.OK != res.Status) return;
13
14 ObjectIdCollection ids = new ObjectIdCollection(res.Value.GetObjectIds());
15 if (ids.Count <= 0) return;
16
17 //注册键盘事件
18 try
19 {
20 k_hook = new KeyboardHook();
21 k_hook.KeyDownEvent += new KeyEventHandler(hook_KeyDown);
22 k_hook.Start();
23 }
24 catch(System.Exception ex)
25 {
26 ed.WriteMessage("\n注册键盘事件错误信息:" + ex.Message);
27 return;
28 }
29
30 Transaction tr = db.TransactionManager.StartTransaction();
31 using (tr)
32 {
33 BlockTable bt = (BlockTable)tr.GetObject(db.BlockTableId, OpenMode.ForRead);
34 BlockTableRecord btr = (BlockTableRecord)tr.GetObject(db.CurrentSpaceId, OpenMode.ForRead);
35
36 //先仅考虑一个实体
37 entId = ids[0];
38 }
39 }
40
41 private void hook_KeyDown(object sender, KeyEventArgs e)
42 {
43 if (ObjectId.Null == entId) return;
44 Transaction tr = db.TransactionManager.StartTransaction();
45 try
46 {
47 using (tr)
48 {
49 using (DocumentLock docLock = doc.LockDocument())
50 {
51 BlockTable bt = (BlockTable)tr.GetObject(db.BlockTableId, OpenMode.ForRead);
52 BlockTableRecord btr = (BlockTableRecord)tr.GetObject(db.CurrentSpaceId, OpenMode.ForRead);
53 Entity ent = tr.GetObject(entId, OpenMode.ForWrite) as Entity; //待移动的实体
54
55 Point3d entPos = Point3d.Origin;
56 if (ent is Circle) //移动一个圆
57 {
58 Circle c = ent as Circle;
59 entPos = c.Center;
60 }
61 if (e.KeyCode == Keys.Up) //向上移
62 {
63 Matrix3d matrix = Matrix3d.Displacement(new Vector3d(0, 10, 0));
64 ent.TransformBy(matrix);
65 }
66 else if (e.KeyCode == Keys.Down)
67 {
68 Matrix3d matrix = Matrix3d.Displacement(new Vector3d(0, -10, 0));
69 ent.TransformBy(matrix);
70 }
71 else if (e.KeyCode == Keys.Left)
72 {
73 Matrix3d matrix = Matrix3d.Displacement(new Vector3d(-10, 0, 0));
74 ent.TransformBy(matrix);
75 }
76 else if (e.KeyCode == Keys.Right)
77 {
78 Matrix3d matrix = Matrix3d.Displacement(new Vector3d(10, 0, 0));
79 ent.TransformBy(matrix);
80 }
81 else if (e.KeyCode == Keys.Escape)
82 {
83 ed.WriteMessage("\n按键操作取消");
84 k_hook.Stop();
85 }
86 else
87 {
88 ed.WriteMessage("\n可以通过上下键来控制实体的移动!");
89 }
90
91 //提交
92 tr.Commit();
93 ed.UpdateScreen();
94 }
95 }
96 }
97 catch (Autodesk.AutoCAD.Runtime.Exception ex)
98 {
99 ed.WriteMessage(" \n异常:" + ex.Message);
100 }
101 }
102
103 ~KeyMoveEn()
104 {
105 k_hook.Stop();
106 }
运行以后便是上面的贴图展现出来的效果。(看了上面的效果,感觉是不是可以实现一个CAD版本的俄罗斯方块游戏)