1 // Permission is hereby granted, free of charge, to any person obtaining
2 // a copy of this software and associated documentation files (the
3 // "Software"), to deal in the Software without restriction, including
4 // without limitation the rights to use, copy, modify, merge, publish,
5 // distribute, sublicense, and/or sell copies of the Software, and to
6 // permit persons to whom the Software is furnished to do so, subject to
7 // the following conditions:
9 // The above copyright notice and this permission notice shall be
10 // included in all copies or substantial portions of the Software.
12 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
13 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
14 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
15 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
16 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
17 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
18 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
20 // Copyright (c) 2007 Novell, Inc.
23 // Geoff Norton (gnorton@novell.com)
27 using System.Collections;
29 using System.Globalization;
30 using System.Runtime.InteropServices;
32 namespace System.Windows.Forms.CarbonInternal {
33 internal class KeyboardHandler : EventHandlerBase, IEventHandler {
34 internal const uint kEventRawKeyDown = 1;
35 internal const uint kEventRawKeyRepeat = 2;
36 internal const uint kEventRawKeyUp = 3;
37 internal const uint kEventRawKeyModifiersChanged = 4;
38 internal const uint kEventHotKeyPressed = 5;
39 internal const uint kEventHotKeyReleased = 6;
41 internal const uint kEventParamKeyMacCharCodes = 1801676914;
42 internal const uint kEventParamKeyCode = 1801678692;
43 internal const uint kEventParamKeyModifiers = 1802334052;
44 internal const uint kEventTextInputUnicodeForKeyEvent = 2;
45 internal const uint kEventParamTextInputSendText = 1953723512;
47 internal const uint typeChar = 1413830740;
48 internal const uint typeUInt32 = 1835100014;
49 internal const uint typeUnicodeText = 1970567284;
51 internal static byte [] key_filter_table;
52 internal static byte [] key_modifier_table;
53 internal static byte [] key_translation_table;
54 internal static byte [] char_translation_table;
56 internal static bool translate_modifier = false;
58 static KeyboardHandler () {
59 // our key filter table is a 256 byte array - if the corresponding byte
60 // is set the key should be filtered from WM_CHAR (apple pushes unicode events
61 // for some keys which win32 only handles as KEYDOWN
62 // currently filtered:
68 // Please update this list as well as the table as more keys are found
69 key_filter_table = new byte [256] {
70 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
71 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01,
72 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
73 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
74 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
75 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
76 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
77 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
78 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
79 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
80 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
81 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
82 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
83 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
84 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
85 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
88 // our char translation table is a set of translations from mac char codes
89 // to win32 vkey codes
90 // most things map directly
91 char_translation_table = new byte [256] {
92 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
93 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 0x25, 0x27, 0x26, 0x28,
94 32, 49, 34, 51, 52, 53, 55, 222, 57, 48, 56, 187, 188, 189, 190, 191,
95 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 186, 60, 61, 62, 63,
96 50, 65, 66, 67, 68, 187, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79,
97 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 219, 220, 221, 54, 189,
98 192, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79,
99 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 123, 124, 125, 126, 0x2e,
100 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143,
101 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159,
102 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175,
103 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191,
104 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207,
105 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223,
106 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239,
107 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255
109 key_translation_table = new byte [256] {
110 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
111 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
112 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
113 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
114 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79,
115 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95,
116 0x74, 0x75, 0x76, 0x72, 0x77, 0x78, 0x79, 103, 104, 105, 106, 107, 108, 109, 0x7a, 0x7b,
117 112, 113, 114, 115, 116, 117, 0x73, 119, 0x71, 121, 0x70, 123, 124, 125, 126, 127,
118 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143,
119 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159,
120 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175,
121 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191,
122 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207,
123 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223,
124 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239,
125 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255
127 // the key modifier table is a state table of the possible modifier keys
128 // apple currently only goes up to 1 << 14 keys, we've extended this to 32
129 // bytes as thats the size that apple uses
130 key_modifier_table = new byte [32];
133 internal KeyboardHandler (XplatUICarbon driver) : base (driver) {}
135 private void ModifierToVirtualKey (int i, ref MSG msg, bool down) {
136 msg.hwnd = XplatUICarbon.FocusWindow;
138 if (i == 9 || i == 13) {
139 msg.message = (down ? Msg.WM_KEYDOWN : Msg.WM_KEYUP);
140 msg.wParam = (IntPtr) VirtualKeys.VK_SHIFT;
141 msg.lParam = IntPtr.Zero;
144 if (i == 12 || i == 14) {
145 msg.message = (down ? Msg.WM_KEYDOWN : Msg.WM_KEYUP);
146 msg.wParam = (IntPtr) VirtualKeys.VK_CONTROL;
147 msg.lParam = IntPtr.Zero;
151 msg.message = (down ? Msg.WM_SYSKEYDOWN : Msg.WM_SYSKEYUP);
152 msg.wParam = (IntPtr) VirtualKeys.VK_MENU;
153 msg.lParam = new IntPtr (0x20000000);
160 public void ProcessModifiers (IntPtr eventref, ref MSG msg) {
161 // we get notified when modifiers change, but not specifically what changed
162 UInt32 modifiers = 0;
164 GetEventParameter (eventref, kEventParamKeyModifiers, typeUInt32, IntPtr.Zero, (uint)Marshal.SizeOf (typeof (UInt32)), IntPtr.Zero, ref modifiers);
166 for (int i = 0; i < 32; i++) {
167 if (key_modifier_table [i] == 0x01 && (modifiers & (1 << i)) == 0) {
168 ModifierToVirtualKey (i, ref msg, false);
169 key_modifier_table [i] = 0x00;
171 } else if (key_modifier_table [i] == 0x00 && (modifiers & (1 << i)) == (1 << i)) {
172 ModifierToVirtualKey (i, ref msg, true);
173 key_modifier_table [i] = 0x01;
181 public void ProcessText (IntPtr eventref, ref MSG msg) {
183 IntPtr buffer = IntPtr.Zero;
186 // get the size of the unicode buffer
187 GetEventParameter (eventref, kEventParamTextInputSendText, typeUnicodeText, IntPtr.Zero, 0, ref size, IntPtr.Zero);
189 buffer = Marshal.AllocHGlobal ((int) size);
190 bdata = new byte [size];
192 // get the actual text buffer
193 GetEventParameter (eventref, kEventParamTextInputSendText, typeUnicodeText, IntPtr.Zero, size, IntPtr.Zero, buffer);
195 Marshal.Copy (buffer, bdata, 0, (int) size);
196 Marshal.FreeHGlobal (buffer);
198 if (key_filter_table [bdata [0]] == 0x00) {
199 // TODO: We support 2byte/4byte unicode? how does this get packed
200 msg.message = Msg.WM_CHAR;
201 msg.wParam = BitConverter.IsLittleEndian ? (IntPtr) bdata [0] : (IntPtr) bdata [size-1];
202 msg.lParam = IntPtr.Zero;
203 msg.hwnd = XplatUICarbon.FocusWindow;
207 public void ProcessKeyPress (IntPtr eventref, ref MSG msg) {
211 GetEventParameter (eventref, kEventParamKeyMacCharCodes, typeChar, IntPtr.Zero, (uint)Marshal.SizeOf (typeof (byte)), IntPtr.Zero, ref charCode);
212 GetEventParameter (eventref, kEventParamKeyCode, typeUInt32, IntPtr.Zero, (uint)Marshal.SizeOf (typeof (byte)), IntPtr.Zero, ref keyCode);
214 msg.lParam = (IntPtr) charCode;
215 msg.wParam = charCode == 0x10 ? (IntPtr) key_translation_table [keyCode] : (IntPtr) char_translation_table [charCode];
216 msg.hwnd = XplatUICarbon.FocusWindow;
219 public bool ProcessEvent (IntPtr callref, IntPtr eventref, IntPtr handle, uint kind, ref MSG msg) {
220 uint klass = EventHandler.GetEventClass (eventref);
223 if (klass == EventHandler.kEventClassTextInput) {
225 case kEventTextInputUnicodeForKeyEvent:
226 ProcessText (eventref, ref msg);
229 Console.WriteLine ("WARNING: KeyboardHandler.ProcessEvent default handler for kEventClassTextInput should not be reached");
232 } else if (klass == EventHandler.kEventClassKeyboard) {
234 case kEventRawKeyDown:
235 case kEventRawKeyRepeat:
236 msg.message = Msg.WM_KEYDOWN;
237 ProcessKeyPress (eventref, ref msg);
240 msg.message = Msg.WM_KEYUP;
241 ProcessKeyPress (eventref, ref msg);
243 case kEventRawKeyModifiersChanged:
244 ProcessModifiers (eventref, ref msg);
247 Console.WriteLine ("WARNING: KeyboardHandler.ProcessEvent default handler for kEventClassKeyboard should not be reached");
251 Console.WriteLine ("WARNING: KeyboardHandler.ProcessEvent default handler for kEventClassTextInput should not be reached");
257 public bool TranslateMessage (ref MSG msg) {
260 if (msg.message >= Msg.WM_KEYFIRST && msg.message <= Msg.WM_KEYLAST)
263 if (msg.message != Msg.WM_KEYDOWN && msg.message != Msg.WM_SYSKEYDOWN && msg.message != Msg.WM_KEYUP && msg.message != Msg.WM_SYSKEYUP && msg.message != Msg.WM_CHAR && msg.message != Msg.WM_SYSCHAR)
266 if (key_modifier_table [8] == 0x01 && key_modifier_table [12] == 0x00 && key_modifier_table [14] == 0x00) {
267 if (msg.message == Msg.WM_KEYDOWN) {
268 msg.message = Msg.WM_SYSKEYDOWN;
269 } else if (msg.message == Msg.WM_CHAR) {
270 msg.message = Msg.WM_SYSCHAR;
271 translate_modifier = true;
272 } else if (msg.message == Msg.WM_KEYUP) {
273 msg.message = Msg.WM_SYSKEYUP;
278 msg.lParam = new IntPtr (0x20000000);
279 } else if (msg.message == Msg.WM_SYSKEYUP && translate_modifier && msg.wParam == (IntPtr) 18) {
280 msg.message = Msg.WM_KEYUP;
282 msg.lParam = IntPtr.Zero;
283 translate_modifier = false;
289 internal Keys ModifierKeys {
291 Keys keys = Keys.None;
292 if (key_modifier_table [9] == 0x01 || key_modifier_table [13] == 0x01) { keys |= Keys.Shift; }
293 if (key_modifier_table [8] == 0x01) { keys |= Keys.Alt; }
294 if (key_modifier_table [12] == 0x01 || key_modifier_table [14] == 0x01) { keys |= Keys.Control; }
299 [DllImport ("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")]
300 static extern int GetEventParameter (IntPtr eventref, uint name, uint type, IntPtr outtype, uint size, ref UInt32 outsize, IntPtr data);
301 [DllImport ("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")]
302 static extern int GetEventParameter (IntPtr eventref, uint name, uint type, IntPtr outtype, uint size, IntPtr outsize, IntPtr data);
303 [DllImport ("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")]
304 static extern int GetEventParameter (IntPtr eventref, uint name, uint type, IntPtr outtype, uint size, IntPtr outsize, ref byte data);
305 [DllImport ("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")]
306 static extern int GetEventParameter (IntPtr eventref, uint name, uint type, IntPtr outtype, uint size, IntPtr outsize, ref UInt32 data);
309 internal enum KeyboardModifiers : uint {
316 controlKey = 1 << 12,
317 rightShiftKey = 1 << 13,
318 rightOptionKey = 1 << 14,
319 rightControlKey = 1 << 14,