In .:
[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 kEventParamKeyModifiers = 1802334052;
43
44                 internal const uint typeChar = 1413830740;
45                 internal const uint typeUInt32 = 1835100014;
46
47                 UInt32 modifiers = 0;
48                 Keys keys = Keys.None;
49
50                 internal KeyboardHandler (XplatUICarbon driver) : base (driver) {}
51
52                 private bool ModifiersToVirtualKeys (UInt32 new_modifiers, ref MSG msg, out int vkey) {
53                         // TODO: X11 appears to only generate VK_SHIFT rather than VK_LSHIFT/VK_RSHIFT
54                         if ((new_modifiers & (uint)KeyboardModifiers.shiftKey) == (uint)KeyboardModifiers.shiftKey && ((modifiers & (uint)KeyboardModifiers.shiftKey) == 0)) {
55                                 msg.message = Msg.WM_KEYDOWN;
56                                 vkey = (int) VirtualKeys.VK_SHIFT;
57                                 keys |= Keys.Shift;
58                         } else if ((new_modifiers & (uint)KeyboardModifiers.shiftKey) == 0 && ((modifiers & (uint)KeyboardModifiers.shiftKey) == (uint)KeyboardModifiers.shiftKey)) {
59                                 msg.message = Msg.WM_KEYUP;
60                                 vkey = (int) VirtualKeys.VK_SHIFT;
61                                 keys &= ~Keys.Shift;
62                         } else if ((new_modifiers & (uint)KeyboardModifiers.rightShiftKey) == (uint)KeyboardModifiers.rightShiftKey && ((modifiers & (uint)KeyboardModifiers.rightShiftKey) == 0)) {
63                                 msg.message = Msg.WM_KEYDOWN;
64                                 vkey = (int) VirtualKeys.VK_SHIFT;
65                                 keys |= Keys.Shift;
66                         } else if ((new_modifiers & (uint)KeyboardModifiers.rightShiftKey) == 0 && ((modifiers & (uint)KeyboardModifiers.rightShiftKey) == (uint)KeyboardModifiers.rightShiftKey)) {
67                                 msg.message = Msg.WM_KEYUP;
68                                 vkey = (int) VirtualKeys.VK_SHIFT;
69                                 keys &= ~Keys.Shift;
70                         } else if ((new_modifiers & (uint)KeyboardModifiers.cmdKey) == (uint)KeyboardModifiers.cmdKey && ((modifiers & (uint)KeyboardModifiers.cmdKey) == 0)) {
71                                 msg.message = Msg.WM_KEYDOWN;
72                                 vkey = (int) VirtualKeys.VK_LWIN;
73                         } else if ((new_modifiers & (uint)KeyboardModifiers.cmdKey) == 0 && ((modifiers & (uint)KeyboardModifiers.cmdKey) == (uint)KeyboardModifiers.cmdKey)) {
74                                 msg.message = Msg.WM_KEYUP;
75                                 vkey = (int) VirtualKeys.VK_LWIN;
76                         } else if ((new_modifiers & (uint)KeyboardModifiers.optionKey) == (uint)KeyboardModifiers.optionKey && ((modifiers & (uint)KeyboardModifiers.optionKey) == 0)) {
77                                 msg.message = Msg.WM_SYSKEYDOWN;
78                                 msg.lParam = new IntPtr (0x20000000);
79                                 vkey = (int) VirtualKeys.VK_MENU;
80                                 keys |= Keys.Alt;
81                         } else if ((new_modifiers & (uint)KeyboardModifiers.optionKey) == 0 && ((modifiers & (uint)KeyboardModifiers.optionKey) == (uint)KeyboardModifiers.optionKey)) {
82                                 msg.message = Msg.WM_SYSKEYUP;
83                                 vkey = (int) VirtualKeys.VK_MENU;
84                                 keys &= ~Keys.Alt;
85                         } else if ((new_modifiers & (uint)KeyboardModifiers.controlKey) == (uint)KeyboardModifiers.controlKey && ((modifiers & (uint)KeyboardModifiers.controlKey) == 0)) {
86                                 msg.message = Msg.WM_KEYDOWN;
87                                 vkey = (int) VirtualKeys.VK_CONTROL;
88                                 keys |= Keys.Control;
89                         } else if ((new_modifiers & (uint)KeyboardModifiers.controlKey) == 0 && ((modifiers & (uint)KeyboardModifiers.controlKey) == (uint)KeyboardModifiers.controlKey)) {
90                                 msg.message = Msg.WM_KEYUP;
91                                 vkey = (int) VirtualKeys.VK_CONTROL;
92                                 keys &= ~Keys.Control;
93                         } else if ((new_modifiers & (uint)KeyboardModifiers.rightControlKey) == (uint)KeyboardModifiers.rightControlKey && ((modifiers & (uint)KeyboardModifiers.rightControlKey) == 0)) {
94                                 msg.message = Msg.WM_KEYDOWN;
95                                 vkey = (int) VirtualKeys.VK_CONTROL;
96                                 keys |= Keys.Control;
97                         } else if ((new_modifiers & (uint)KeyboardModifiers.rightControlKey) == 0 && ((modifiers & (uint)KeyboardModifiers.rightControlKey) == (uint)KeyboardModifiers.rightControlKey)) {
98                                 msg.message = Msg.WM_KEYUP;
99                                 vkey = (int) VirtualKeys.VK_CONTROL;
100                                 keys &= ~Keys.Control;
101                         } else {
102                                 vkey = -1;
103                                 return false;
104                         }
105                         return true;
106                 }
107
108                 private bool CharCodeToVirtualKeys (byte charCode, out int vkey) {
109                         vkey = (int) charCode;
110                         switch (vkey) {
111                                 case 28:
112                                         vkey = (int) VirtualKeys.VK_LEFT;
113                                         break;
114                                 case 29:
115                                         vkey = (int) VirtualKeys.VK_RIGHT;
116                                         break;
117                                 case 30:
118                                         vkey = (int) VirtualKeys.VK_UP;
119                                         break;
120                                 case 31:
121                                         vkey = (int) VirtualKeys.VK_DOWN;
122                                         break;
123                         }       
124                         
125                         return true;
126                 }
127
128
129                 public bool ProcessEvent (IntPtr callref, IntPtr eventref, IntPtr handle, uint kind, ref MSG msg) {
130                         int vkey = -1;
131                         bool result = true;
132                         byte charCode = 0x0;
133                         UInt32 new_modifiers = 0;
134
135                         GetEventParameter (eventref, kEventParamKeyMacCharCodes, typeChar, IntPtr.Zero, (uint)Marshal.SizeOf (typeof (byte)), IntPtr.Zero, ref charCode);
136                         GetEventParameter (eventref, kEventParamKeyModifiers, typeUInt32, IntPtr.Zero, (uint)Marshal.SizeOf (typeof (UInt32)), IntPtr.Zero, ref new_modifiers);
137
138                         switch (kind) {
139                                 case kEventRawKeyDown:
140                                 case kEventRawKeyRepeat:
141                                         msg.message = Msg.WM_KEYDOWN;
142                                         result = CharCodeToVirtualKeys (charCode, out vkey);
143                                         break;
144                                 case kEventRawKeyUp: 
145                                         msg.message = Msg.WM_KEYUP;
146                                         result = CharCodeToVirtualKeys (charCode, out vkey);
147                                         break;
148                                 case kEventRawKeyModifiersChanged: 
149                                         result = ModifiersToVirtualKeys (new_modifiers, ref msg, out vkey);
150                                         modifiers = new_modifiers;
151                                         break;
152                         }
153                         msg.wParam = (IntPtr) vkey;
154
155                         if (result) {
156                                 msg.hwnd = XplatUICarbon.FocusWindow;
157                         }
158                         
159                         return result;
160                 }
161                 
162                 internal bool TranslateMessage (ref MSG msg)
163                 {
164                         bool res = false;
165
166                         if (msg.message >= Msg.WM_KEYFIRST && msg.message <= Msg.WM_KEYLAST)
167                                 res = true;
168
169                         if (msg.message != Msg.WM_KEYDOWN && msg.message != Msg.WM_SYSKEYDOWN)
170                                 return res;
171
172                         Msg message = (msg.message == Msg.WM_KEYDOWN ? Msg.WM_CHAR : Msg.WM_SYSCHAR);
173                         XplatUI.PostMessage (msg.hwnd, message, msg.wParam, msg.lParam);
174                         
175                         return res;
176                 }
177
178                 internal Keys ModifierKeys {
179                         get {
180                                 return keys;
181                         }
182                 }
183
184                 [DllImport ("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")]
185                 static extern int GetEventParameter (IntPtr eventref, uint name, uint type, IntPtr outtype, uint size, IntPtr outsize, ref byte data);
186                 [DllImport ("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")]
187                 static extern int GetEventParameter (IntPtr eventref, uint name, uint type, IntPtr outtype, uint size, IntPtr outsize, ref UInt32 data);
188         }
189
190         internal enum KeyboardModifiers : uint {
191                 activeFlag = 1 << 0,
192                 btnState = 1 << 7,
193                 cmdKey = 1 << 8,
194                 shiftKey = 1 << 9,
195                 alphaLock = 1 << 10,
196                 optionKey = 1 << 11,
197                 controlKey = 1 << 12,
198                 rightShiftKey = 1 << 13,
199                 rightOptionKey = 1 << 14,
200                 rightControlKey = 1 << 14,
201         }
202 }