From 574909c426b1be64f83dadaac12bbbd8694ebc24 Mon Sep 17 00:00:00 2001 From: the_fiddler Date: Thu, 4 Nov 2010 17:57:09 +0000 Subject: [PATCH] * X11KeyMap.cs: Added AltGr keycode. * X11Mouse.cs: Use XQueryPointer instead of trying to hook events. * X11Keyboard.cs: Improved handling of key modifiers. * X11Factory.cs: Use new X11Mouse API. * Functions.cs: Added XButtonGrab/XButtonUngrab. * API.cs: Added missing XF86 keysyms. --- Source/OpenTK/Platform/X11/API.cs | 75 +++++++++++++ Source/OpenTK/Platform/X11/Functions.cs | 14 ++- Source/OpenTK/Platform/X11/X11Factory.cs | 2 +- Source/OpenTK/Platform/X11/X11KeyMap.cs | 1 + Source/OpenTK/Platform/X11/X11Keyboard.cs | 46 ++++++-- Source/OpenTK/Platform/X11/X11Mouse.cs | 128 +++++----------------- 6 files changed, 154 insertions(+), 112 deletions(-) diff --git a/Source/OpenTK/Platform/X11/API.cs b/Source/OpenTK/Platform/X11/API.cs index 1f970123..43581b2b 100644 --- a/Source/OpenTK/Platform/X11/API.cs +++ b/Source/OpenTK/Platform/X11/API.cs @@ -1142,6 +1142,8 @@ XF86VidModeGetGammaRampSize( Hyper_L = 0xffed, /* Left hyper */ Hyper_R = 0xffee, /* Right hyper */ + ISO_Level3_Shift = 0xfe03, + /* * Latin 1 * (ISO/IEC 8859-1 = Unicode U+0020..U+00FF) @@ -1245,6 +1247,79 @@ XF86VidModeGetGammaRampSize( bar = 0x007c, /* U+007C VERTICAL LINE */ braceright = 0x007d, /* U+007D RIGHT CURLY BRACKET */ asciitilde = 0x007e, /* U+007E TILDE */ + + // Extra keys + + XF86AudioMute = 0x1008ff12, + XF86AudioLowerVolume = 0x1008ff11, + XF86AudioRaiseVolume = 0x1008ff13, + XF86PowerOff = 0x1008ff2a, + XF86Suspend = 0x1008ffa7, + XF86Copy = 0x1008ff57, + XF86Paste = 0x1008ff6d, + XF86Cut = 0x1008ff58, + XF86MenuKB = 0x1008ff65, + XF86Calculator = 0x1008ff1d, + XF86Sleep = 0x1008ff2f, + XF86WakeUp = 0x1008ff2b , + XF86Explorer = 0x1008ff5d, + XF86Send = 0x1008ff7b, + XF86Xfer = 0x1008ff8a, + XF86Launch1 = 0x1008ff41, + XF86Launch2 = 0x1008ff42, + XF86Launch3 = 0x1008ff43, + XF86Launch4 = 0x1008ff44, + XF86Launch5 = 0x1008ff45, + XF86LaunchA = 0x1008ff4a, + XF86LaunchB = 0x1008ff4b, + XF86WWW = 0x1008ff2e, + XF86DOS = 0x1008ff5a, + XF86ScreenSaver = 0x1008ff2d, + XF86RotateWindows = 0x1008ff74, + XF86Mail = 0x1008ff19, + XF86Favorites = 0x1008ff30, + XF86MyComputer = 0x1008ff33, + XF86Back = 0x1008ff26, + XF86Forward = 0x1008ff27 , + XF86Eject = 0x1008ff2c, + XF86AudioPlay = 0x1008ff14, + XF86AudioStop = 0x1008ff15, + XF86AudioPrev = 0x1008ff16, + XF86AudioNext = 0x1008ff17, + XF86AudioRecord = 0x1008ff1c, + XF86AudioPause =0x1008ff31, + XF86AudioRewind = 0x1008ff3e, + XF86AudioForward = 0x1008ff97, + XF86Phone = 0x1008ff6e, + XF86Tools = 0x1008ff81, + XF86HomePage = 0x1008ff18, + XF86Close = 0x1008ff56, + XF86Reload = 0x1008ff73, + XF86ScrollUp = 0x1008ff78, + XF86ScrollDown = 0x1008ff79, + XF86New = 0x1008ff68, + XF86TouchpadToggle = 0x1008ffa9, + XF86WebCam = 0x1008ff8f, + XF86Search = 0x1008ff1b, + XF86Finance = 0x1008ff3c, + XF86Shop = 0x1008ff36, + XF86MonBrightnessDown = 0x1008ff03, + XF86MonBrightnessUp = 0x1008ff02, + XF86AudioMedia = 0x1008ff32, + XF86Display = 0x1008ff59, + XF86KbdLightOnOff = 0x1008ff04, + XF86KbdBrightnessDown = 0x1008ff06, + XF86KbdBrightnessUp = 0x1008ff05, + XF86Reply = 0x1008ff72, + XF86MailForward = 0x1008ff90, + XF86Save = 0x1008ff77, + XF86Documents = 0x1008ff5b, + XF86Battery = 0x1008ff93, + XF86Bluetooth = 0x1008ff94, + XF86WLAN = 0x1008ff95, + + SunProps = 0x1005ff70, + SunOpen = 0x1005ff73, } #endregion diff --git a/Source/OpenTK/Platform/X11/Functions.cs b/Source/OpenTK/Platform/X11/Functions.cs index b2bf4947..69e1e362 100644 --- a/Source/OpenTK/Platform/X11/Functions.cs +++ b/Source/OpenTK/Platform/X11/Functions.cs @@ -108,8 +108,9 @@ namespace OpenTK.Platform.X11 public extern static int XConnectionNumber(IntPtr diplay); [DllImport("libX11")] public extern static int XPending(IntPtr diplay); + [DllImport("libX11", EntryPoint = "XSelectInput")] - public extern static IntPtr XSelectInput(IntPtr display, IntPtr window, IntPtr mask); + public extern static int XSelectInput(IntPtr display, IntPtr window, IntPtr mask); [DllImport("libX11", EntryPoint = "XDestroyWindow")] public extern static int XDestroyWindow(IntPtr display, IntPtr window); @@ -179,6 +180,17 @@ namespace OpenTK.Platform.X11 [DllImport("libX11", EntryPoint = "XUngrabPointer")] public extern static int XUngrabPointer(IntPtr display, IntPtr timestamp); + [DllImport("libX11", EntryPoint = "XGrabButton")] + public extern static int XGrabButton(IntPtr display, + int button, uint modifiers, Window grab_window, + Bool owner_events, EventMask event_mask, + GrabMode pointer_mode, GrabMode keyboard_mode, + Window confine_to, Cursor cursor); + + [DllImport("libX11", EntryPoint = "XUngrabButton")] + public extern static int XUngrabButton(IntPtr display, uint button, uint + modifiers, Window grab_window); + [DllImport("libX11", EntryPoint = "XQueryPointer")] public extern static bool XQueryPointer(IntPtr display, IntPtr window, out IntPtr root, out IntPtr child, out int root_x, out int root_y, out int win_x, out int win_y, out int keys_buttons); diff --git a/Source/OpenTK/Platform/X11/X11Factory.cs b/Source/OpenTK/Platform/X11/X11Factory.cs index f2459183..c3292637 100644 --- a/Source/OpenTK/Platform/X11/X11Factory.cs +++ b/Source/OpenTK/Platform/X11/X11Factory.cs @@ -88,7 +88,7 @@ namespace OpenTK.Platform.X11 //if (XI2Mouse.IsSupported(IntPtr.Zero)) // return new XI2Mouse(null); // Requires xorg 1.7 or higher. //else - return new X11Mouse(null); // Always supported. + return new X11Mouse(); // Always supported. } #endregion diff --git a/Source/OpenTK/Platform/X11/X11KeyMap.cs b/Source/OpenTK/Platform/X11/X11KeyMap.cs index 9fba864c..0e2c7e80 100644 --- a/Source/OpenTK/Platform/X11/X11KeyMap.cs +++ b/Source/OpenTK/Platform/X11/X11KeyMap.cs @@ -36,6 +36,7 @@ namespace OpenTK.Platform.X11 this.Add(XKey.Super_R, Key.WinRight); this.Add(XKey.Meta_L, Key.WinLeft); this.Add(XKey.Meta_R, Key.WinRight); + this.Add(XKey.ISO_Level3_Shift, Key.AltRight); // Normally AltGr this.Add(XKey.Menu, Key.Menu); this.Add(XKey.Tab, Key.Tab); diff --git a/Source/OpenTK/Platform/X11/X11Keyboard.cs b/Source/OpenTK/Platform/X11/X11Keyboard.cs index 81534264..ef1f0a0b 100644 --- a/Source/OpenTK/Platform/X11/X11Keyboard.cs +++ b/Source/OpenTK/Platform/X11/X11Keyboard.cs @@ -38,12 +38,36 @@ namespace OpenTK.Platform.X11 { readonly static X11KeyMap keymap = new X11KeyMap(); readonly static string name = "Core X11 keyboard"; - KeyboardState state = new KeyboardState(); readonly byte[] keys = new byte[32]; + readonly int KeysymsPerKeycode; + KeyboardState state = new KeyboardState(); public X11Keyboard() { Debug.WriteLine("Using X11Keyboard."); + state.IsConnected = true; + + IntPtr display = API.DefaultDisplay; + using (new XLock(display)) + { + // Find the number of keysyms per keycode. + int first = 0, last = 0; + API.DisplayKeycodes(display, ref first, ref last); + IntPtr keysym_ptr = API.GetKeyboardMapping(display, (byte)first, last - first + 1, + ref KeysymsPerKeycode); + Functions.XFree(keysym_ptr); + + try + { + // Request that auto-repeat is only set on devices that support it physically. + // This typically means that it's turned off for keyboards what we want). + // We prefer this method over XAutoRepeatOff/On, because the latter needs to + // be reset before the program exits. + bool supported; + Functions.XkbSetDetectableAutoRepeat(display, true, out supported); + } + catch { } + } } public KeyboardState GetState() @@ -78,18 +102,20 @@ namespace OpenTK.Platform.X11 Functions.XQueryKeymap(display, keys); for (int keycode = 8; keycode < 256; keycode++) { - IntPtr keysym = Functions.XKeycodeToKeysym(display, (byte)keycode, 0); - IntPtr keysym2 = Functions.XKeycodeToKeysym(display, (byte)keycode, 1); bool pressed = (keys[keycode >> 3] >> (keycode & 0x07) & 0x01) != 0; - Key key; - if (keymap.TryGetValue((XKey)keysym, out key) || - keymap.TryGetValue((XKey)keysym2, out key)) + + for (int mod = 0; mod < KeysymsPerKeycode; mod++) { - if (pressed) - state.EnableBit((int)key); - else - state.DisableBit((int)key); + IntPtr keysym = Functions.XKeycodeToKeysym(display, (byte)keycode, mod); + if (keysym != IntPtr.Zero && keymap.TryGetValue((XKey)keysym, out key)) + { + if (pressed) + state.EnableBit((int)key); + else + state.DisableBit((int)key); + break; + } } } } diff --git a/Source/OpenTK/Platform/X11/X11Mouse.cs b/Source/OpenTK/Platform/X11/X11Mouse.cs index 881c488e..9dd523c6 100644 --- a/Source/OpenTK/Platform/X11/X11Mouse.cs +++ b/Source/OpenTK/Platform/X11/X11Mouse.cs @@ -34,41 +34,17 @@ namespace OpenTK.Platform.X11 { sealed class X11Mouse : IMouseDriver2 { + readonly IntPtr display; MouseState mouse = new MouseState(); - X11WindowInfo window; - // Can either attach itself to the specified window or can hook the root window. - public X11Mouse(X11WindowInfo win) + // Can either attach itself to the specified window or can hook the root window. + public X11Mouse() { - if (win != null) - { - window = win; - } - else - { - using (new XLock(API.DefaultDisplay)) - { - window = new X11WindowInfo(); - window.Display = API.DefaultDisplay; - window.Screen = Functions.XDefaultScreen(window.Display); - window.RootWindow = Functions.XRootWindow(window.Display, window.Screen); - window.WindowHandle = window.RootWindow; - window.EventMask = EventMask.ButtonMotionMask | - EventMask.ButtonPressMask | EventMask.ButtonReleaseMask; - - //Functions.XGrabPointer(window.Display, window.RootWindow, true, - // window.EventMask, GrabMode.GrabModeAsync, GrabMode.GrabModeAsync, IntPtr.Zero, - // IntPtr.Zero, IntPtr.Zero); - //Functions.XSelectInput(window.Display, window.RootWindow, new IntPtr((int)window.EventMask)); - } - - Debug.WriteLine("Using X11Mouse."); - } + Debug.WriteLine("Using X11Mouse."); + mouse.IsConnected = true; + display = API.DefaultDisplay; } - // Todo: remove this - public IList Mouse { get { throw new NotSupportedException(); } } - public MouseState GetState() { ProcessEvents(); @@ -98,77 +74,29 @@ namespace OpenTK.Platform.X11 IntPtr root, child; int root_x, root_y, win_x, win_y; int buttons; - Functions.XQueryPointer(window.Display, window.WindowHandle, out root, out child, - out root_x, out root_y, out win_x, out win_y, out buttons); - mouse.X = root_x; - mouse.Y = root_y; - WriteBit(MouseButton.Left, buttons & (int)MouseMask.Button1Mask); - WriteBit(MouseButton.Middle, buttons & (int)MouseMask.Button2Mask); - WriteBit(MouseButton.Right, buttons & (int)MouseMask.Button3Mask); - if ((buttons & (int)MouseMask.Button4Mask) != 0) - mouse.WheelPrecise++; - if ((buttons & (int)MouseMask.Button5Mask) != 0) - mouse.WheelPrecise--; - WriteBit(MouseButton.Button1, buttons & (int)MouseMask.Button6Mask); - WriteBit(MouseButton.Button2, buttons & (int)MouseMask.Button7Mask); - WriteBit(MouseButton.Button3, buttons & (int)MouseMask.Button8Mask); -// XEvent e = new XEvent(); -// -// while (true) -// { -// using (new XLock(window.Display)) -// { -// if (!Functions.XCheckWindowEvent(window.Display, window.WindowHandle, window.EventMask, ref e)) -// break; -// -// switch (e.type) -// { -// case XEventName.ButtonPress: -// switch (e.ButtonEvent.button) -// { -// case 1: mouse.EnableBit((int)MouseButton.Left); break; -// case 2: mouse.EnableBit((int)MouseButton.Middle); break; -// case 3: mouse.EnableBit((int)MouseButton.Right); break; -// case 4: mouse.WheelPrecise++; break; -// case 5: mouse.WheelPrecise--; break; -// case 6: mouse.EnableBit((int)MouseButton.Button1); break; -// case 7: mouse.EnableBit((int)MouseButton.Button2); break; -// case 8: mouse.EnableBit((int)MouseButton.Button3); break; -// case 9: mouse.EnableBit((int)MouseButton.Button4); break; -// case 10: mouse.EnableBit((int)MouseButton.Button5); break; -// case 11: mouse.EnableBit((int)MouseButton.Button6); break; -// case 12: mouse.EnableBit((int)MouseButton.Button7); break; -// case 13: mouse.EnableBit((int)MouseButton.Button8); break; -// case 15: mouse.EnableBit((int)MouseButton.Button9); break; -// } -// break; -// -// case XEventName.ButtonRelease: -// switch (e.ButtonEvent.button) -// { -// case 1: mouse.DisableBit((int)MouseButton.Left); break; -// case 2: mouse.DisableBit((int)MouseButton.Middle); break; -// case 3: mouse.DisableBit((int)MouseButton.Right); break; -// case 6: mouse.DisableBit((int)MouseButton.Button1); break; -// case 7: mouse.DisableBit((int)MouseButton.Button2); break; -// case 8: mouse.DisableBit((int)MouseButton.Button3); break; -// case 9: mouse.DisableBit((int)MouseButton.Button4); break; -// case 10: mouse.DisableBit((int)MouseButton.Button5); break; -// case 11: mouse.DisableBit((int)MouseButton.Button6); break; -// case 12: mouse.DisableBit((int)MouseButton.Button7); break; -// case 13: mouse.DisableBit((int)MouseButton.Button8); break; -// case 15: mouse.DisableBit((int)MouseButton.Button9); break; -// } -// break; -// -// case XEventName.MotionNotify: -// mouse.X = e.MotionEvent.x; -// mouse.Y = e.MotionEvent.y; -// break; -// } -// } -// } + using (new XLock(display)) + { + IntPtr window = Functions.XRootWindow(display, Functions.XDefaultScreen(display)); + Functions.XQueryPointer(display, window, out root, out child, + out root_x, out root_y, out win_x, out win_y, out buttons); + + mouse.X = root_x; + mouse.Y = root_y; + WriteBit(MouseButton.Left, buttons & (int)MouseMask.Button1Mask); + WriteBit(MouseButton.Middle, buttons & (int)MouseMask.Button2Mask); + WriteBit(MouseButton.Right, buttons & (int)MouseMask.Button3Mask); + // Note: this will never work right. After spending a week on this, I simply don't care + // anymore. If someone can fix it, please do. + // Note 2: I have tried passively grabbing those buttons - no go (BadAccess). + if ((buttons & (int)MouseMask.Button4Mask) != 0) + mouse.WheelPrecise++; + if ((buttons & (int)MouseMask.Button5Mask) != 0) + mouse.WheelPrecise--; + WriteBit(MouseButton.Button1, buttons & (int)MouseMask.Button6Mask); + WriteBit(MouseButton.Button2, buttons & (int)MouseMask.Button7Mask); + WriteBit(MouseButton.Button3, buttons & (int)MouseMask.Button8Mask); + } } } }