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 {
86                                 vkey = -1;
87                                 return false;
88                         }
89                         return true;
90                 }
91
92                 private bool CharCodeToVirtualKeys (byte charCode, out int vkey) {
93                         vkey = (int) charCode;
94                         switch (vkey) {
95                                 case 28:
96                                         vkey = (int) VirtualKeys.VK_LEFT;
97                                         break;
98                                 case 29:
99                                         vkey = (int) VirtualKeys.VK_RIGHT;
100                                         break;
101                                 case 30:
102                                         vkey = (int) VirtualKeys.VK_UP;
103                                         break;
104                                 case 31:
105                                         vkey = (int) VirtualKeys.VK_DOWN;
106                                         break;
107                         }       
108                         
109                         return true;
110                 }
111
112
113                 public bool ProcessEvent (IntPtr callref, IntPtr eventref, IntPtr handle, uint kind, ref MSG msg) {
114                         int vkey = -1;
115                         bool result = true;
116                         byte charCode = 0x0;
117                         UInt32 new_modifiers = 0;
118
119                         GetEventParameter (eventref, kEventParamKeyMacCharCodes, typeChar, IntPtr.Zero, (uint)Marshal.SizeOf (typeof (byte)), IntPtr.Zero, ref charCode);
120                         GetEventParameter (eventref, kEventParamKeyModifiers, typeUInt32, IntPtr.Zero, (uint)Marshal.SizeOf (typeof (UInt32)), IntPtr.Zero, ref new_modifiers);
121
122                         switch (kind) {
123                                 case kEventRawKeyDown:
124                                 case kEventRawKeyRepeat:
125                                         msg.message = Msg.WM_KEYDOWN;
126                                         result = CharCodeToVirtualKeys (charCode, out vkey);
127                                         break;
128                                 case kEventRawKeyUp: 
129                                         msg.message = Msg.WM_KEYUP;
130                                         result = CharCodeToVirtualKeys (charCode, out vkey);
131                                         break;
132                                 case kEventRawKeyModifiersChanged: 
133                                         result = ModifiersToVirtualKeys (new_modifiers, ref msg, out vkey);
134                                         modifiers = new_modifiers;
135                                         break;
136                         }
137                         msg.wParam = (IntPtr) vkey;
138
139                         if (result) {
140                                 msg.hwnd = XplatUICarbon.FocusWindow;
141                         }
142                         
143                         return result;
144                 }
145                 
146                 internal bool TranslateMessage (ref MSG msg)
147                 {
148                         bool res = false;
149
150                         if (msg.message >= Msg.WM_KEYFIRST && msg.message <= Msg.WM_KEYLAST)
151                                 res = true;
152
153                         if (msg.message != Msg.WM_KEYDOWN && msg.message != Msg.WM_SYSKEYDOWN)
154                                 return res;
155
156                         Msg message = (msg.message == Msg.WM_KEYDOWN ? Msg.WM_CHAR : Msg.WM_SYSCHAR);
157                         XplatUI.PostMessage (msg.hwnd, message, msg.wParam, msg.lParam);
158                         
159                         return res;
160                 }
161
162                 internal Keys ModifierKeys {
163                         get {
164                                 return keys;
165                         }
166                 }
167
168                 [DllImport ("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")]
169                 static extern int GetEventParameter (IntPtr eventref, uint name, uint type, IntPtr outtype, uint size, IntPtr outsize, ref byte data);
170                 [DllImport ("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")]
171                 static extern int GetEventParameter (IntPtr eventref, uint name, uint type, IntPtr outtype, uint size, IntPtr outsize, ref UInt32 data);
172         }
173
174         internal enum KeyboardModifiers : uint {
175                 activeFlag = 1 << 0,
176                 btnState = 1 << 7,
177                 cmdKey = 1 << 8,
178                 shiftKey = 1 << 9,
179                 alphaLock = 1 << 10,
180                 optionKey = 1 << 11,
181                 controlKey = 1 << 12,
182                 rightShiftKey = 1 << 13,
183                 rightOptionKey = 1 << 14,
184                 rightControlKey = 1 << 14,
185         }
186 }