public XI2MouseKeyboard() { window = new X11WindowInfo(); window.Display = Functions.XOpenDisplay(IntPtr.Zero); using (new XLock(window.Display)) { XSetWindowAttributes attr = new XSetWindowAttributes(); window.Screen = Functions.XDefaultScreen(window.Display); window.RootWindow = Functions.XRootWindow(window.Display, window.Screen); window.Handle = Functions.XCreateWindow(window.Display, window.RootWindow, 0, 0, 1, 1, 0, 0, CreateWindowArgs.InputOnly, IntPtr.Zero, SetWindowValuemask.Nothing, attr); KeyMap = new X11KeyMap(window.Display); } if (!IsSupported(window.Display)) { throw new NotSupportedException("XInput2 not supported."); } // Enable XI2 mouse/keyboard events // Note: the input event loop blocks waiting for these events // *or* a custom ClientMessage event that instructs us to exit. // See SendExitEvent() below. using (new XLock(window.Display)) using (XIEventMask mask = new XIEventMask(1, XIEventMasks.RawKeyPressMask | XIEventMasks.RawKeyReleaseMask | XIEventMasks.RawButtonPressMask | XIEventMasks.RawButtonReleaseMask | XIEventMasks.RawMotionMask | XIEventMasks.MotionMask | XIEventMasks.DeviceChangedMask)) { XI.SelectEvents(window.Display, window.RootWindow, mask); UpdateDevices(); } ProcessingThread = new Thread(ProcessEvents); ProcessingThread.IsBackground = true; ProcessingThread.Start(); }
// Checks whether XInput2 is supported on the specified display. // If a display is not specified, the default display is used. internal static bool IsSupported(IntPtr display) { try { if (display == IntPtr.Zero) { display = API.DefaultDisplay; } using (new XLock(display)) { int major, ev, error; if (Functions.XQueryExtension(display, "XInputExtension", out major, out ev, out error) != 0) { XIOpCode = major; int minor = 2; while (minor >= 0) { if (XI.QueryVersion(display, ref major, ref minor) == ErrorCodes.Success) { XIVersion = major * 100 + minor * 10; return(true); } minor--; } } } } catch (DllNotFoundException e) { Debug.Print(e.ToString()); Debug.Print("XInput2 extension not supported. Mouse support will suffer."); } return(false); }
private void UpdateDevices() { lock (Sync) { devices.Clear(); keyboards.Clear(); int count; unsafe { XIDeviceInfo *list = (XIDeviceInfo *)XI.QueryDevice(window.Display, XI.XIAllDevices, out count); Debug.Print("Refreshing input device list"); Debug.Print("{0} input devices detected", count); for (int i = 0; i < count; i++) { switch ((list + i)->use) { case XIDeviceType.MasterKeyboard: //case XIDeviceType.SlaveKeyboard: { XIKeyboard k = new XIKeyboard(); k.DeviceInfo = *(list + i); k.State.SetIsConnected(k.DeviceInfo.enabled); k.Name = Marshal.PtrToStringAnsi(k.DeviceInfo.name); int id = k.DeviceInfo.deviceid; if (!keyboard_ids.ContainsKey(id)) { keyboard_ids.Add(k.DeviceInfo.deviceid, 0); } keyboard_ids[id] = keyboards.Count; keyboards.Add(k); } break; case XIDeviceType.MasterPointer: //case XIDeviceType.SlavePointer: case XIDeviceType.FloatingSlave: { XIMouse d = new XIMouse(); d.DeviceInfo = *(list + i); d.State.SetIsConnected(d.DeviceInfo.enabled); d.Name = Marshal.PtrToStringAnsi(d.DeviceInfo.name); Debug.Print("Device {0} \"{1}\" is {2} and has:", i, d.Name, d.DeviceInfo.enabled ? "enabled" : "disabled"); // Decode the XIDeviceInfo to axes, buttons and scroll types for (int j = 0; j < d.DeviceInfo.num_classes; j++) { XIAnyClassInfo *class_info = *((XIAnyClassInfo **)d.DeviceInfo.classes + j); switch (class_info->type) { case XIClassType.Button: { XIButtonClassInfo *button = (XIButtonClassInfo *)class_info; Debug.Print("\t{0} buttons", button->num_buttons); } break; case XIClassType.Scroll: { XIScrollClassInfo *scroll = (XIScrollClassInfo *)class_info; switch (scroll->scroll_type) { case XIScrollType.Vertical: Debug.WriteLine("\tSmooth vertical scrolling"); d.ScrollY = *scroll; break; case XIScrollType.Horizontal: Debug.WriteLine("\tSmooth horizontal scrolling"); d.ScrollX = *scroll; break; default: Debug.Print("\tUnknown scrolling type {0}", scroll->scroll_type); break; } } break; case XIClassType.Valuator: { // We use relative x/y valuators for mouse movement. // Iff these are not available, we fall back to // absolute x/y valuators. XIValuatorClassInfo *valuator = (XIValuatorClassInfo *)class_info; if (valuator->label == XI.RelativeX) { Debug.WriteLine("\tRelative X movement"); d.MotionX = *valuator; } else if (valuator->label == XI.RelativeY) { Debug.WriteLine("\tRelative Y movement"); d.MotionY = *valuator; } else if (valuator->label == XI.AbsoluteX) { Debug.WriteLine("\tAbsolute X movement"); if (d.MotionX.number == -1) { d.MotionX = *valuator; } } else if (valuator->label == XI.AbsoluteY) { Debug.WriteLine("\tAbsolute X movement"); if (d.MotionY.number == -1) { d.MotionY = *valuator; } } else { IntPtr label = Functions.XGetAtomName(window.Display, valuator->label); Debug.Print("\tUnknown valuator {0}", Marshal.PtrToStringAnsi(label)); Functions.XFree(label); } } break; } } // Map the hardware device id to the current XIMouse id int id = d.DeviceInfo.deviceid; if (!rawids.ContainsKey(id)) { rawids.Add(id, 0); } rawids[id] = devices.Count; devices.Add(d); } break; } } XI.FreeDeviceInfo((IntPtr)list); } } }