MouseHandler.cs 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228
  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 <[email protected]>
  24. //
  25. //
  26. using System;
  27. using System.Runtime.InteropServices;
  28. namespace System.Windows.Forms.CarbonInternal {
  29. internal class MouseHandler : EventHandlerBase, IEventHandler {
  30. internal const uint kEventMouseDown = 1;
  31. internal const uint kEventMouseUp = 2;
  32. internal const uint kEventMouseMoved = 5;
  33. internal const uint kEventMouseDragged = 6;
  34. internal const uint kEventMouseEntered = 8;
  35. internal const uint kEventMouseExited = 9;
  36. internal const uint kEventMouseWheelMoved = 10;
  37. internal const uint kEventMouseScroll = 11;
  38. internal const uint kEventParamMouseLocation = 1835822947;
  39. internal const uint kEventParamMouseButton = 1835168878;
  40. internal const uint kEventParamMouseWheelAxis = 1836540280;
  41. internal const uint kEventParamMouseWheelDelta = 1836541036;
  42. internal const uint typeLongInteger = 1819242087;
  43. internal const uint typeMouseWheelAxis = 1836540280;
  44. internal const uint typeMouseButton = 1835168878;
  45. internal const uint typeQDPoint = 1363439732;
  46. internal const uint kEventMouseWheelAxisX = 0;
  47. internal const uint kEventMouseWheelAxisY = 1;
  48. internal const uint DoubleClickInterval = 7500000;
  49. internal static ClickStruct ClickPending;
  50. internal MouseHandler (XplatUICarbon driver) : base (driver) {}
  51. public bool ProcessEvent (IntPtr callref, IntPtr eventref, IntPtr handle, uint kind, ref MSG msg) {
  52. QDPoint qdpoint = new QDPoint ();
  53. CGPoint point = new CGPoint ();
  54. Rect window_bounds = new Rect ();
  55. IntPtr view_handle = IntPtr.Zero;
  56. IntPtr window_handle = IntPtr.Zero;
  57. bool client = true;
  58. ushort button = 0;
  59. Hwnd hwnd;
  60. GetEventParameter (eventref, kEventParamMouseLocation, typeQDPoint, IntPtr.Zero, (uint)Marshal.SizeOf (typeof (QDPoint)), IntPtr.Zero, ref qdpoint);
  61. GetEventParameter (eventref, kEventParamMouseButton, typeMouseButton, IntPtr.Zero, (uint)Marshal.SizeOf (typeof (ushort)), IntPtr.Zero, ref button);
  62. if (button == 1 && ((Driver.ModifierKeys & Keys.Control) != 0))
  63. button = 2;
  64. point.x = qdpoint.x;
  65. point.y = qdpoint.y;
  66. if (FindWindow (qdpoint, ref window_handle) == 5)
  67. return true;
  68. GetWindowBounds (handle, 33, ref window_bounds);
  69. HIViewFindByID (HIViewGetRoot (handle), new HIViewID (EventHandler.kEventClassWindow, 1), ref window_handle);
  70. point.x -= window_bounds.left;
  71. point.y -= window_bounds.top;
  72. HIViewGetSubviewHit (window_handle, ref point, true, ref view_handle);
  73. HIViewConvertPoint (ref point, window_handle, view_handle);
  74. hwnd = Hwnd.ObjectFromHandle (view_handle);
  75. if (hwnd != null)
  76. client = (hwnd.ClientWindow == view_handle ? true : false);
  77. if (XplatUICarbon.Grab.Hwnd != IntPtr.Zero) {
  78. hwnd = Hwnd.ObjectFromHandle (XplatUICarbon.Grab.Hwnd);
  79. client = true;
  80. }
  81. if (hwnd == null)
  82. return true;
  83. if (client) {
  84. qdpoint.x = (short) point.x;
  85. qdpoint.y = (short) point.y;
  86. Driver.ScreenToClient (hwnd.Handle, ref qdpoint);
  87. } else {
  88. point.x = qdpoint.x;
  89. point.y = qdpoint.y;
  90. }
  91. msg.hwnd = hwnd.Handle;
  92. msg.lParam = (IntPtr) ((ushort) point.y << 16 | (ushort) point.x);
  93. switch (kind) {
  94. case kEventMouseDown:
  95. UpdateMouseState (button, true);
  96. msg.message = (client ? Msg.WM_MOUSEMOVE : Msg.WM_NCMOUSEMOVE) + ((button - 1) * 3) + 1;
  97. msg.wParam = Driver.GetMousewParam (0);
  98. if (ClickPending.Pending && (((DateTime.Now.Ticks - ClickPending.Time) < DoubleClickInterval) && (msg.hwnd == ClickPending.Hwnd) && (msg.wParam == ClickPending.wParam) && (msg.lParam == ClickPending.lParam) && (msg.message == ClickPending.Message))) {
  99. msg.message = (client ? Msg.WM_MOUSEMOVE : Msg.WM_NCMOUSEMOVE) + ((button - 1) * 3) + 3;
  100. ClickPending.Pending = false;
  101. } else {
  102. ClickPending.Pending = true;
  103. ClickPending.Hwnd = msg.hwnd;
  104. ClickPending.Message = msg.message;
  105. ClickPending.wParam = msg.wParam;
  106. ClickPending.lParam = msg.lParam;
  107. ClickPending.Time = DateTime.Now.Ticks;
  108. }
  109. break;
  110. case kEventMouseUp:
  111. UpdateMouseState (button, false);
  112. msg.message = (client ? Msg.WM_MOUSEMOVE : Msg.WM_NCMOUSEMOVE) + ((button - 1) * 3) + 2;
  113. msg.wParam = Driver.GetMousewParam (0);
  114. break;
  115. case kEventMouseDragged:
  116. case kEventMouseMoved:
  117. if (XplatUICarbon.Grab.Hwnd == IntPtr.Zero) {
  118. IntPtr ht = IntPtr.Zero;
  119. if (client) {
  120. ht = (IntPtr) HitTest.HTCLIENT;
  121. NativeWindow.WndProc(msg.hwnd, Msg.WM_SETCURSOR, msg.hwnd, (IntPtr)HitTest.HTCLIENT);
  122. } else {
  123. ht = (IntPtr) NativeWindow.WndProc (hwnd.client_window, Msg.WM_NCHITTEST, IntPtr.Zero, msg.lParam).ToInt32 ();
  124. NativeWindow.WndProc(hwnd.client_window, Msg.WM_SETCURSOR, msg.hwnd, ht);
  125. }
  126. }
  127. msg.message = (client ? Msg.WM_MOUSEMOVE : Msg.WM_NCMOUSEMOVE);
  128. msg.wParam = Driver.GetMousewParam (0);
  129. break;
  130. case kEventMouseWheelMoved:
  131. case kEventMouseScroll:
  132. UInt16 axis = 0;
  133. Int32 delta = 0;
  134. GetEventParameter (eventref, kEventParamMouseWheelAxis, typeMouseWheelAxis, IntPtr.Zero, (uint)Marshal.SizeOf (typeof (UInt16)), IntPtr.Zero, ref axis);
  135. GetEventParameter (eventref, kEventParamMouseWheelDelta, typeLongInteger, IntPtr.Zero, (uint)Marshal.SizeOf (typeof (Int32)), IntPtr.Zero, ref delta);
  136. if (axis == kEventMouseWheelAxisY) {
  137. msg.hwnd = XplatUICarbon.FocusWindow;
  138. msg.message = Msg.WM_MOUSEWHEEL;
  139. msg.wParam = Driver.GetMousewParam (delta*40);
  140. return true;
  141. }
  142. break;
  143. default:
  144. return false;
  145. }
  146. Driver.mouse_position.X = (int) point.x;
  147. Driver.mouse_position.Y = (int) point.y;
  148. return true;
  149. }
  150. internal bool TranslateMessage (ref MSG msg) {
  151. if (msg.message == Msg.WM_MOUSEMOVE || msg.message == Msg.WM_NCMOUSEMOVE) {
  152. Hwnd hwnd = Hwnd.ObjectFromHandle (msg.hwnd);
  153. if (XplatUICarbon.MouseHwnd == null) {
  154. Driver.PostMessage (hwnd.Handle, Msg.WM_MOUSE_ENTER, IntPtr.Zero, IntPtr.Zero);
  155. Cursor.SetCursor (hwnd.Cursor);
  156. } else if (XplatUICarbon.MouseHwnd.Handle != hwnd.Handle) {
  157. Driver.PostMessage (XplatUICarbon.MouseHwnd.Handle, Msg.WM_MOUSELEAVE, IntPtr.Zero, IntPtr.Zero);
  158. Driver.PostMessage (hwnd.Handle, Msg.WM_MOUSE_ENTER, IntPtr.Zero, IntPtr.Zero);
  159. Cursor.SetCursor (hwnd.Cursor);
  160. }
  161. XplatUICarbon.MouseHwnd = hwnd;
  162. }
  163. return false;
  164. }
  165. private void UpdateMouseState (int button, bool down) {
  166. switch (button) {
  167. case 1:
  168. if (down) XplatUICarbon.MouseState |= MouseButtons.Left; else XplatUICarbon.MouseState &= ~MouseButtons.Left;
  169. break;
  170. case 2:
  171. if (down) XplatUICarbon.MouseState |= MouseButtons.Right; else XplatUICarbon.MouseState &= ~MouseButtons.Right;
  172. break;
  173. case 3:
  174. if (down) XplatUICarbon.MouseState |= MouseButtons.Middle; else XplatUICarbon.MouseState &= ~MouseButtons.Middle;
  175. break;
  176. }
  177. }
  178. [DllImport ("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")]
  179. static extern int GetEventParameter (IntPtr eventref, uint name, uint type, IntPtr outtype, uint size, IntPtr outsize, ref QDPoint data);
  180. [DllImport ("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")]
  181. static extern int GetEventParameter (IntPtr eventref, uint name, uint type, IntPtr outtype, uint size, IntPtr outsize, ref Int32 data);
  182. [DllImport ("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")]
  183. static extern int GetEventParameter (IntPtr eventref, uint name, uint type, IntPtr outtype, uint size, IntPtr outsize, ref ushort data);
  184. [DllImport("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")]
  185. internal static extern short FindWindow (QDPoint point, ref IntPtr handle);
  186. [DllImport("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")]
  187. internal static extern int GetWindowBounds (IntPtr handle, uint region, ref Rect bounds);
  188. [DllImport("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")]
  189. internal static extern int HIViewConvertPoint (ref CGPoint point, IntPtr source_view, IntPtr target_view);
  190. [DllImport("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")]
  191. internal static extern IntPtr HIViewGetRoot (IntPtr handle);
  192. [DllImport("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")]
  193. internal static extern int HIViewGetSubviewHit (IntPtr content_view, ref CGPoint point, bool tval, ref IntPtr hit_view);
  194. [DllImport("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")]
  195. internal static extern int HIViewFindByID (IntPtr root_window, HIViewID id, ref IntPtr view_handle);
  196. [DllImport("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")]
  197. internal static extern int GetCurrentEventButtonState ();
  198. }
  199. }