fix typo
[mcs.git] / class / Managed.Windows.Forms / System.Windows.Forms.CarbonInternal / KeyboardHandler.cs
blobedc2416b9a9639fb87bbeb999211751a8b0dc7b3
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:
8 //
9 // The above copyright notice and this permission notice shall be
10 // included in all copies or substantial portions of the Software.
11 //
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.
22 // Authors:
23 // Geoff Norton (gnorton@novell.com)
26 using System;
27 using System.Collections;
28 using System.Text;
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 internal string ComposedString;
60 static KeyboardHandler () {
61 // our key filter table is a 256 byte array - if the corresponding byte
62 // is set the key should be filtered from WM_CHAR (apple pushes unicode events
63 // for some keys which win32 only handles as KEYDOWN
64 // currently filtered:
65 // fn+f* == 16
66 // left == 28
67 // right == 29
68 // up == 30
69 // down == 31
70 // Please update this list as well as the table as more keys are found
71 key_filter_table = new byte [256] {
72 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
73 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01,
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,
86 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
87 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
90 // our char translation table is a set of translations from mac char codes
91 // to win32 vkey codes
92 // most things map directly
93 char_translation_table = new byte [256] {
94 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
95 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 0x25, 0x27, 0x26, 0x28,
96 32, 49, 34, 51, 52, 53, 55, 222, 57, 48, 56, 187, 188, 189, 190, 191,
97 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 186, 60, 61, 62, 63,
98 50, 65, 66, 67, 68, 187, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79,
99 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 219, 220, 221, 54, 189,
100 192, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79,
101 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 123, 124, 125, 126, 0x2e,
102 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143,
103 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159,
104 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175,
105 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191,
106 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207,
107 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223,
108 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239,
109 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255
111 key_translation_table = new byte [256] {
112 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
113 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
114 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
115 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
116 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79,
117 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95,
118 0x74, 0x75, 0x76, 0x72, 0x77, 0x78, 0x79, 103, 104, 105, 106, 107, 108, 109, 0x7a, 0x7b,
119 112, 113, 114, 115, 116, 117, 0x73, 119, 0x71, 121, 0x70, 123, 124, 125, 126, 127,
120 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143,
121 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159,
122 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175,
123 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191,
124 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207,
125 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223,
126 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239,
127 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255
129 // the key modifier table is a state table of the possible modifier keys
130 // apple currently only goes up to 1 << 14 keys, we've extended this to 32
131 // bytes as thats the size that apple uses
132 key_modifier_table = new byte [32];
135 internal KeyboardHandler (XplatUICarbon driver) : base (driver) {}
137 private void ModifierToVirtualKey (int i, ref MSG msg, bool down) {
138 msg.hwnd = XplatUICarbon.FocusWindow;
140 if (i == 9 || i == 13) {
141 msg.message = (down ? Msg.WM_KEYDOWN : Msg.WM_KEYUP);
142 msg.wParam = (IntPtr) VirtualKeys.VK_SHIFT;
143 msg.lParam = IntPtr.Zero;
144 return;
146 if (i == 12 || i == 14) {
147 msg.message = (down ? Msg.WM_KEYDOWN : Msg.WM_KEYUP);
148 msg.wParam = (IntPtr) VirtualKeys.VK_CONTROL;
149 msg.lParam = IntPtr.Zero;
150 return;
152 if (i == 8) {
153 msg.message = (down ? Msg.WM_SYSKEYDOWN : Msg.WM_SYSKEYUP);
154 msg.wParam = (IntPtr) VirtualKeys.VK_MENU;
155 msg.lParam = new IntPtr (0x20000000);
156 return;
159 return;
162 public void ProcessModifiers (IntPtr eventref, ref MSG msg) {
163 // we get notified when modifiers change, but not specifically what changed
164 UInt32 modifiers = 0;
166 GetEventParameter (eventref, kEventParamKeyModifiers, typeUInt32, IntPtr.Zero, (uint)Marshal.SizeOf (typeof (UInt32)), IntPtr.Zero, ref modifiers);
168 for (int i = 0; i < 32; i++) {
169 if (key_modifier_table [i] == 0x01 && (modifiers & (1 << i)) == 0) {
170 ModifierToVirtualKey (i, ref msg, false);
171 key_modifier_table [i] = 0x00;
172 return;
173 } else if (key_modifier_table [i] == 0x00 && (modifiers & (1 << i)) == (1 << i)) {
174 ModifierToVirtualKey (i, ref msg, true);
175 key_modifier_table [i] = 0x01;
176 return;
180 return;
183 public void ProcessText (IntPtr eventref, ref MSG msg) {
184 UInt32 size = 0;
185 IntPtr buffer = IntPtr.Zero;
186 byte [] bdata;
188 // get the size of the unicode buffer
189 GetEventParameter (eventref, kEventParamTextInputSendText, typeUnicodeText, IntPtr.Zero, 0, ref size, IntPtr.Zero);
191 buffer = Marshal.AllocHGlobal ((int) size);
192 bdata = new byte [size];
194 // get the actual text buffer
195 GetEventParameter (eventref, kEventParamTextInputSendText, typeUnicodeText, IntPtr.Zero, size, IntPtr.Zero, buffer);
197 Marshal.Copy (buffer, bdata, 0, (int) size);
198 Marshal.FreeHGlobal (buffer);
200 if (key_filter_table [bdata [0]] == 0x00) {
201 if (size == 1) {
202 msg.message = Msg.WM_CHAR;
203 msg.wParam = BitConverter.IsLittleEndian ? (IntPtr) bdata [0] : (IntPtr) bdata [size-1];
204 msg.lParam = IntPtr.Zero;
205 msg.hwnd = XplatUICarbon.FocusWindow;
206 } else {
207 msg.message = Msg.WM_IME_COMPOSITION;
208 Encoding enc = BitConverter.IsLittleEndian ? Encoding.Unicode : Encoding.BigEndianUnicode;
209 ComposedString = enc.GetString (bdata);
210 msg.hwnd = XplatUICarbon.FocusWindow;
215 public void ProcessKeyPress (IntPtr eventref, ref MSG msg) {
216 byte charCode = 0x0;
217 byte keyCode = 0x0;
219 GetEventParameter (eventref, kEventParamKeyMacCharCodes, typeChar, IntPtr.Zero, (uint)Marshal.SizeOf (typeof (byte)), IntPtr.Zero, ref charCode);
220 GetEventParameter (eventref, kEventParamKeyCode, typeUInt32, IntPtr.Zero, (uint)Marshal.SizeOf (typeof (byte)), IntPtr.Zero, ref keyCode);
222 msg.lParam = (IntPtr) charCode;
223 msg.wParam = charCode == 0x10 ? (IntPtr) key_translation_table [keyCode] : (IntPtr) char_translation_table [charCode];
224 msg.hwnd = XplatUICarbon.FocusWindow;
227 public bool ProcessEvent (IntPtr callref, IntPtr eventref, IntPtr handle, uint kind, ref MSG msg) {
228 uint klass = EventHandler.GetEventClass (eventref);
229 bool result = true;
231 if (klass == EventHandler.kEventClassTextInput) {
232 switch (kind) {
233 case kEventTextInputUnicodeForKeyEvent:
234 ProcessText (eventref, ref msg);
235 break;
236 default:
237 Console.WriteLine ("WARNING: KeyboardHandler.ProcessEvent default handler for kEventClassTextInput should not be reached");
238 break;
240 } else if (klass == EventHandler.kEventClassKeyboard) {
241 switch (kind) {
242 case kEventRawKeyDown:
243 case kEventRawKeyRepeat:
244 msg.message = Msg.WM_KEYDOWN;
245 ProcessKeyPress (eventref, ref msg);
246 break;
247 case kEventRawKeyUp:
248 msg.message = Msg.WM_KEYUP;
249 ProcessKeyPress (eventref, ref msg);
250 break;
251 case kEventRawKeyModifiersChanged:
252 ProcessModifiers (eventref, ref msg);
253 break;
254 default:
255 Console.WriteLine ("WARNING: KeyboardHandler.ProcessEvent default handler for kEventClassKeyboard should not be reached");
256 break;
258 } else {
259 Console.WriteLine ("WARNING: KeyboardHandler.ProcessEvent default handler for kEventClassTextInput should not be reached");
262 return result;
265 public bool TranslateMessage (ref MSG msg) {
266 bool res = false;
268 if (msg.message >= Msg.WM_KEYFIRST && msg.message <= Msg.WM_KEYLAST)
269 res = true;
271 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)
272 return res;
274 if (key_modifier_table [8] == 0x01 && key_modifier_table [12] == 0x00 && key_modifier_table [14] == 0x00) {
275 if (msg.message == Msg.WM_KEYDOWN) {
276 msg.message = Msg.WM_SYSKEYDOWN;
277 } else if (msg.message == Msg.WM_CHAR) {
278 msg.message = Msg.WM_SYSCHAR;
279 translate_modifier = true;
280 } else if (msg.message == Msg.WM_KEYUP) {
281 msg.message = Msg.WM_SYSKEYUP;
282 } else {
283 return res;
286 msg.lParam = new IntPtr (0x20000000);
287 } else if (msg.message == Msg.WM_SYSKEYUP && translate_modifier && msg.wParam == (IntPtr) 18) {
288 msg.message = Msg.WM_KEYUP;
290 msg.lParam = IntPtr.Zero;
291 translate_modifier = false;
294 return res;
297 internal Keys ModifierKeys {
298 get {
299 Keys keys = Keys.None;
300 if (key_modifier_table [9] == 0x01 || key_modifier_table [13] == 0x01) { keys |= Keys.Shift; }
301 if (key_modifier_table [8] == 0x01) { keys |= Keys.Alt; }
302 if (key_modifier_table [12] == 0x01 || key_modifier_table [14] == 0x01) { keys |= Keys.Control; }
303 return keys;
307 [DllImport ("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")]
308 static extern int GetEventParameter (IntPtr eventref, uint name, uint type, IntPtr outtype, uint size, ref UInt32 outsize, IntPtr data);
309 [DllImport ("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")]
310 static extern int GetEventParameter (IntPtr eventref, uint name, uint type, IntPtr outtype, uint size, IntPtr outsize, IntPtr data);
311 [DllImport ("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")]
312 static extern int GetEventParameter (IntPtr eventref, uint name, uint type, IntPtr outtype, uint size, IntPtr outsize, ref byte data);
313 [DllImport ("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")]
314 static extern int GetEventParameter (IntPtr eventref, uint name, uint type, IntPtr outtype, uint size, IntPtr outsize, ref UInt32 data);
317 internal enum KeyboardModifiers : uint {
318 activeFlag = 1 << 0,
319 btnState = 1 << 7,
320 cmdKey = 1 << 8,
321 shiftKey = 1 << 9,
322 alphaLock = 1 << 10,
323 optionKey = 1 << 11,
324 controlKey = 1 << 12,
325 rightShiftKey = 1 << 13,
326 rightOptionKey = 1 << 14,
327 rightControlKey = 1 << 14,