2009-06-12 Bill Holmes <billholmes54@gmail.com>
[mono.git] / mcs / class / Managed.Windows.Forms / System.Windows.Forms.CarbonInternal / KeyboardHandler.cs
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.
19 //
20 // Copyright (c) 2007 Novell, Inc.
21 //
22 // Authors:
23 //  Geoff Norton (gnorton@novell.com)
24 //
25 //
26 using System;
27 using System.Collections;
28 using System.Text;
29 using System.Globalization;
30 using System.Runtime.InteropServices;
31
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;
40
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;
46
47                 internal const uint typeChar = 1413830740;
48                 internal const uint typeUInt32 = 1835100014;
49                 internal const uint typeUnicodeText = 1970567284;
50
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;
55
56                 internal static bool translate_modifier = false;
57
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:
63                         //      fn+f* == 16
64                         //      left == 28
65                         //      right == 29
66                         //      up == 30
67                         //      down == 31
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
86                                                         };
87
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
108                                                         };
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 
126                                                         };
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];
131                 }
132
133                 internal KeyboardHandler (XplatUICarbon driver) : base (driver) {}
134
135                 private void ModifierToVirtualKey (int i, ref MSG msg, bool down) {
136                         msg.hwnd = XplatUICarbon.FocusWindow;
137
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;
142                                 return;
143                         }
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;
148                                 return;
149                         }
150                         if (i == 8) {
151                                 msg.message = (down ? Msg.WM_SYSKEYDOWN : Msg.WM_SYSKEYUP);
152                                 msg.wParam = (IntPtr) VirtualKeys.VK_MENU;
153                                 msg.lParam = new IntPtr (0x20000000);
154                                 return;
155                         }
156                         
157                         return;
158                 }
159
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;
163
164                         GetEventParameter (eventref, kEventParamKeyModifiers, typeUInt32, IntPtr.Zero, (uint)Marshal.SizeOf (typeof (UInt32)), IntPtr.Zero, ref modifiers);
165
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;
170                                         return;
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;
174                                         return;
175                                 }
176                         }
177
178                         return;
179                 }
180
181                 public void ProcessText (IntPtr eventref, ref MSG msg) {
182                         UInt32 size = 0;
183                         IntPtr buffer = IntPtr.Zero;
184                         byte [] bdata;
185
186                         // get the size of the unicode buffer
187                         GetEventParameter (eventref, kEventParamTextInputSendText, typeUnicodeText, IntPtr.Zero, 0, ref size, IntPtr.Zero);
188
189                         buffer = Marshal.AllocHGlobal ((int) size);
190                         bdata = new byte [size];
191
192                         // get the actual text buffer
193                         GetEventParameter (eventref, kEventParamTextInputSendText, typeUnicodeText, IntPtr.Zero, size, IntPtr.Zero, buffer);
194
195                         Marshal.Copy (buffer, bdata, 0, (int) size);
196                         Marshal.FreeHGlobal (buffer);
197
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;
204                         }
205                 }
206
207                 public void ProcessKeyPress (IntPtr eventref, ref MSG msg) {
208                         byte charCode = 0x0;
209                         byte keyCode = 0x0;
210
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);
213
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;
217                 }
218
219                 public bool ProcessEvent (IntPtr callref, IntPtr eventref, IntPtr handle, uint kind, ref MSG msg) {
220                         uint klass = EventHandler.GetEventClass (eventref);
221                         bool result = true;
222
223                         if (klass == EventHandler.kEventClassTextInput) {
224                                 switch (kind) {
225                                         case kEventTextInputUnicodeForKeyEvent:
226                                                 ProcessText (eventref, ref msg);
227                                                 break;
228                                         default:
229                                                 Console.WriteLine ("WARNING: KeyboardHandler.ProcessEvent default handler for kEventClassTextInput should not be reached");
230                                                 break;
231                                 }
232                         } else if (klass == EventHandler.kEventClassKeyboard) {
233                                 switch (kind) {
234                                         case kEventRawKeyDown:
235                                         case kEventRawKeyRepeat:
236                                                 msg.message = Msg.WM_KEYDOWN;
237                                                 ProcessKeyPress (eventref, ref msg);
238                                                 break;
239                                         case kEventRawKeyUp:
240                                                 msg.message = Msg.WM_KEYUP;
241                                                 ProcessKeyPress (eventref, ref msg);
242                                                 break;
243                                         case kEventRawKeyModifiersChanged:
244                                                 ProcessModifiers (eventref, ref msg);
245                                                 break;
246                                         default:
247                                                 Console.WriteLine ("WARNING: KeyboardHandler.ProcessEvent default handler for kEventClassKeyboard should not be reached");
248                                                 break;
249                                 }
250                         } else {
251                                 Console.WriteLine ("WARNING: KeyboardHandler.ProcessEvent default handler for kEventClassTextInput should not be reached");
252                         }
253
254                         return result;
255                 }
256
257                 public bool TranslateMessage (ref MSG msg) {
258                         bool res = false;
259  
260                         if (msg.message >= Msg.WM_KEYFIRST && msg.message <= Msg.WM_KEYLAST)
261                                 res = true;
262                         
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) 
264                                 return res;
265
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;
274                                 } else {
275                                         return res;
276                                 }
277
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;
281                                 
282                                 msg.lParam = IntPtr.Zero;
283                                 translate_modifier = false;
284                         }
285
286                         return res;
287                 }
288
289                 internal Keys ModifierKeys {
290                         get {
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; }
295                                 return keys;
296                         }
297                 }
298
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);
307         }
308
309         internal enum KeyboardModifiers : uint {
310                 activeFlag = 1 << 0,
311                 btnState = 1 << 7,
312                 cmdKey = 1 << 8,
313                 shiftKey = 1 << 9,
314                 alphaLock = 1 << 10,
315                 optionKey = 1 << 11,
316                 controlKey = 1 << 12,
317                 rightShiftKey = 1 << 13,
318                 rightOptionKey = 1 << 14,
319                 rightControlKey = 1 << 14,
320         }
321 }