diff options
Diffstat (limited to 'xorg-server/hw/dmx/input')
43 files changed, 10821 insertions, 0 deletions
diff --git a/xorg-server/hw/dmx/input/ChkNotMaskEv.c b/xorg-server/hw/dmx/input/ChkNotMaskEv.c new file mode 100644 index 000000000..fdc67a889 --- /dev/null +++ b/xorg-server/hw/dmx/input/ChkNotMaskEv.c @@ -0,0 +1,107 @@ +/* + * Copyright 1985, 1987, 1998 The Open Group + * + * Permission to use, copy, modify, distribute, and sell this software and its + * documentation for any purpose is hereby granted without fee, provided that + * the above copyright notice appear in all copies and that both that + * copyright notice and this permission notice appear in supporting + * documentation. + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * Except as contained in this notice, the name of The Open Group shall not be + * used in advertising or otherwise to promote the sale, use or other dealings + * in this Software without prior written authorization from The Open Group. + */ +/* $XFree86 */ + +/* + * Copyright 2002-2003 Red Hat Inc., Durham, North Carolina. + * + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation on the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NON-INFRINGEMENT. IN NO EVENT SHALL RED HAT AND/OR THEIR SUPPLIERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/** \file + * This file provides a #XCheckNotMaskEvent function that is derived + * from the standard Xlib XCheckMaskEvent function. */ + +#ifdef HAVE_DMX_CONFIG_H +#include <dmx-config.h> +#endif + +#define NEED_EVENTS +#include "dmx.h" +#include "ChkNotMaskEv.h" + +extern long const _Xevent_to_mask[]; + +/** Check existing events in queue to find if any match. If so, return. + * If not, flush buffer and see if any more events are readable. If one + * matches, return. If all else fails, tell the user no events found. + */ +Bool XCheckNotMaskEvent (Display *dpy, long mask, XEvent *event) +{ + register _XQEvent *prev, *qelt; + unsigned long qe_serial = 0; + int n; /* time through count */ + + LockDisplay(dpy); + prev = NULL; + for (n = 3; --n >= 0;) { + for (qelt = prev ? prev->next : dpy->head; + qelt; + prev = qelt, qelt = qelt->next) { + if (qelt->event.type >= LASTEvent + || !(_Xevent_to_mask[qelt->event.type] & mask)) { + *event = qelt->event; + _XDeq(dpy, prev, qelt); + UnlockDisplay(dpy); + return True; + } + } + if (prev) + qe_serial = prev->qserial_num; + switch (n) { + case 2: + _XEventsQueued(dpy, QueuedAfterReading); + break; + case 1: + _XFlush(dpy); + break; + } + if (prev && prev->qserial_num != qe_serial) + /* another thread has snatched this event */ + prev = NULL; + } + UnlockDisplay(dpy); + return False; +} diff --git a/xorg-server/hw/dmx/input/ChkNotMaskEv.h b/xorg-server/hw/dmx/input/ChkNotMaskEv.h new file mode 100644 index 000000000..f79075e1d --- /dev/null +++ b/xorg-server/hw/dmx/input/ChkNotMaskEv.h @@ -0,0 +1,40 @@ +/* + * Copyright 2002 Red Hat Inc., Durham, North Carolina. + * + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation on the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NON-INFRINGEMENT. IN NO EVENT SHALL RED HAT AND/OR THEIR SUPPLIERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* + * Authors: + * Rickard E. (Rik) Faith <faith@redhat.com> + * + */ + +/** \file + * Interface for #XCheckNotMaskEvent function. \see ChkNotMaskEv.c */ + +#ifndef _CHKNOTMASKEV_H_ +#define _CHKNOTMASKEV_H_ +extern Bool XCheckNotMaskEvent (Display *dpy, long mask, XEvent *event); +#endif diff --git a/xorg-server/hw/dmx/input/Makefile.am b/xorg-server/hw/dmx/input/Makefile.am new file mode 100644 index 000000000..da8de0546 --- /dev/null +++ b/xorg-server/hw/dmx/input/Makefile.am @@ -0,0 +1,71 @@ +noinst_LIBRARIES = libdmxinput.a + +if DMX_BUILD_LNX +RAWSRCS = lnx-keyboard.c \ + lnx-keyboard.h \ + lnx-ms.c \ + lnx-ms.h \ + lnx-ps2.c \ + lnx-ps2.h +endif + +if DMX_BUILD_USB +USBSRCS = usb-keyboard.c \ + usb-keyboard.h \ + usb-mouse.c \ + usb-mouse.h \ + usb-other.c \ + usb-other.h \ + usb-common.c \ + usb-common.h \ + usb-private.h +endif + +DRVSRCS = dmxdummy.c \ + dmxdummy.h \ + dmxbackend.c \ + dmxbackend.h \ + dmxconsole.c \ + dmxconsole.h \ + dmxcommon.c \ + dmxcommon.h + +DMXSRCS = dmxinputinit.c \ + dmxinputinit.h \ + dmxarg.c \ + dmxarg.h \ + dmxsigio.c \ + dmxsigio.h \ + dmxevents.c \ + dmxevents.h \ + dmxxinput.c \ + dmxmotion.c \ + dmxmotion.h \ + dmxeq.c \ + dmxeq.h \ + dmxmap.c \ + dmxmap.h + + +libdmxinput_a_SOURCES = ChkNotMaskEv.c \ + ChkNotMaskEv.h \ + $(RAWSRCS) \ + $(USBSRCS) \ + $(DRVSRCS) \ + $(DMXSRCS) \ + $(LIBSRCS) + +if GLX +GLX_DEFS = @GL_CFLAGS@ +GLX_INCS = -I@MESA_SOURCE@/include +endif + +AM_CFLAGS = $(DIX_CFLAGS) \ + -I$(top_srcdir)/hw/dmx \ + -I$(top_srcdir)/hw/xfree86/common \ + $(GLX_INCS) \ + -DHAVE_DMX_CONFIG_H \ + $(GLX_DEFS) \ + @DMXMODULES_CFLAGS@ + +EXTRA_DIST = dmxdetach.c diff --git a/xorg-server/hw/dmx/input/Makefile.in b/xorg-server/hw/dmx/input/Makefile.in new file mode 100644 index 000000000..bbac88828 --- /dev/null +++ b/xorg-server/hw/dmx/input/Makefile.in @@ -0,0 +1,738 @@ +# Makefile.in generated by automake 1.10.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +subdir = hw/dmx/input +DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/acinclude.m4 \ + $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/include/do-not-use-config.h \ + $(top_builddir)/include/xorg-server.h \ + $(top_builddir)/include/dix-config.h \ + $(top_builddir)/include/xgl-config.h \ + $(top_builddir)/include/xorg-config.h \ + $(top_builddir)/include/xkb-config.h \ + $(top_builddir)/include/xwin-config.h \ + $(top_builddir)/include/kdrive-config.h +CONFIG_CLEAN_FILES = +LIBRARIES = $(noinst_LIBRARIES) +ARFLAGS = cru +libdmxinput_a_AR = $(AR) $(ARFLAGS) +libdmxinput_a_LIBADD = +am__libdmxinput_a_SOURCES_DIST = ChkNotMaskEv.c ChkNotMaskEv.h \ + lnx-keyboard.c lnx-keyboard.h lnx-ms.c lnx-ms.h lnx-ps2.c \ + lnx-ps2.h usb-keyboard.c usb-keyboard.h usb-mouse.c \ + usb-mouse.h usb-other.c usb-other.h usb-common.c usb-common.h \ + usb-private.h dmxdummy.c dmxdummy.h dmxbackend.c dmxbackend.h \ + dmxconsole.c dmxconsole.h dmxcommon.c dmxcommon.h \ + dmxinputinit.c dmxinputinit.h dmxarg.c dmxarg.h dmxsigio.c \ + dmxsigio.h dmxevents.c dmxevents.h dmxxinput.c dmxmotion.c \ + dmxmotion.h dmxeq.c dmxeq.h dmxmap.c dmxmap.h +@DMX_BUILD_LNX_TRUE@am__objects_1 = lnx-keyboard.$(OBJEXT) \ +@DMX_BUILD_LNX_TRUE@ lnx-ms.$(OBJEXT) lnx-ps2.$(OBJEXT) +@DMX_BUILD_USB_TRUE@am__objects_2 = usb-keyboard.$(OBJEXT) \ +@DMX_BUILD_USB_TRUE@ usb-mouse.$(OBJEXT) usb-other.$(OBJEXT) \ +@DMX_BUILD_USB_TRUE@ usb-common.$(OBJEXT) +am__objects_3 = dmxdummy.$(OBJEXT) dmxbackend.$(OBJEXT) \ + dmxconsole.$(OBJEXT) dmxcommon.$(OBJEXT) +am__objects_4 = dmxinputinit.$(OBJEXT) dmxarg.$(OBJEXT) \ + dmxsigio.$(OBJEXT) dmxevents.$(OBJEXT) dmxxinput.$(OBJEXT) \ + dmxmotion.$(OBJEXT) dmxeq.$(OBJEXT) dmxmap.$(OBJEXT) +am_libdmxinput_a_OBJECTS = ChkNotMaskEv.$(OBJEXT) $(am__objects_1) \ + $(am__objects_2) $(am__objects_3) $(am__objects_4) +libdmxinput_a_OBJECTS = $(am_libdmxinput_a_OBJECTS) +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)/include +depcomp = $(SHELL) $(top_srcdir)/depcomp +am__depfiles_maybe = depfiles +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +LTCOMPILE = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ + $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +CCLD = $(CC) +LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \ + $(LDFLAGS) -o $@ +SOURCES = $(libdmxinput_a_SOURCES) +DIST_SOURCES = $(am__libdmxinput_a_SOURCES_DIST) +ETAGS = etags +CTAGS = ctags +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +ADMIN_MAN_DIR = @ADMIN_MAN_DIR@ +ADMIN_MAN_SUFFIX = @ADMIN_MAN_SUFFIX@ +ALLOCA = @ALLOCA@ +AMTAR = @AMTAR@ +APPDEFAULTDIR = @APPDEFAULTDIR@ +APPLE_APPLICATIONS_DIR = @APPLE_APPLICATIONS_DIR@ +APP_MAN_DIR = @APP_MAN_DIR@ +APP_MAN_SUFFIX = @APP_MAN_SUFFIX@ +AR = @AR@ +AS = @AS@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +BASE_FONT_PATH = @BASE_FONT_PATH@ +BUILD_DATE = @BUILD_DATE@ +BUILD_TIME = @BUILD_TIME@ +CC = @CC@ +CCAS = @CCAS@ +CCASDEPMODE = @CCASDEPMODE@ +CCASFLAGS = @CCASFLAGS@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +COMPILEDDEFAULTFONTPATH = @COMPILEDDEFAULTFONTPATH@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CXX = @CXX@ +CXXCPP = @CXXCPP@ +CXXDEPMODE = @CXXDEPMODE@ +CXXFLAGS = @CXXFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DARWIN_LIBS = @DARWIN_LIBS@ +DBUS_CFLAGS = @DBUS_CFLAGS@ +DBUS_LIBS = @DBUS_LIBS@ +DEFAULT_LIBRARY_PATH = @DEFAULT_LIBRARY_PATH@ +DEFAULT_LOGPREFIX = @DEFAULT_LOGPREFIX@ +DEFAULT_MODULE_PATH = @DEFAULT_MODULE_PATH@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DGA_CFLAGS = @DGA_CFLAGS@ +DGA_LIBS = @DGA_LIBS@ +DIX_CFLAGS = @DIX_CFLAGS@ +DLLTOOL = @DLLTOOL@ +DMXEXAMPLES_DEP_CFLAGS = @DMXEXAMPLES_DEP_CFLAGS@ +DMXEXAMPLES_DEP_LIBS = @DMXEXAMPLES_DEP_LIBS@ +DMXMODULES_CFLAGS = @DMXMODULES_CFLAGS@ +DMXMODULES_LIBS = @DMXMODULES_LIBS@ +DMXXIEXAMPLES_DEP_CFLAGS = @DMXXIEXAMPLES_DEP_CFLAGS@ +DMXXIEXAMPLES_DEP_LIBS = @DMXXIEXAMPLES_DEP_LIBS@ +DMXXMUEXAMPLES_DEP_CFLAGS = @DMXXMUEXAMPLES_DEP_CFLAGS@ +DMXXMUEXAMPLES_DEP_LIBS = @DMXXMUEXAMPLES_DEP_LIBS@ +DRI2PROTO_CFLAGS = @DRI2PROTO_CFLAGS@ +DRI2PROTO_LIBS = @DRI2PROTO_LIBS@ +DRIPROTO_CFLAGS = @DRIPROTO_CFLAGS@ +DRIPROTO_LIBS = @DRIPROTO_LIBS@ +DRIVER_MAN_DIR = @DRIVER_MAN_DIR@ +DRIVER_MAN_SUFFIX = @DRIVER_MAN_SUFFIX@ +DRI_DRIVER_PATH = @DRI_DRIVER_PATH@ +DSYMUTIL = @DSYMUTIL@ +DTRACE = @DTRACE@ +ECHO = @ECHO@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +F77 = @F77@ +FFLAGS = @FFLAGS@ +FILE_MAN_DIR = @FILE_MAN_DIR@ +FILE_MAN_SUFFIX = @FILE_MAN_SUFFIX@ +FREETYPE_CFLAGS = @FREETYPE_CFLAGS@ +FREETYPE_LIBS = @FREETYPE_LIBS@ +GLX_ARCH_DEFINES = @GLX_ARCH_DEFINES@ +GLX_DEFINES = @GLX_DEFINES@ +GL_CFLAGS = @GL_CFLAGS@ +GL_LIBS = @GL_LIBS@ +GREP = @GREP@ +HAL_CFLAGS = @HAL_CFLAGS@ +HAL_LIBS = @HAL_LIBS@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +KDRIVE_CFLAGS = @KDRIVE_CFLAGS@ +KDRIVE_INCS = @KDRIVE_INCS@ +KDRIVE_LIBS = @KDRIVE_LIBS@ +KDRIVE_LOCAL_LIBS = @KDRIVE_LOCAL_LIBS@ +KDRIVE_PURE_INCS = @KDRIVE_PURE_INCS@ +KDRIVE_PURE_LIBS = @KDRIVE_PURE_LIBS@ +LAUNCHD = @LAUNCHD@ +LDFLAGS = @LDFLAGS@ +LD_EXPORT_SYMBOLS_FLAG = @LD_EXPORT_SYMBOLS_FLAG@ +LEX = @LEX@ +LEXLIB = @LEXLIB@ +LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@ +LIBDRM_CFLAGS = @LIBDRM_CFLAGS@ +LIBDRM_LIBS = @LIBDRM_LIBS@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIB_MAN_DIR = @LIB_MAN_DIR@ +LIB_MAN_SUFFIX = @LIB_MAN_SUFFIX@ +LINUXDOC = @LINUXDOC@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAINT = @MAINT@ +MAKEINFO = @MAKEINFO@ +MAKE_HTML = @MAKE_HTML@ +MAKE_PDF = @MAKE_PDF@ +MAKE_PS = @MAKE_PS@ +MAKE_TEXT = @MAKE_TEXT@ +MESA_SOURCE = @MESA_SOURCE@ +MISC_MAN_DIR = @MISC_MAN_DIR@ +MISC_MAN_SUFFIX = @MISC_MAN_SUFFIX@ +MKDIR_P = @MKDIR_P@ +MKFONTDIR = @MKFONTDIR@ +MKFONTSCALE = @MKFONTSCALE@ +NMEDIT = @NMEDIT@ +OBJC = @OBJC@ +OBJCCLD = @OBJCCLD@ +OBJCDEPMODE = @OBJCDEPMODE@ +OBJCFLAGS = @OBJCFLAGS@ +OBJCLINK = @OBJCLINK@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OPENSSL_CFLAGS = @OPENSSL_CFLAGS@ +OPENSSL_LIBS = @OPENSSL_LIBS@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +PCIACCESS_CFLAGS = @PCIACCESS_CFLAGS@ +PCIACCESS_LIBS = @PCIACCESS_LIBS@ +PCI_TXT_IDS_PATH = @PCI_TXT_IDS_PATH@ +PERL = @PERL@ +PKG_CONFIG = @PKG_CONFIG@ +PROJECTROOT = @PROJECTROOT@ +PS2PDF = @PS2PDF@ +RANLIB = @RANLIB@ +RAWCPP = @RAWCPP@ +RAWCPPFLAGS = @RAWCPPFLAGS@ +SED = @SED@ +SERVER_MISC_CONFIG_PATH = @SERVER_MISC_CONFIG_PATH@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +SOLARIS_ASM_CFLAGS = @SOLARIS_ASM_CFLAGS@ +SOLARIS_INOUT_ARCH = @SOLARIS_INOUT_ARCH@ +STRIP = @STRIP@ +TSLIB_CFLAGS = @TSLIB_CFLAGS@ +TSLIB_LIBS = @TSLIB_LIBS@ +UTILS_SYS_LIBS = @UTILS_SYS_LIBS@ +VENDOR_MAN_VERSION = @VENDOR_MAN_VERSION@ +VENDOR_NAME = @VENDOR_NAME@ +VENDOR_NAME_SHORT = @VENDOR_NAME_SHORT@ +VENDOR_RELEASE = @VENDOR_RELEASE@ +VERSION = @VERSION@ +X11APP_ARCHS = @X11APP_ARCHS@ +X11EXAMPLES_DEP_CFLAGS = @X11EXAMPLES_DEP_CFLAGS@ +X11EXAMPLES_DEP_LIBS = @X11EXAMPLES_DEP_LIBS@ +XDMCP_CFLAGS = @XDMCP_CFLAGS@ +XDMCP_LIBS = @XDMCP_LIBS@ +XDMXCONFIG_DEP_CFLAGS = @XDMXCONFIG_DEP_CFLAGS@ +XDMXCONFIG_DEP_LIBS = @XDMXCONFIG_DEP_LIBS@ +XDMX_CFLAGS = @XDMX_CFLAGS@ +XDMX_LIBS = @XDMX_LIBS@ +XDMX_SYS_LIBS = @XDMX_SYS_LIBS@ +XEGLMODULES_CFLAGS = @XEGLMODULES_CFLAGS@ +XEGL_LIBS = @XEGL_LIBS@ +XEGL_SYS_LIBS = @XEGL_SYS_LIBS@ +XEPHYR_CFLAGS = @XEPHYR_CFLAGS@ +XEPHYR_DRI_LIBS = @XEPHYR_DRI_LIBS@ +XEPHYR_INCS = @XEPHYR_INCS@ +XEPHYR_LIBS = @XEPHYR_LIBS@ +XF86CONFIGFILE = @XF86CONFIGFILE@ +XF86MISC_CFLAGS = @XF86MISC_CFLAGS@ +XF86MISC_LIBS = @XF86MISC_LIBS@ +XF86VIDMODE_CFLAGS = @XF86VIDMODE_CFLAGS@ +XF86VIDMODE_LIBS = @XF86VIDMODE_LIBS@ +XGLMODULES_CFLAGS = @XGLMODULES_CFLAGS@ +XGLMODULES_LIBS = @XGLMODULES_LIBS@ +XGLXMODULES_CFLAGS = @XGLXMODULES_CFLAGS@ +XGLXMODULES_LIBS = @XGLXMODULES_LIBS@ +XGLX_LIBS = @XGLX_LIBS@ +XGLX_SYS_LIBS = @XGLX_SYS_LIBS@ +XGL_LIBS = @XGL_LIBS@ +XGL_MODULE_PATH = @XGL_MODULE_PATH@ +XGL_SYS_LIBS = @XGL_SYS_LIBS@ +XKB_BASE_DIRECTORY = @XKB_BASE_DIRECTORY@ +XKB_BIN_DIRECTORY = @XKB_BIN_DIRECTORY@ +XKB_COMPILED_DIR = @XKB_COMPILED_DIR@ +XKM_OUTPUT_DIR = @XKM_OUTPUT_DIR@ +XLIB_CFLAGS = @XLIB_CFLAGS@ +XLIB_LIBS = @XLIB_LIBS@ +XNESTMODULES_CFLAGS = @XNESTMODULES_CFLAGS@ +XNESTMODULES_LIBS = @XNESTMODULES_LIBS@ +XNEST_LIBS = @XNEST_LIBS@ +XNEST_SYS_LIBS = @XNEST_SYS_LIBS@ +XORGCFG_DEP_CFLAGS = @XORGCFG_DEP_CFLAGS@ +XORGCFG_DEP_LIBS = @XORGCFG_DEP_LIBS@ +XORGCONFIG_DEP_CFLAGS = @XORGCONFIG_DEP_CFLAGS@ +XORGCONFIG_DEP_LIBS = @XORGCONFIG_DEP_LIBS@ +XORG_CFLAGS = @XORG_CFLAGS@ +XORG_INCS = @XORG_INCS@ +XORG_LIBS = @XORG_LIBS@ +XORG_MODULES_CFLAGS = @XORG_MODULES_CFLAGS@ +XORG_MODULES_LIBS = @XORG_MODULES_LIBS@ +XORG_OS = @XORG_OS@ +XORG_OS_SUBDIR = @XORG_OS_SUBDIR@ +XORG_SYS_LIBS = @XORG_SYS_LIBS@ +XPRINTMODULES_CFLAGS = @XPRINTMODULES_CFLAGS@ +XPRINTMODULES_LIBS = @XPRINTMODULES_LIBS@ +XPRINTPROTO_CFLAGS = @XPRINTPROTO_CFLAGS@ +XPRINTPROTO_LIBS = @XPRINTPROTO_LIBS@ +XPRINT_CFLAGS = @XPRINT_CFLAGS@ +XPRINT_LIBS = @XPRINT_LIBS@ +XPRINT_SYS_LIBS = @XPRINT_SYS_LIBS@ +XRESEXAMPLES_DEP_CFLAGS = @XRESEXAMPLES_DEP_CFLAGS@ +XRESEXAMPLES_DEP_LIBS = @XRESEXAMPLES_DEP_LIBS@ +XSDL_INCS = @XSDL_INCS@ +XSDL_LIBS = @XSDL_LIBS@ +XSERVERCFLAGS_CFLAGS = @XSERVERCFLAGS_CFLAGS@ +XSERVERCFLAGS_LIBS = @XSERVERCFLAGS_LIBS@ +XSERVERLIBS_CFLAGS = @XSERVERLIBS_CFLAGS@ +XSERVERLIBS_LIBS = @XSERVERLIBS_LIBS@ +XSERVER_LIBS = @XSERVER_LIBS@ +XSERVER_SYS_LIBS = @XSERVER_SYS_LIBS@ +XTSTEXAMPLES_DEP_CFLAGS = @XTSTEXAMPLES_DEP_CFLAGS@ +XTSTEXAMPLES_DEP_LIBS = @XTSTEXAMPLES_DEP_LIBS@ +XVFB_LIBS = @XVFB_LIBS@ +XVFB_SYS_LIBS = @XVFB_SYS_LIBS@ +XWINMODULES_CFLAGS = @XWINMODULES_CFLAGS@ +XWINMODULES_LIBS = @XWINMODULES_LIBS@ +XWIN_LIBS = @XWIN_LIBS@ +XWIN_SERVER_NAME = @XWIN_SERVER_NAME@ +XWIN_SYS_LIBS = @XWIN_SYS_LIBS@ +YACC = @YACC@ +YFLAGS = @YFLAGS@ +__XCONFIGFILE__ = @__XCONFIGFILE__@ +abi_ansic = @abi_ansic@ +abi_extension = @abi_extension@ +abi_font = @abi_font@ +abi_videodrv = @abi_videodrv@ +abi_xinput = @abi_xinput@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_CXX = @ac_ct_CXX@ +ac_ct_F77 = @ac_ct_F77@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +driverdir = @driverdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +extdir = @extdir@ +ft_config = @ft_config@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +launchagentsdir = @launchagentsdir@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +logdir = @logdir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +moduledir = @moduledir@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +sbindir = @sbindir@ +sdkdir = @sdkdir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +xglmoduledir = @xglmoduledir@ +xpconfigdir = @xpconfigdir@ +noinst_LIBRARIES = libdmxinput.a +@DMX_BUILD_LNX_TRUE@RAWSRCS = lnx-keyboard.c \ +@DMX_BUILD_LNX_TRUE@ lnx-keyboard.h \ +@DMX_BUILD_LNX_TRUE@ lnx-ms.c \ +@DMX_BUILD_LNX_TRUE@ lnx-ms.h \ +@DMX_BUILD_LNX_TRUE@ lnx-ps2.c \ +@DMX_BUILD_LNX_TRUE@ lnx-ps2.h + +@DMX_BUILD_USB_TRUE@USBSRCS = usb-keyboard.c \ +@DMX_BUILD_USB_TRUE@ usb-keyboard.h \ +@DMX_BUILD_USB_TRUE@ usb-mouse.c \ +@DMX_BUILD_USB_TRUE@ usb-mouse.h \ +@DMX_BUILD_USB_TRUE@ usb-other.c \ +@DMX_BUILD_USB_TRUE@ usb-other.h \ +@DMX_BUILD_USB_TRUE@ usb-common.c \ +@DMX_BUILD_USB_TRUE@ usb-common.h \ +@DMX_BUILD_USB_TRUE@ usb-private.h + +DRVSRCS = dmxdummy.c \ + dmxdummy.h \ + dmxbackend.c \ + dmxbackend.h \ + dmxconsole.c \ + dmxconsole.h \ + dmxcommon.c \ + dmxcommon.h + +DMXSRCS = dmxinputinit.c \ + dmxinputinit.h \ + dmxarg.c \ + dmxarg.h \ + dmxsigio.c \ + dmxsigio.h \ + dmxevents.c \ + dmxevents.h \ + dmxxinput.c \ + dmxmotion.c \ + dmxmotion.h \ + dmxeq.c \ + dmxeq.h \ + dmxmap.c \ + dmxmap.h + +libdmxinput_a_SOURCES = ChkNotMaskEv.c \ + ChkNotMaskEv.h \ + $(RAWSRCS) \ + $(USBSRCS) \ + $(DRVSRCS) \ + $(DMXSRCS) \ + $(LIBSRCS) + +@GLX_TRUE@GLX_DEFS = @GL_CFLAGS@ +@GLX_TRUE@GLX_INCS = -I@MESA_SOURCE@/include +AM_CFLAGS = $(DIX_CFLAGS) \ + -I$(top_srcdir)/hw/dmx \ + -I$(top_srcdir)/hw/xfree86/common \ + $(GLX_INCS) \ + -DHAVE_DMX_CONFIG_H \ + $(GLX_DEFS) \ + @DMXMODULES_CFLAGS@ + +EXTRA_DIST = dmxdetach.c +all: all-am + +.SUFFIXES: +.SUFFIXES: .c .lo .o .obj +$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \ + && exit 0; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign hw/dmx/input/Makefile'; \ + cd $(top_srcdir) && \ + $(AUTOMAKE) --foreign hw/dmx/input/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +clean-noinstLIBRARIES: + -test -z "$(noinst_LIBRARIES)" || rm -f $(noinst_LIBRARIES) +libdmxinput.a: $(libdmxinput_a_OBJECTS) $(libdmxinput_a_DEPENDENCIES) + -rm -f libdmxinput.a + $(libdmxinput_a_AR) libdmxinput.a $(libdmxinput_a_OBJECTS) $(libdmxinput_a_LIBADD) + $(RANLIB) libdmxinput.a + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ChkNotMaskEv.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dmxarg.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dmxbackend.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dmxcommon.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dmxconsole.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dmxdummy.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dmxeq.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dmxevents.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dmxinputinit.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dmxmap.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dmxmotion.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dmxsigio.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dmxxinput.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lnx-keyboard.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lnx-ms.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lnx-ps2.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/usb-common.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/usb-keyboard.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/usb-mouse.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/usb-other.Po@am__quote@ + +.c.o: +@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c $< + +.c.obj: +@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` +@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'` + +.c.lo: +@am__fastdepCC_TRUE@ $(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $< + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonemtpy = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + if test -z "$(ETAGS_ARGS)$$tags$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$tags $$unique; \ + fi +ctags: CTAGS +CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + test -z "$(CTAGS_ARGS)$$tags$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$tags $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && cd $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) $$here + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \ + fi; \ + cp -pR $$d/$$file $(distdir)$$dir || exit 1; \ + else \ + test -f $(distdir)/$$file \ + || cp -p $$d/$$file $(distdir)/$$file \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile $(LIBRARIES) +installdirs: +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic clean-libtool clean-noinstLIBRARIES \ + mostlyclean-am + +distclean: distclean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +info: info-am + +info-am: + +install-data-am: + +install-dvi: install-dvi-am + +install-exec-am: + +install-html: install-html-am + +install-info: install-info-am + +install-man: + +install-pdf: install-pdf-am + +install-ps: install-ps-am + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: + +.MAKE: install-am install-strip + +.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \ + clean-libtool clean-noinstLIBRARIES ctags distclean \ + distclean-compile distclean-generic distclean-libtool \ + distclean-tags distdir dvi dvi-am html html-am info info-am \ + install install-am install-data install-data-am install-dvi \ + install-dvi-am install-exec install-exec-am install-html \ + install-html-am install-info install-info-am install-man \ + install-pdf install-pdf-am install-ps install-ps-am \ + install-strip installcheck installcheck-am installdirs \ + maintainer-clean maintainer-clean-generic mostlyclean \ + mostlyclean-compile mostlyclean-generic mostlyclean-libtool \ + pdf pdf-am ps ps-am tags uninstall uninstall-am + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/xorg-server/hw/dmx/input/dmxarg.c b/xorg-server/hw/dmx/input/dmxarg.c new file mode 100644 index 000000000..49a1da9af --- /dev/null +++ b/xorg-server/hw/dmx/input/dmxarg.c @@ -0,0 +1,175 @@ +/* + * Copyright 2002-2003 Red Hat Inc., Durham, North Carolina. + * + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation on the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NON-INFRINGEMENT. IN NO EVENT SHALL RED HAT AND/OR THEIR SUPPLIERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* + * Authors: + * Rickard E. (Rik) Faith <faith@redhat.com> + * + */ + +/** \file + * Generic comma-delimited argument processing. */ + +#ifdef HAVE_DMX_CONFIG_H +#include <dmx-config.h> +#endif + +#define DMX_ARG_TEST 0 + +#include "dmx.h" +#include "dmxarg.h" +#include <stdio.h> +#include <string.h> + +#if DMX_ARG_TEST +#include <stdlib.h> +#endif + +/** Stores the parsed argument list. */ +struct _dmxArg { + int argc; /**< Number of arguments in argv */ + int argm; /**< Maximum number of arguments store-able in argv */ + const char **argv; /**< Arguments */ +}; + +/** Create an (externally opaque) \a dmxArg object. */ +dmxArg dmxArgCreate(void) +{ + dmxArg a = malloc(sizeof(*a)); + a->argc = 0; + a->argm = 2; + a->argv = malloc(a->argm * sizeof(*a->argv)); + a->argv[0] = NULL; + return a; +} + +/** Free the specified \a dmxArg object. */ +void dmxArgFree(dmxArg a) +{ + int i; + + for (i = 0; i < a->argc; i++) free((char *)a->argv[i]); + free(a->argv); + free(a); +} + +/** Add the \a string as the next argument in the \a dmxArg object. */ +void dmxArgAdd(dmxArg a, const char *string) +{ + if (a->argm <= a->argc + 2) + a->argv = realloc(a->argv, sizeof(*a->argv) * (a->argm *= 2)); + a->argv[a->argc++] = strdup(string); + a->argv[a->argc] = NULL; +} + +/** Return the argument number \a item in the \a dmxArg object. + * Arguments are 0 based. NULL will be returned for values less than 0 + * or equal to or greater than the number of arguments in the object. */ +const char *dmxArgV(dmxArg a, int item) +{ + if (item < 0 || item >= a->argc) return NULL; + return a->argv[item]; +} + +/** Return the number of arguments in the \a dmxArg object. */ +int dmxArgC(dmxArg a) +{ + return a->argc; +} + +/** Parse a string into arguments delimited by commas. Return a new \a + * dmxArg object containing the arguments. */ +dmxArg dmxArgParse(const char *string) +{ + char *tmp; + char *start, *pt; + dmxArg a = dmxArgCreate(); + int done; + int len; + + if (!string) return a; + + len = strlen(string) + 2; + tmp = malloc(len); + strncpy(tmp, string, len); + + for (start = pt = tmp, done = 0; !done && *pt; start = ++pt) { + for (;*pt && *pt != ','; pt++); + if (!*pt) done = 1; + *pt = '\0'; + dmxArgAdd(a, start); + } + if (!done) dmxArgAdd(a, ""); /* Final comma */ + + free(tmp); + return a; +} + +#if DMX_ARG_TEST +static void dmxArgPrint(dmxArg a) +{ + int i; + + printf(" argc = %d\n", dmxArgC(a)); + for (i = 0; i < dmxArgC(a); i++) + printf(" argv[%d] = \"%s\"\n", i, dmxArgV(a, i)); +} + +static void dmxArgTest(const char *string) +{ + dmxArg a; + + if (!string) + printf("Testing NULL\n"); + else if (!strlen(string)) + printf("Testing (empty)\n"); + else + printf("Testing \"%s\"\n", string); + + a = dmxArgParse(string); + dmxArgPrint(a); + dmxArgFree(a); +} + +int main(void) +{ + dmxArgTest(NULL); + dmxArgTest(""); + dmxArgTest(","); + + dmxArgTest("a"); + dmxArgTest("a,"); + dmxArgTest(",a"); + + dmxArgTest("a,b"); + dmxArgTest("a,b,"); + dmxArgTest("a,b,,"); + dmxArgTest("a,b,,c"); + + return 0; +} +#endif diff --git a/xorg-server/hw/dmx/input/dmxarg.h b/xorg-server/hw/dmx/input/dmxarg.h new file mode 100644 index 000000000..ca76f9272 --- /dev/null +++ b/xorg-server/hw/dmx/input/dmxarg.h @@ -0,0 +1,49 @@ +/* + * Copyright 2002 Red Hat Inc., Durham, North Carolina. + * + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation on the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NON-INFRINGEMENT. IN NO EVENT SHALL RED HAT AND/OR THEIR SUPPLIERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* + * Authors: + * Rickard E. (Rik) Faith <faith@redhat.com> + * + */ + +/** \file + * Interface to argument handling functions. \see dmxarg.c */ + +#ifndef _DMXARG_H_ +#define _DMXARG_H_ + +typedef struct _dmxArg *dmxArg; + +extern dmxArg dmxArgCreate(void); +extern void dmxArgFree(dmxArg a); +extern void dmxArgAdd(dmxArg a, const char *string); +extern const char *dmxArgV(dmxArg a, int item); +extern int dmxArgC(dmxArg a); +extern dmxArg dmxArgParse(const char *string); + +#endif diff --git a/xorg-server/hw/dmx/input/dmxbackend.c b/xorg-server/hw/dmx/input/dmxbackend.c new file mode 100644 index 000000000..b1791098a --- /dev/null +++ b/xorg-server/hw/dmx/input/dmxbackend.c @@ -0,0 +1,617 @@ +/* + * Copyright 2001-2003 Red Hat Inc., Durham, North Carolina. + * + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation on the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NON-INFRINGEMENT. IN NO EVENT SHALL RED HAT AND/OR THEIR SUPPLIERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* + * Authors: + * David H. Dawes <dawes@xfree86.org> + * Kevin E. Martin <kem@redhat.com> + * Rickard E. (Rik) Faith <faith@redhat.com> + */ + +/** \file + * These routines support taking input from devices on the backend + * (output) displays. \see dmxcommon.c. */ + +#ifdef HAVE_DMX_CONFIG_H +#include <dmx-config.h> +#endif + +#define DMX_BACKEND_DEBUG 0 + +#include "dmxinputinit.h" +#include "dmxbackend.h" +#include "dmxcommon.h" +#include "dmxconsole.h" +#include "dmxcursor.h" +#include "dmxprop.h" +#include "dmxsync.h" +#include "dmxcb.h" /* For dmxGlobalWidth and dmxGlobalHeight */ +#include "dmxevents.h" /* For dmxGetGlobalPosition */ +#include "ChkNotMaskEv.h" + +#include "inputstr.h" +#include "input.h" +#include <X11/keysym.h> +#include "mipointer.h" +#include "scrnintstr.h" +#include "windowstr.h" + +/* Private area for backend devices. */ +typedef struct _myPrivate { + DMX_COMMON_PRIVATE; + int myScreen; + DMXScreenInfo *grabbedScreen; + + int lastX, lastY; + int centerX, centerY; + int relative; + int newscreen; + int initialized; + DevicePtr mou, kbd; + int entered; + int offX, offY; +} myPrivate; + +#if DMX_BACKEND_DEBUG +#define DMXDBG0(f) dmxLog(dmxDebug,f) +#define DMXDBG1(f,a) dmxLog(dmxDebug,f,a) +#define DMXDBG2(f,a,b) dmxLog(dmxDebug,f,a,b) +#define DMXDBG3(f,a,b,c) dmxLog(dmxDebug,f,a,b,c) +#define DMXDBG4(f,a,b,c,d) dmxLog(dmxDebug,f,a,b,c,d) +#define DMXDBG5(f,a,b,c,d,e) dmxLog(dmxDebug,f,a,b,c,d,e) +#define DMXDBG6(f,a,b,c,d,e,g) dmxLog(dmxDebug,f,a,b,c,d,e,g) +#define DMXDBG7(f,a,b,c,d,e,g,h) dmxLog(dmxDebug,f,a,b,c,d,e,g,h) +#define DMXDBG8(f,a,b,c,d,e,g,h,i) dmxLog(dmxDebug,f,a,b,c,d,e,g,h,i) +#define DMXDBG9(f,a,b,c,d,e,g,h,i,j) dmxLog(dmxDebug,f,a,b,c,d,e,g,h,i,j) +#else +#define DMXDBG0(f) +#define DMXDBG1(f,a) +#define DMXDBG2(f,a,b) +#define DMXDBG3(f,a,b,c) +#define DMXDBG4(f,a,b,c,d) +#define DMXDBG5(f,a,b,c,d,e) +#define DMXDBG6(f,a,b,c,d,e,g) +#define DMXDBG7(f,a,b,c,d,e,g,h) +#define DMXDBG8(f,a,b,c,d,e,g,h,i) +#define DMXDBG9(f,a,b,c,d,e,g,h,i,j) +#endif + +/** Create and return a private data structure. */ +pointer dmxBackendCreatePrivate(DeviceIntPtr pDevice) +{ + GETDMXLOCALFROMPDEVICE; + myPrivate *priv = xalloc(sizeof(*priv)); + memset(priv, 0, sizeof(*priv)); + priv->dmxLocal = dmxLocal; + return priv; +} + +/** Destroy the private data structure. No checking is performed to + * verify that the structure was actually created by + * #dmxBackendCreatePrivate. */ +void dmxBackendDestroyPrivate(pointer private) +{ + if (private) xfree(private); +} + +static void *dmxBackendTestScreen(DMXScreenInfo *dmxScreen, void *closure) +{ + long target = (long)closure; + + if (dmxScreen->index == target) return dmxScreen; + return NULL; +} + +/* Return non-zero if screen and priv->myScreen are on the same physical + * backend display (1 if they are the same screen, 2 if they are + * different screens). Since this is a common operation, the results + * are cached. The cache is invalidated if \a priv is NULL (this should + * be done with each server generation and reconfiguration). */ +static int dmxBackendSameDisplay(myPrivate *priv, long screen) +{ + static myPrivate *oldpriv = NULL; + static int oldscreen = -1; + static int retcode = 0; + + if (priv == oldpriv && screen == oldscreen) return retcode; + if (!priv) { /* Invalidate cache */ + oldpriv = NULL; + oldscreen = -1; + retcode = 0; + return 0; + } + + if (screen == priv->myScreen) retcode = 1; + else if (screen < 0 || screen >= dmxNumScreens) retcode = 0; + else if (dmxPropertyIterate(priv->be, + dmxBackendTestScreen, + (void *)screen)) retcode = 2; + else retcode = 0; + + oldpriv = priv; + oldscreen = screen; + return retcode; +} + +static void *dmxBackendTestEvents(DMXScreenInfo *dmxScreen, void *closure) +{ + XEvent *X = (XEvent *)closure; + + if (XCheckNotMaskEvent(dmxScreen->beDisplay, ExposureMask, X)) + return dmxScreen; + return NULL; +} + +static void *dmxBackendTestMotionEvent(DMXScreenInfo *dmxScreen, void *closure) +{ + XEvent *X = (XEvent *)closure; + + if (XCheckTypedEvent(dmxScreen->beDisplay, MotionNotify, X)) + return dmxScreen; + return NULL; +} + +static DMXScreenInfo *dmxBackendGetEvent(myPrivate *priv, XEvent *X) +{ + DMXScreenInfo *dmxScreen; + + if ((dmxScreen = dmxPropertyIterate(priv->be, dmxBackendTestEvents, X))) + return dmxScreen; + return NULL; +} + +static DMXScreenInfo *dmxBackendPendingMotionEvent(myPrivate *priv, int save) +{ + DMXScreenInfo *dmxScreen; + XEvent N; + + if ((dmxScreen = dmxPropertyIterate(priv->be, + dmxBackendTestMotionEvent, &N))) { + if (save) XPutBackEvent(dmxScreen->beDisplay, &N); + return dmxScreen; + } + return NULL; +} + +static void *dmxBackendTestWindow(DMXScreenInfo *dmxScreen, void *closure) +{ + Window win = (Window)(long)closure; + if (dmxScreen->scrnWin == win) return dmxScreen; + return NULL; +} + +static DMXScreenInfo *dmxBackendFindWindow(myPrivate *priv, Window win) +{ + return dmxPropertyIterate(priv->be, dmxBackendTestWindow, + (void *)(long)win); +} + +/* If the cursor is over a set of overlapping screens and one of those + * screens takes backend input, then we want that particular screen to + * be current, not one of the other ones. */ +static int dmxBackendFindOverlapping(myPrivate *priv, int screen, int x, int y) +{ + DMXScreenInfo *start = &dmxScreens[screen]; + DMXScreenInfo *pt; + + if (!start->over) return screen; + + for (pt = start->over; /* condition at end of loop */; pt = pt->over) { + if (pt->index == priv->myScreen + && dmxOnScreen(x, y, &dmxScreens[pt->index])) return pt->index; + if (pt == start) break; + } + return screen; +} + +/* Return non-zero if \a x and \a y are off \a screen. */ +static int dmxBackendOffscreen(int screen, int x, int y) +{ + DMXScreenInfo *dmxScreen = &dmxScreens[screen]; + + return (!dmxOnScreen(x, y, dmxScreen)); +} + +/** This routine is called from #dmxCoreMotion for each motion + * event. #x and #y are global coordinants. */ +void dmxBackendUpdatePosition(pointer private, int x, int y) +{ + GETPRIVFROMPRIVATE; + int screen = miPointerGetScreen(inputInfo.pointer)->myNum; + DMXScreenInfo *dmxScreen = &dmxScreens[priv->myScreen]; + int oldRelative = priv->relative; + int topscreen = dmxBackendFindOverlapping(priv, screen, x, y); + int same = dmxBackendSameDisplay(priv, topscreen); + int offscreen = dmxBackendOffscreen(priv->myScreen, x, y); + int offthis = dmxBackendOffscreen(screen, x, y); + + DMXDBG9("dmxBackendUpdatePosition(%d,%d) my=%d mi=%d rel=%d" + " topscreen=%d same=%d offscreen=%d offthis=%d\n", + x, y, priv->myScreen, screen, priv->relative, + topscreen, same, offscreen, offthis); + + if (offscreen) { + /* If the cursor is off the input screen, it should be moving + * relative unless it is visible on a screen of the same display + * (i.e., one that shares the mouse). */ + if (same == 2 && !offthis) { + if (priv->relative) { + DMXDBG0(" Off screen, but not absolute\n"); + priv->relative = 0; + } + } else { + if (!priv->relative) { + DMXDBG0(" Off screen, but not relative\n"); + priv->relative = 1; + } + } + } else { + if (topscreen != screen) { + DMXDBG2(" Using screen %d instead of %d (from mi)\n", + topscreen, screen); + } + if (same) { + if (priv->relative) { + DMXDBG0(" On screen, but not absolute\n"); + priv->relative = 0; + } + } else { + if (!priv->relative) { + DMXDBG0(" Not on screen, but not relative\n"); + priv->relative = 1; + } + } + } + + if (oldRelative != priv->relative) { + DMXDBG2(" Do switch, relative=%d same=%d\n", + priv->relative, same); + /* Discard all pre-switch events */ + dmxSync(dmxScreen, TRUE); + while (dmxBackendPendingMotionEvent(priv, FALSE)); + + if (dmxInput->console && offscreen) { + /* Our special case is a console window and a backend window + * share a display. In this case, the cursor is either on + * the backend window (taking absolute input), or not (in + * which case the cursor needs to be in the console + * window). */ + if (priv->grabbedScreen) { + DMXDBG2(" *** force ungrab on %s, display=%p\n", + priv->grabbedScreen->name, + priv->grabbedScreen->beDisplay); + XUngrabPointer(priv->grabbedScreen->beDisplay, CurrentTime); + dmxSync(priv->grabbedScreen, TRUE); + priv->grabbedScreen = NULL; + } + DMXDBG0(" Capturing console\n"); + dmxConsoleCapture(dmxInput); + } else { + priv->newscreen = 1; + if (priv->relative && !dmxInput->console) { + DMXDBG5(" Hide cursor; warp from %d,%d to %d,%d on %d\n", + priv->lastX, priv->lastY, priv->centerX, priv->centerY, + priv->myScreen); + dmxConsoleUncapture(dmxInput); + dmxHideCursor(dmxScreen); + priv->lastX = priv->centerX; + priv->lastY = priv->centerY; + XWarpPointer(priv->display, None, priv->window, + 0, 0, 0, 0, priv->lastX, priv->lastY); + dmxSync(dmxScreen, TRUE); + } else { + DMXDBG0(" Check cursor\n"); + dmxCheckCursor(); + } + } + } +} + +/** Get events from the X queue on the backend servers and put the + * events into the DMX event queue. */ +void dmxBackendCollectEvents(DevicePtr pDev, + dmxMotionProcPtr motion, + dmxEnqueueProcPtr enqueue, + dmxCheckSpecialProcPtr checkspecial, + DMXBlockType block) +{ + GETPRIVFROMPDEV; + GETDMXINPUTFROMPRIV; + XEvent X; + DMXScreenInfo *dmxScreen; + int left = 0; + int entered = priv->entered; + int ignoreLeave = 0; + int v[2]; + int retcode; + + while ((dmxScreen = dmxBackendGetEvent(priv, &X))) { + switch (X.type) { + case EnterNotify: + dmxCommonSaveState(priv); + if (entered++) + continue; + priv->entered = 1; + ignoreLeave = 1; + DMXDBG5("dmxBackendCollectEvents: Enter %lu %d,%d; GRAB %s %p\n", + X.xcrossing.root, X.xcrossing.x, X.xcrossing.y, + dmxScreen->name, dmxScreen->beDisplay); + XRaiseWindow(dmxScreen->beDisplay, dmxScreen->scrnWin); + priv->grabbedScreen = dmxScreen; + if ((retcode = XGrabPointer(dmxScreen->beDisplay, + dmxScreen->scrnWin, + True, 0, GrabModeAsync, + GrabModeAsync, None, None, + CurrentTime))) { + dmxLog(dmxError, + "XGrabPointer failed during backend enter (%d)\n", + retcode); + } + break; + case LeaveNotify: + if (ignoreLeave) { + ignoreLeave = 0; + continue; + } + dmxCommonRestoreState(priv); + if (left++) + continue; + DMXDBG7("dmxBackendCollectEvents: Leave %lu %d,%d %d %d %s %s\n", + X.xcrossing.root, X.xcrossing.x, X.xcrossing.y, + X.xcrossing.detail, X.xcrossing.focus, + priv->grabbedScreen ? "UNGRAB" : "", + dmxScreen->name); + if (priv->grabbedScreen) { + XUngrabPointer(priv->grabbedScreen->beDisplay, CurrentTime); + dmxSync(priv->grabbedScreen, TRUE); + priv->grabbedScreen = NULL; + } + break; + case MotionNotify: + DMXDBG9("dmxBackendCollectEvents: MotionNotify %d/%d (mi %d)" + " newscreen=%d: %d %d (e=%d; last=%d,%d)\n", + dmxScreen->index, priv->myScreen, + miPointerCurrentScreen()->myNum, + priv->newscreen, + X.xmotion.x, X.xmotion.y, + entered, priv->lastX, priv->lastY); + if (dmxBackendPendingMotionEvent(priv, TRUE)) + continue; + if (!(dmxScreen = dmxBackendFindWindow(priv, X.xmotion.window))) + dmxLog(dmxFatal, + " Event on non-existant window %lu\n", + X.xmotion.window); + if (!priv->relative || dmxInput->console) { + int newX = X.xmotion.x - dmxScreen->rootX; + int newY = X.xmotion.y - dmxScreen->rootY; + + if (!priv->newscreen) { + int width = dmxScreen->rootWidth; + int height = dmxScreen->rootHeight; + if (!newX) newX = -1; + if (newX == width - 1) newX = width; + if (!newY) newY = -1; + if (newY == height - 1) newY = height; + } + priv->newscreen = 0; + v[0] = dmxScreen->rootXOrigin + newX; + v[1] = dmxScreen->rootYOrigin + newY; + DMXDBG8(" Absolute move: %d,%d (r=%dx%d+%d+%d s=%dx%d)\n", + v[0], v[1], + priv->be->rootWidth, priv->be->rootHeight, + priv->be->rootX, priv->be->rootY, + priv->be->scrnWidth, priv->be->scrnHeight); + motion(priv->mou, v, 0, 2, DMX_ABSOLUTE, block); + priv->entered = 0; + } else { + int newX = priv->lastX - X.xmotion.x; + int newY = priv->lastY - X.xmotion.y; + priv->lastX = X.xmotion.x; + priv->lastY = X.xmotion.y; + v[0] = newX; + v[1] = newY; + DMXDBG2(" Relative move: %d, %d\n", v[0], v[1]); + motion(priv->mou, v, 0, 2, DMX_RELATIVE, block); + } + if (entered && priv->relative) { + DMXDBG4(" **** Relative %d %d instead of absolute %d %d\n", + v[0], v[1], + (dmxScreen->rootXOrigin + X.xmotion.x + - dmxScreen->rootX), + (dmxScreen->rootYOrigin + X.xmotion.y + - dmxScreen->rootY)); + } + break; + + case KeyPress: + case KeyRelease: + enqueue(priv->kbd, X.type, X.xkey.keycode, 0, NULL, block); + break; + case ButtonPress: + case ButtonRelease: + /* fall-through */ + default: + /* Pass the whole event here, because + * this may be an extension event. */ + enqueue(priv->mou, X.type, X.xbutton.button, 0, &X, block); + break; + } + } +} + +/** Called after input events are processed from the DMX queue. No + * event processing actually takes place here, but this is a convenient + * place to update the pointer. */ +void dmxBackendProcessInput(pointer private) +{ + GETPRIVFROMPRIVATE; + + DMXDBG6("dmxBackendProcessInput: myScreen=%d relative=%d" + " last=%d,%d center=%d,%d\n", + priv->myScreen, priv->relative, + priv->lastX, priv->lastY, + priv->centerX, priv->centerY); + + if (priv->relative + && !dmxInput->console + && (priv->lastX != priv->centerX || priv->lastY != priv->centerY)) { + DMXDBG4(" warping pointer from last=%d,%d to center=%d,%d\n", + priv->lastX, priv->lastY, priv->centerX, priv->centerY); + priv->lastX = priv->centerX; + priv->lastY = priv->centerY; + XWarpPointer(priv->display, None, priv->window, + 0, 0, 0, 0, priv->lastX, priv->lastY); + dmxSync(&dmxScreens[priv->myScreen], TRUE); + } +} + +static void dmxBackendComputeCenter(myPrivate *priv) +{ + int centerX; + int centerY; + + centerX = priv->be->rootWidth / 2 + priv->be->rootX; + centerY = priv->be->rootHeight / 2 + priv->be->rootY; + + if (centerX > priv->be->rootWidth) centerX = priv->be->rootWidth - 1; + if (centerY > priv->be->rootHeight) centerY = priv->be->rootHeight - 1; + if (centerX < 1) centerX = 1; + if (centerY < 1) centerY = 1; + + priv->centerX = centerX; + priv->centerY = centerY; +} + +static DMXScreenInfo *dmxBackendInitPrivate(DevicePtr pDev) +{ + GETPRIVFROMPDEV; + DMXInputInfo *dmxInput = &dmxInputs[dmxLocal->inputIdx]; + DMXScreenInfo *dmxScreen; + int i; + + /* Fill in myPrivate */ + for (i = 0,dmxScreen = &dmxScreens[0]; i<dmxNumScreens; i++,dmxScreen++) { + if (dmxPropertySameDisplay(dmxScreen, dmxInput->name)) { + priv->display = dmxScreen->beDisplay; + priv->window = dmxScreen->scrnWin; + priv->be = dmxScreen; + break; + } + } + + if (i >= dmxNumScreens) + dmxLog(dmxFatal, + "%s is not an existing backend display - cannot initialize\n", + dmxInput->name); + + return dmxScreen; +} + +/** Re-initialized the backend device described by \a pDev (after a + * reconfig). */ +void dmxBackendLateReInit(DevicePtr pDev) +{ + GETPRIVFROMPDEV; + int x, y; + + DMXDBG1("dmxBackendLateReInit miPointerCurrentScreen() = %p\n", + miPointerCurrentScreen()); + + dmxBackendSameDisplay(NULL, 0); /* Invalidate cache */ + dmxBackendInitPrivate(pDev); + dmxBackendComputeCenter(priv); + dmxGetGlobalPosition(&x, &y); + dmxInvalidateGlobalPosition(); /* To force event processing */ + dmxBackendUpdatePosition(priv, x, y); +} + +/** Initialized the backend device described by \a pDev. */ +void dmxBackendInit(DevicePtr pDev) +{ + GETPRIVFROMPDEV; + DMXScreenInfo *dmxScreen; + + dmxBackendSameDisplay(NULL, 0); /* Invalidate cache */ + + if (dmxLocal->type == DMX_LOCAL_MOUSE) priv->mou = pDev; + if (dmxLocal->type == DMX_LOCAL_KEYBOARD) priv->kbd = pDev; + if (priv->initialized++) return; /* Only do once for mouse/keyboard pair */ + + dmxScreen = dmxBackendInitPrivate(pDev); + + /* Finish initialization using computed values or constants. */ + dmxBackendComputeCenter(priv); + priv->eventMask = (EnterWindowMask|LeaveWindowMask); + priv->myScreen = dmxScreen->index; + priv->lastX = priv->centerX; + priv->lastY = priv->centerY; + priv->relative = 0; + priv->newscreen = 0; +} + +/** Get information about the backend pointer (for initialization). */ +void dmxBackendMouGetInfo(DevicePtr pDev, DMXLocalInitInfoPtr info) +{ + const DMXScreenInfo *dmxScreen = dmxBackendInitPrivate(pDev); + + info->buttonClass = 1; + dmxCommonMouGetMap(pDev, info->map, &info->numButtons); + info->valuatorClass = 1; + info->numRelAxes = 2; + info->minval[0] = 0; + info->minval[1] = 0; + info->maxval[0] = dmxScreen->beWidth; + info->maxval[1] = dmxScreen->beHeight; + info->res[0] = 1; + info->minres[0] = 0; + info->maxres[0] = 1; + info->ptrFeedbackClass = 1; +} + +/** Get information about the backend keyboard (for initialization). */ +void dmxBackendKbdGetInfo(DevicePtr pDev, DMXLocalInitInfoPtr info) +{ + dmxCommonKbdGetInfo(pDev, info); + info->keyboard = 1; + info->keyClass = 1; + dmxCommonKbdGetMap(pDev, &info->keySyms, info->modMap); + info->freemap = 1; + info->focusClass = 1; + info->kbdFeedbackClass = 1; +} + +/** Process #DMXFunctionType functions. The only function handled here + * is to acknowledge a pending server shutdown. */ +int dmxBackendFunctions(pointer private, DMXFunctionType function) +{ + switch (function) { + case DMX_FUNCTION_TERMINATE: + return 1; + default: + return 0; + } +} diff --git a/xorg-server/hw/dmx/input/dmxbackend.h b/xorg-server/hw/dmx/input/dmxbackend.h new file mode 100644 index 000000000..ee78f0014 --- /dev/null +++ b/xorg-server/hw/dmx/input/dmxbackend.h @@ -0,0 +1,56 @@ +/* + * Copyright 2002 Red Hat Inc., Durham, North Carolina. + * + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation on the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NON-INFRINGEMENT. IN NO EVENT SHALL RED HAT AND/OR THEIR SUPPLIERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* + * Authors: + * Rickard E. (Rik) Faith <faith@redhat.com> + * + */ + +/** \file + * Interface to backend input device support. \see dmxbackend.c \see + * dmxcommon.c */ + +#ifndef _DMXBACKEND_H_ +#define _DMXBACKEND_H_ + +extern pointer dmxBackendCreatePrivate(DeviceIntPtr pDevice); +extern void dmxBackendDestroyPrivate(pointer private); +extern void dmxBackendInit(DevicePtr pDev); +extern void dmxBackendLateReInit(DevicePtr pDev); +extern void dmxBackendMouGetInfo(DevicePtr pDev, DMXLocalInitInfoPtr info); +extern void dmxBackendKbdGetInfo(DevicePtr pDev, DMXLocalInitInfoPtr info); +extern void dmxBackendCollectEvents(DevicePtr pDev, + dmxMotionProcPtr motion, + dmxEnqueueProcPtr enqueue, + dmxCheckSpecialProcPtr checkspecial, + DMXBlockType block); +extern void dmxBackendProcessInput(pointer private); +extern int dmxBackendFunctions(pointer private, DMXFunctionType function); +extern void dmxBackendUpdatePosition(pointer private, int x, int y); + +#endif diff --git a/xorg-server/hw/dmx/input/dmxcommon.c b/xorg-server/hw/dmx/input/dmxcommon.c new file mode 100644 index 000000000..e77bb7918 --- /dev/null +++ b/xorg-server/hw/dmx/input/dmxcommon.c @@ -0,0 +1,677 @@ +/* + * Copyright 2001-2003 Red Hat Inc., Durham, North Carolina. + * + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation on the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NON-INFRINGEMENT. IN NO EVENT SHALL RED HAT AND/OR THEIR SUPPLIERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* + * Authors: + * David H. Dawes <dawes@xfree86.org> + * Kevin E. Martin <kem@redhat.com> + * Rickard E. (Rik) Faith <faith@redhat.com> + */ + +/** \file + * + * This file implements common routines used by the backend and console + * input devices. + */ + +#ifdef HAVE_DMX_CONFIG_H +#include <dmx-config.h> +#endif + +#define DMX_STATE_DEBUG 0 + +#include "dmxinputinit.h" +#include "dmxcommon.h" +#include "dmxconsole.h" +#include "dmxprop.h" +#include "dmxsync.h" +#include "dmxmap.h" + +#include "inputstr.h" +#include "input.h" +#include <X11/keysym.h> +#include "mipointer.h" +#include "scrnintstr.h" + +#include <unistd.h> /* For usleep() */ + +#if DMX_STATE_DEBUG +#define DMXDBG0(f) dmxLog(dmxDebug,f) +#else +#define DMXDBG0(f) +#endif + +/** Each device has a private area that is visible only from inside the + * driver code. */ +typedef struct _myPrivate { + DMX_COMMON_PRIVATE; +} myPrivate; + +static void dmxCommonKbdSetAR(Display *display, + unsigned char *old, unsigned char *new) +{ + XKeyboardControl kc; + XKeyboardState ks; + unsigned long mask = KBKey | KBAutoRepeatMode; + int i, j; + int minKeycode, maxKeycode; + + if (!old) { + XGetKeyboardControl(display, &ks); + old = (unsigned char *)ks.auto_repeats; + } + + XDisplayKeycodes(display, &minKeycode, &maxKeycode); + for (i = 1; i < 32; i++) { + if (!old || old[i] != new[i]) { + for (j = 0; j < 8; j++) { + if ((new[i] & (1 << j)) != (old[i] & (1 << j))) { + kc.key = i * 8 + j; + kc.auto_repeat_mode = ((new[i] & (1 << j)) + ? AutoRepeatModeOn + : AutoRepeatModeOff); + if (kc.key >= minKeycode && kc.key <= maxKeycode) + XChangeKeyboardControl(display, mask, &kc); + } + } + } + } +} + +static void dmxCommonKbdSetLeds(Display *display, unsigned long new) +{ + int i; + XKeyboardControl kc; + + for (i = 0; i < 32; i++) { + kc.led = i + 1; + kc.led_mode = (new & (1 << i)) ? LedModeOn : LedModeOff; + XChangeKeyboardControl(display, KBLed | KBLedMode, &kc); + } +} + +static void dmxCommonKbdSetCtrl(Display *display, + KeybdCtrl *old, KeybdCtrl *new) +{ + XKeyboardControl kc; + unsigned long mask = KBKeyClickPercent | KBAutoRepeatMode; + + if (!old + || old->click != new->click + || old->autoRepeat != new->autoRepeat) { + + kc.key_click_percent = new->click; + kc.auto_repeat_mode = new->autoRepeat; + + XChangeKeyboardControl(display, mask, &kc); + } + + dmxCommonKbdSetLeds(display, new->leds); + dmxCommonKbdSetAR(display, old ? old->autoRepeats : NULL, + new->autoRepeats); +} + +static void dmxCommonMouSetCtrl(Display *display, PtrCtrl *old, PtrCtrl *new) +{ + Bool do_accel, do_threshold; + + if (!old + || old->num != new->num + || old->den != new->den + || old->threshold != new->threshold) { + do_accel = (new->num > 0 && new->den > 0); + do_threshold = (new->threshold > 0); + if (do_accel || do_threshold) { + XChangePointerControl(display, do_accel, do_threshold, + new->num, new->den, new->threshold); + } + } +} + +/** Update the keyboard control. */ +void dmxCommonKbdCtrl(DevicePtr pDev, KeybdCtrl *ctrl) +{ + GETPRIVFROMPDEV; + + if (!priv->stateSaved && priv->be) dmxCommonSaveState(priv); + if (!priv->display || !priv->stateSaved) return; + dmxCommonKbdSetCtrl(priv->display, + priv->kctrlset ? &priv->kctrl : NULL, + ctrl); + priv->kctrl = *ctrl; + priv->kctrlset = 1; +} + +/** Update the mouse control. */ +void dmxCommonMouCtrl(DevicePtr pDev, PtrCtrl *ctrl) +{ + GETPRIVFROMPDEV; + + /* Don't set the acceleration for the + * console, because that should be + * controlled by the X server that the + * console is running on. Otherwise, + * the acceleration for the console + * window would be unexpected for the + * scale of the window. */ + if (priv->be) { + dmxCommonMouSetCtrl(priv->display, + priv->mctrlset ? &priv->mctrl : NULL, + ctrl); + priv->mctrl = *ctrl; + priv->mctrlset = 1; + } +} + +/** Sound they keyboard bell. */ +void dmxCommonKbdBell(DevicePtr pDev, int percent, + int volume, int pitch, int duration) +{ + GETPRIVFROMPDEV; + XKeyboardControl kc; + XKeyboardState ks; + unsigned long mask = KBBellPercent | KBBellPitch | KBBellDuration; + + if (!priv->be) XGetKeyboardControl(priv->display, &ks); + kc.bell_percent = volume; + kc.bell_pitch = pitch; + kc.bell_duration = duration; + XChangeKeyboardControl(priv->display, mask, &kc); + XBell(priv->display, percent); + if (!priv->be) { + kc.bell_percent = ks.bell_percent; + kc.bell_pitch = ks.bell_pitch; + kc.bell_duration = ks.bell_duration; + XChangeKeyboardControl(priv->display, mask, &kc); + } +} + +/** Get the keyboard mapping. */ +void dmxCommonKbdGetMap(DevicePtr pDev, KeySymsPtr pKeySyms, CARD8 *pModMap) +{ + GETPRIVFROMPDEV; + int min_keycode; + int max_keycode; + int map_width; + KeySym *keyboard_mapping; + XModifierKeymap *modifier_mapping; + int i, j; + + /* Compute pKeySyms. Cast + * XGetKeyboardMapping because of + * compiler warning on 64-bit machines. + * We assume pointers to 32-bit and + * 64-bit ints are the same. */ + XDisplayKeycodes(priv->display, &min_keycode, &max_keycode); + keyboard_mapping = (KeySym *)XGetKeyboardMapping(priv->display, + min_keycode, + max_keycode + - min_keycode + 1, + &map_width); + pKeySyms->minKeyCode = min_keycode; + pKeySyms->maxKeyCode = max_keycode; + pKeySyms->mapWidth = map_width; + pKeySyms->map = keyboard_mapping; + + + /* Compute pModMap */ + modifier_mapping = XGetModifierMapping(priv->display); + for (i = 0; i < MAP_LENGTH; i++) + pModMap[i] = 0; + for (j = 0; j < 8; j++) { + int max_keypermod = modifier_mapping->max_keypermod; + + for (i = 0; i < max_keypermod; i++) { + CARD8 keycode = modifier_mapping->modifiermap[j*max_keypermod + i]; + if (keycode) + pModMap[keycode] |= 1 << j; + } + } + XFreeModifiermap(modifier_mapping); +} + +/** Fill in the XKEYBOARD parts of the \a info structure for the + * specified \a pDev. */ +void dmxCommonKbdGetInfo(DevicePtr pDev, DMXLocalInitInfoPtr info) +{ +#ifdef XKB + GETPRIVFROMPDEV; + GETDMXINPUTFROMPRIV; + char *pt; + + dmxCommonSaveState(priv); + if (priv->xkb) { + info->names.keymap = NULL; +#define NAME(x) \ + priv->xkb->names->x ? XGetAtomName(priv->display,priv->xkb->names->x) : NULL + info->names.keycodes = NAME(keycodes); + info->names.types = NAME(types); + info->names.compat = NAME(compat); + info->names.symbols = NAME(symbols); + info->names.geometry = NAME(geometry); + info->freenames = 1; +#undef NAME + dmxLogInput(dmxInput, + "XKEYBOARD: keycodes = %s\n", info->names.keycodes); + dmxLogInput(dmxInput, + "XKEYBOARD: symbols = %s\n", info->names.symbols); + dmxLogInput(dmxInput, + "XKEYBOARD: geometry = %s\n", info->names.geometry); + if ((pt = strchr(info->names.keycodes, '+'))) *pt = '\0'; + } + dmxCommonRestoreState(priv); +#endif +} + +/** Turn \a pDev on (i.e., take input from \a pDev). */ +int dmxCommonKbdOn(DevicePtr pDev) +{ + GETPRIVFROMPDEV; + if (priv->be) dmxCommonSaveState(priv); + priv->eventMask |= DMX_KEYBOARD_EVENT_MASK; + XSelectInput(priv->display, priv->window, priv->eventMask); + if (priv->be) + XSetInputFocus(priv->display, priv->window, RevertToPointerRoot, + CurrentTime); + return -1; +} + +/** Turn \a pDev off. */ +void dmxCommonKbdOff(DevicePtr pDev) +{ + GETPRIVFROMPDEV; + priv->eventMask &= ~DMX_KEYBOARD_EVENT_MASK; + XSelectInput(priv->display, priv->window, priv->eventMask); + dmxCommonRestoreState(priv); +} + +/** Turn \a pDev on (i.e., take input from \a pDev). */ +int dmxCommonOthOn(DevicePtr pDev) +{ + GETPRIVFROMPDEV; + GETDMXINPUTFROMPRIV; + XEventClass event_list[DMX_MAX_XINPUT_EVENT_TYPES]; + int event_type[DMX_MAX_XINPUT_EVENT_TYPES]; + int count = 0; + +#define ADD(type) \ + if (count < DMX_MAX_XINPUT_EVENT_TYPES) { \ + type(priv->xi, event_type[count], event_list[count]); \ + if (event_type[count]) { \ + dmxMapInsert(dmxLocal, event_type[count], XI_##type); \ + ++count; \ + } \ + } else { \ + dmxLog(dmxWarning, "More than %d event types for %s\n", \ + DMX_MAX_XINPUT_EVENT_TYPES, dmxInput->name); \ + } + + if (!(priv->xi = XOpenDevice(priv->display, dmxLocal->deviceId))) { + dmxLog(dmxWarning, "Cannot open %s device (id=%d) on %s\n", + dmxLocal->deviceName ? dmxLocal->deviceName : "(unknown)", + dmxLocal->deviceId, dmxInput->name); + return -1; + } + ADD(DeviceKeyPress); + ADD(DeviceKeyRelease); + ADD(DeviceButtonPress); + ADD(DeviceButtonRelease); + ADD(DeviceMotionNotify); + ADD(DeviceFocusIn); + ADD(DeviceFocusOut); + ADD(ProximityIn); + ADD(ProximityOut); + ADD(DeviceStateNotify); + ADD(DeviceMappingNotify); + ADD(ChangeDeviceNotify); + XSelectExtensionEvent(priv->display, priv->window, event_list, count); + + return -1; +} + +/** Turn \a pDev off. */ +void dmxCommonOthOff(DevicePtr pDev) +{ + GETPRIVFROMPDEV; + + if (priv->xi) XCloseDevice(priv->display, priv->xi); + priv->xi = NULL; +} + +/** Fill the \a info structure with information needed to initialize \a + * pDev. */ +void dmxCommonOthGetInfo(DevicePtr pDev, DMXLocalInitInfoPtr info) +{ + GETPRIVFROMPDEV; + GETDMXINPUTFROMPRIV; + XExtensionVersion *ext; + XDeviceInfo *devices; + Display *display = priv->display; + int num; + int i, j, k; + int (*handler)(Display *, char *, char *); + + if (!display && !(display = XOpenDisplay(dmxInput->name))) + return; + + /* Print out information about the XInput Extension. */ + handler = XSetExtensionErrorHandler(dmxInputExtensionErrorHandler); + ext = XGetExtensionVersion(display, INAME); + XSetExtensionErrorHandler(handler); + + if (ext && ext != (XExtensionVersion *)NoSuchExtension) { + XFree(ext); + devices = XListInputDevices(display, &num); + for (i = 0; i < num; i++) { + if (devices[i].id == (XID)dmxLocal->deviceId) { + XAnyClassPtr any; + XKeyInfoPtr ki; + XButtonInfoPtr bi; + XValuatorInfoPtr vi; + for (j = 0, any = devices[i].inputclassinfo; + j < devices[i].num_classes; + any = (XAnyClassPtr)((char *)any + any->length), j++) { + switch (any->class) { + case KeyClass: + ki = (XKeyInfoPtr)any; + info->keyboard = 1; + info->keyClass = 1; + info->keySyms.minKeyCode = ki->min_keycode; + info->keySyms.maxKeyCode = ki->max_keycode; + info->kbdFeedbackClass = 1; + break; + case ButtonClass: + bi = (XButtonInfoPtr)any; + info->buttonClass = 1; + info->numButtons = bi->num_buttons; + info->ptrFeedbackClass = 1; + break; + case ValuatorClass: + /* This assume all axes are either + * Absolute or Relative. */ + vi = (XValuatorInfoPtr)any; + info->valuatorClass = 1; + if (vi->mode == Absolute) + info->numAbsAxes = vi->num_axes; + else + info->numRelAxes = vi->num_axes; + for (k = 0; k < vi->num_axes; k++) { + info->res[k] = vi->axes[k].resolution; + info->minres[k] = vi->axes[k].resolution; + info->maxres[k] = vi->axes[k].resolution; + info->minval[k] = vi->axes[k].min_value; + info->maxval[k] = vi->axes[k].max_value; + } + break; + case FeedbackClass: + /* Only keyboard and pointer feedback + * are handled at this time. */ + break; + case ProximityClass: + info->proximityClass = 1; + break; + case FocusClass: + info->focusClass = 1; + break; + case OtherClass: + break; + } + } + } + } + XFreeDeviceList(devices); + } + if (display != priv->display) XCloseDisplay(display); +} + +/** Obtain the mouse button mapping. */ +void dmxCommonMouGetMap(DevicePtr pDev, unsigned char *map, int *nButtons) +{ + GETPRIVFROMPDEV; + int i; + + *nButtons = XGetPointerMapping(priv->display, map, DMX_MAX_BUTTONS); + for (i = 0; i <= *nButtons; i++) map[i] = i; +} + +static void *dmxCommonXSelect(DMXScreenInfo *dmxScreen, void *closure) +{ + myPrivate *priv = closure; + XSelectInput(dmxScreen->beDisplay, dmxScreen->scrnWin, priv->eventMask); + return NULL; +} + +static void *dmxCommonAddEnabledDevice(DMXScreenInfo *dmxScreen, void *closure) +{ + AddEnabledDevice(XConnectionNumber(dmxScreen->beDisplay)); + return NULL; +} + +static void *dmxCommonRemoveEnabledDevice(DMXScreenInfo *dmxScreen, + void *closure) +{ + RemoveEnabledDevice(XConnectionNumber(dmxScreen->beDisplay)); + return NULL; +} + +/** Turn \a pDev on (i.e., take input from \a pDev). */ +int dmxCommonMouOn(DevicePtr pDev) +{ + GETPRIVFROMPDEV; + GETDMXINPUTFROMPRIV; + + priv->eventMask |= DMX_POINTER_EVENT_MASK; + if (dmxShadowFB) { + XWarpPointer(priv->display, priv->window, priv->window, + 0, 0, 0, 0, + priv->initPointerX, + priv->initPointerY); + dmxSync(&dmxScreens[dmxInput->scrnIdx], TRUE); + } + if (!priv->be) { + XSelectInput(priv->display, priv->window, priv->eventMask); + AddEnabledDevice(XConnectionNumber(priv->display)); + } else { + dmxPropertyIterate(priv->be, dmxCommonXSelect, priv); + dmxPropertyIterate(priv->be, dmxCommonAddEnabledDevice, dmxInput); + } + + return -1; +} + +/** Turn \a pDev off. */ +void dmxCommonMouOff(DevicePtr pDev) +{ + GETPRIVFROMPDEV; + GETDMXINPUTFROMPRIV; + + priv->eventMask &= ~DMX_POINTER_EVENT_MASK; + if (!priv->be) { + RemoveEnabledDevice(XConnectionNumber(priv->display)); + XSelectInput(priv->display, priv->window, priv->eventMask); + } else { + dmxPropertyIterate(priv->be, dmxCommonRemoveEnabledDevice, dmxInput); + dmxPropertyIterate(priv->be, dmxCommonXSelect, priv); + } +} + +/** Given the global coordinates \a x and \a y, determine the screen + * with the lowest number on which those coordinates lie. If they are + * not on any screen, return -1. The number returned is an index into + * #dmxScreenInfo and is between -1 and #dmxNumScreens - 1, + * inclusive. */ +int dmxFindPointerScreen(int x, int y) +{ + int i; + + for (i = 0; i < dmxNumScreens; i++) { + if (x >= dixScreenOrigins[i].x + && x < dixScreenOrigins[i].x + screenInfo.screens[i]->width + && y >= dixScreenOrigins[i].y + && y < dixScreenOrigins[i].y + screenInfo.screens[i]->height) + return i; + } + return -1; +} + +/** Returns a pointer to the private area for the device that comes just + * prior to \a pDevice in the current \a dmxInput device list. This is + * used as the private area for the current device in some situations + * (e.g., when a keyboard and mouse form a pair that should share the + * same private area). If the requested private area cannot be located, + * then NULL is returned. */ +pointer dmxCommonCopyPrivate(DeviceIntPtr pDevice) +{ + GETDMXLOCALFROMPDEVICE; + DMXInputInfo *dmxInput = &dmxInputs[dmxLocal->inputIdx]; + int i; + + for (i = 0; i < dmxInput->numDevs; i++) + if (dmxInput->devs[i] == dmxLocal && i) + return dmxInput->devs[i-1]->private; + return NULL; +} + +/** This routine saves and resets some important state for the backend + * and console device drivers: + * - the modifier map is saved and set to 0 (so DMX controls the LEDs) + * - the key click, bell, led, and repeat masks are saved and set to the + * values that DMX claims to be using + * + * This routine and #dmxCommonRestoreState are used when the pointer + * enters and leaves the console window, or when the backend window is + * active or not active (for a full-screen window, this only happens at + * server startup and server shutdown). + */ +void dmxCommonSaveState(pointer private) +{ + GETPRIVFROMPRIVATE; + XKeyboardState ks; + unsigned long i; + XModifierKeymap *modmap; + + if (dmxInput->console) priv = dmxInput->devs[0]->private; + if (!priv->display || priv->stateSaved) return; + DMXDBG0("dmxCommonSaveState\n"); +#ifdef XKB + if (dmxUseXKB && (priv->xkb = XkbAllocKeyboard())) { + if (XkbGetIndicatorMap(priv->display, XkbAllIndicatorsMask, priv->xkb) + || XkbGetNames(priv->display, XkbAllNamesMask, priv->xkb)) { + dmxLogInput(dmxInput, "Could not get XKB information\n"); + XkbFreeKeyboard(priv->xkb, 0, True); + priv->xkb = NULL; + } else { + if (priv->xkb->indicators) { + priv->savedIndicators = *priv->xkb->indicators; + for (i = 0; i < XkbNumIndicators; i++) + if (priv->xkb->indicators->phys_indicators & (1 << i)) { + priv->xkb->indicators->maps[i].flags + = XkbIM_NoAutomatic; + } + XkbSetIndicatorMap(priv->display, ~0, priv->xkb); + } + } + } +#endif + + XGetKeyboardControl(priv->display, &ks); + priv->savedKctrl.click = ks.key_click_percent; + priv->savedKctrl.bell = ks.bell_percent; + priv->savedKctrl.bell_pitch = ks.bell_pitch; + priv->savedKctrl.bell_duration = ks.bell_duration; + priv->savedKctrl.leds = ks.led_mask; + priv->savedKctrl.autoRepeat = ks.global_auto_repeat; + for (i = 0; i < 32; i++) + priv->savedKctrl.autoRepeats[i] = ks.auto_repeats[i]; + + dmxCommonKbdSetCtrl(priv->display, &priv->savedKctrl, + &priv->dmxLocal->kctrl); + + priv->savedModMap = XGetModifierMapping(priv->display); + + modmap = XNewModifiermap(0); + XSetModifierMapping(priv->display, modmap); + if (dmxInput->scrnIdx != -1) + dmxSync(&dmxScreens[dmxInput->scrnIdx], TRUE); + XFreeModifiermap(modmap); + + priv->stateSaved = 1; +} + +/** This routine restores all the information saved by #dmxCommonSaveState. */ +void dmxCommonRestoreState(pointer private) +{ + GETPRIVFROMPRIVATE; + int retcode = -1; + CARD32 start; + + if (dmxInput->console) + priv = dmxInput->devs[0]->private; + if (!priv->stateSaved) + return; + priv->stateSaved = 0; + + DMXDBG0("dmxCommonRestoreState\n"); +#ifdef XKB + if (priv->xkb) { + *priv->xkb->indicators = priv->savedIndicators; + XkbSetIndicatorMap(priv->display, ~0, priv->xkb); + XkbFreeKeyboard(priv->xkb, 0, True); + priv->xkb = 0; + } +#endif + + for (start = GetTimeInMillis(); GetTimeInMillis() - start < 5000;) { + CARD32 tmp; + + retcode = XSetModifierMapping(priv->display, priv->savedModMap); + if (retcode == MappingSuccess) + break; + if (retcode == MappingBusy) + dmxLogInput(dmxInput, "Keyboard busy, waiting\n"); + else + dmxLogInput(dmxInput, "Keyboard error, waiting\n"); + + /* Don't generate X11 protocol for a bit */ + for (tmp = GetTimeInMillis(); GetTimeInMillis() - tmp < 250;) { + usleep(250); /* This ends up sleeping only until + * the next key press generates an + * interruption. We make the delay + * relatively short in case the user + * pressed they keys quickly. */ + } + + } + if (retcode != MappingSuccess) + dmxLog(dmxWarning, "Unable to restore keyboard modifier state!\n"); + + XFreeModifiermap(priv->savedModMap); + priv->savedModMap = NULL; + + dmxCommonKbdSetCtrl(priv->display, NULL, &priv->savedKctrl); + priv->kctrlset = 0; /* Invalidate copy */ +} diff --git a/xorg-server/hw/dmx/input/dmxcommon.h b/xorg-server/hw/dmx/input/dmxcommon.h new file mode 100644 index 000000000..1cc935d0b --- /dev/null +++ b/xorg-server/hw/dmx/input/dmxcommon.h @@ -0,0 +1,132 @@ +/* + * Copyright 2002,2003 Red Hat Inc., Durham, North Carolina. + * + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation on the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NON-INFRINGEMENT. IN NO EVENT SHALL RED HAT AND/OR THEIR SUPPLIERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* + * Authors: + * Rickard E. (Rik) Faith <faith@redhat.com> + * + */ + +/** \file + * Interface to functions used by backend and console input devices. + * \see dmxcommon.c \see dmxbackend.c \see dmxconsole.c */ + +#ifndef _DMXCOMMON_H_ +#define _DMXCOMMON_H_ + +#define DMX_COMMON_OTHER \ + Display *display; \ + Window window; \ + DMXScreenInfo *be; \ + DMXLocalInputInfoPtr dmxLocal; \ + int initPointerX; \ + int initPointerY; \ + long eventMask; \ + KeybdCtrl kctrl; \ + PtrCtrl mctrl; \ + int kctrlset; \ + int mctrlset; \ + KeybdCtrl savedKctrl; \ + XModifierKeymap *savedModMap; \ + int stateSaved + +#ifdef XKB +#define DMX_COMMON_XKB \ + DMX_COMMON_OTHER; \ + XkbDescPtr xkb; \ + XkbIndicatorRec savedIndicators +#else +#define DMX_COMMON_XKB DMX_COMMON_OTHER +#endif + +#ifdef XINPUT +#define DMX_COMMON_PRIVATE \ + DMX_COMMON_XKB; \ + XDevice *xi +#else +#define DMX_COMMON_PRIVATE DMX_COMMON_OTHER +#endif + +#define GETONLYPRIVFROMPRIVATE \ + myPrivate *priv = private + +#define GETPRIVFROMPRIVATE \ + GETONLYPRIVFROMPRIVATE; \ + DMXInputInfo *dmxInput = &dmxInputs[priv->dmxLocal->inputIdx] + +#define GETDMXLOCALFROMPDEVICE \ + DevicePtr pDev = &pDevice->public; \ + DMXLocalInputInfoPtr dmxLocal = pDev->devicePrivate + +#define GETDMXINPUTFROMPRIV \ + DMXInputInfo *dmxInput = &dmxInputs[priv->dmxLocal->inputIdx] + +#define GETDMXINPUTFROMPDEVICE \ + GETDMXLOCALFROMPDEVICE; \ + DMXInputInfo *dmxInput = &dmxInputs[dmxLocal->inputIdx] + +#define GETDMXLOCALFROMPDEV \ + DMXLocalInputInfoPtr dmxLocal = pDev->devicePrivate + +#define GETDMXINPUTFROMPDEV \ + GETDMXLOCALFROMPDEV; \ + DMXInputInfo *dmxInput = &dmxInputs[dmxLocal->inputIdx] + +#define GETPRIVFROMPDEV \ + GETDMXLOCALFROMPDEV; \ + myPrivate *priv = dmxLocal->private + +#define DMX_KEYBOARD_EVENT_MASK \ + (KeyPressMask | KeyReleaseMask | KeymapStateMask) + +#define DMX_POINTER_EVENT_MASK \ + (ButtonPressMask | ButtonReleaseMask | PointerMotionMask) + +extern void dmxCommonKbdGetInfo(DevicePtr pDev, DMXLocalInitInfoPtr info); +extern void dmxCommonKbdGetMap(DevicePtr pDev, + KeySymsPtr pKeySyms, CARD8 *pModMap); +extern void dmxCommonKbdCtrl(DevicePtr pDev, KeybdCtrl *ctrl); +extern void dmxCommonKbdBell(DevicePtr pDev, int percent, + int volume, int pitch, int duration); +extern int dmxCommonKbdOn(DevicePtr pDev); +extern void dmxCommonKbdOff(DevicePtr pDev); +extern void dmxCommonMouGetMap(DevicePtr pDev, + unsigned char *map, int *nButtons); +extern void dmxCommonMouCtrl(DevicePtr pDev, PtrCtrl *ctrl); +extern int dmxCommonMouOn(DevicePtr pDev); +extern void dmxCommonMouOff(DevicePtr pDev); +extern int dmxFindPointerScreen(int x, int y); + +extern int dmxCommonOthOn(DevicePtr pDev); +extern void dmxCommonOthOff(DevicePtr pDev); +extern void dmxCommonOthGetInfo(DevicePtr pDev, DMXLocalInitInfoPtr info); + + /* helper functions */ +extern pointer dmxCommonCopyPrivate(DeviceIntPtr pDevice); +extern void dmxCommonSaveState(pointer private); +extern void dmxCommonRestoreState(pointer private); +#endif diff --git a/xorg-server/hw/dmx/input/dmxconsole.c b/xorg-server/hw/dmx/input/dmxconsole.c new file mode 100644 index 000000000..b2a2ec302 --- /dev/null +++ b/xorg-server/hw/dmx/input/dmxconsole.c @@ -0,0 +1,1031 @@ +/* + * Copyright 2001-2003 Red Hat Inc., Durham, North Carolina. + * + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation on the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NON-INFRINGEMENT. IN NO EVENT SHALL RED HAT AND/OR THEIR SUPPLIERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* + * Authors: + * David H. Dawes <dawes@xfree86.org> + * Kevin E. Martin <kem@redhat.com> + * Rickard E. (Rik) Faith <faith@redhat.com> + * + */ + +/** \file + * + * This file implements the console input devices. + */ + +#ifdef HAVE_DMX_CONFIG_H +#include <dmx-config.h> +#endif + +#define DMX_CONSOLE_DEBUG 0 +#define DMX_WINDOW_DEBUG 0 + +#include "dmxinputinit.h" +#include "dmxevents.h" +#include "dmxconsole.h" +#include "dmxcommon.h" +#include "dmxscrinit.h" +#include "dmxcb.h" +#include "dmxsync.h" + +#include "inputstr.h" +#include "input.h" +#include "mipointer.h" +#include "windowstr.h" + +#define CONSOLE_NUM 3 +#define CONSOLE_DEN 4 +#define DMX_CONSOLE_NAME "DMX Console" +#define DMX_RES_NAME "Xdmx" +#define DMX_RES_CLASS "XDmx" +#define CONSOLE_BG_COLOR "gray75" +#define CONSOLE_FG_COLOR "black" +#define CONSOLE_SCREEN_BG_COLOR "white" +#define CONSOLE_SCREEN_FG_COLOR "black" +#define CONSOLE_SCREEN_DET_COLOR "gray75" +#define CONSOLE_SCREEN_CUR_COLOR "red" + +#if DMX_CONSOLE_DEBUG +#define DMXDBG0(f) dmxLog(dmxDebug,f) +#define DMXDBG1(f,a) dmxLog(dmxDebug,f,a) +#define DMXDBG2(f,a,b) dmxLog(dmxDebug,f,a,b) +#define DMXDBG3(f,a,b,c) dmxLog(dmxDebug,f,a,b,c) +#define DMXDBG4(f,a,b,c,d) dmxLog(dmxDebug,f,a,b,c,d) +#define DMXDBG5(f,a,b,c,d,e) dmxLog(dmxDebug,f,a,b,c,d,e) +#define DMXDBG6(f,a,b,c,d,e,g) dmxLog(dmxDebug,f,a,b,c,d,e,g) +#define DMXDBG7(f,a,b,c,d,e,g,h) dmxLog(dmxDebug,f,a,b,c,d,e,g,h) +#else +#define DMXDBG0(f) +#define DMXDBG1(f,a) +#define DMXDBG2(f,a,b) +#define DMXDBG3(f,a,b,c) +#define DMXDBG4(f,a,b,c,d) +#define DMXDBG5(f,a,b,c,d,e) +#define DMXDBG6(f,a,b,c,d,e,g) +#define DMXDBG7(f,a,b,c,d,e,g,h) +#endif + +/* Private area for consoles. */ +typedef struct _myPrivate { + DMX_COMMON_PRIVATE; + int lastX; + int lastY; + int globalX; + int globalY; + int curX; + int curY; + int width; + int height; + int consWidth; + int consHeight; + double xScale; + double yScale; + XlibGC gc, gcDet, gcRev, gcCur; + int grabbed, fine, captured; + Cursor cursorNormal, cursorGrabbed, cursorEmpty; + Pixmap pixmap; + + CloseScreenProcPtr CloseScreen; + struct _myPrivate *next; /* for closing multiple consoles */ + int initialized; + DevicePtr mou, kbd; +} myPrivate; + +static int scalex(myPrivate *priv, int x) +{ + return (int)((x * priv->xScale) + .5); +} + +static int scaley(myPrivate *priv, int y) +{ + return (int)((y * priv->yScale) + .5); +} + +static int unscalex(myPrivate *priv, int x) +{ + return (int)((x / priv->xScale) + .5); +} + +static int unscaley(myPrivate *priv, int y) +{ + return (int)((y / priv->yScale) + .5); +} + +/** Create the private area for \a pDevice. */ +pointer dmxConsoleCreatePrivate(DeviceIntPtr pDevice) +{ + GETDMXLOCALFROMPDEVICE; + myPrivate *priv = xalloc(sizeof(*priv)); + memset(priv, 0, sizeof(*priv)); + priv->dmxLocal = dmxLocal; + return priv; +} + +/** If \a private is non-NULL, free its associated memory. */ +void dmxConsoleDestroyPrivate(pointer private) +{ + if (private) xfree(private); +} + +static void dmxConsoleDrawFineCursor(myPrivate *priv, XRectangle *rect) +{ + int size = 6; + int x, y; + + XDrawLine(priv->display, priv->pixmap, priv->gcCur, + x = scalex(priv, priv->globalX) - size, + scaley(priv, priv->globalY), + scalex(priv, priv->globalX) + size, + scaley(priv, priv->globalY)); + XDrawLine(priv->display, priv->pixmap, priv->gcCur, + scalex(priv, priv->globalX), + y = scaley(priv, priv->globalY) - size, + scalex(priv, priv->globalX), + scaley(priv, priv->globalY) + size); + if (priv->grabbed) { + XDrawLine(priv->display, priv->pixmap, priv->gcCur, + scalex(priv, priv->globalX) - (int)(size / 1.4), + scaley(priv, priv->globalY) - (int)(size / 1.4), + scalex(priv, priv->globalX) + (int)(size / 1.4), + scaley(priv, priv->globalY) + (int)(size / 1.4)); + XDrawLine(priv->display, priv->pixmap, priv->gcCur, + scalex(priv, priv->globalX) - (int)(size / 1.4), + scaley(priv, priv->globalY) + (int)(size / 1.4), + scalex(priv, priv->globalX) + (int)(size / 1.4), + scaley(priv, priv->globalY) - (int)(size / 1.4)); + } + if (rect) { + rect->x = x; + rect->y = y; + rect->width = 2 * size; + rect->height = 2 * size; + } +} + +static void dmxConsoleDrawWindows(pointer private) +{ + GETONLYPRIVFROMPRIVATE; + Display *dpy = priv->display; + int i; + Region whole, used, avail; + XRectangle rect; + + whole = XCreateRegion(); + used = XCreateRegion(); + avail = XCreateRegion(); + rect.x = 0; + rect.y = 0; + rect.width = priv->consWidth; + rect.height = priv->consHeight; + XUnionRectWithRegion(&rect, whole, whole); + + for (i = 0; i < dmxNumScreens; i++) { + WindowPtr pRoot = WindowTable[i]; + WindowPtr pChild; + +#if DMX_WINDOW_DEBUG + dmxLog(dmxDebug, "%lu %p %p %p 2\n", + pRoot->drawable.id, + pRoot->parent, pRoot->firstChild, pRoot->lastChild); +#endif + + for (pChild = pRoot->firstChild; pChild; pChild = pChild->nextSib) { + if (pChild->mapped + && pChild->realized) { +#if DMX_WINDOW_DEBUG + dmxLog(dmxDebug, " %p %d,%d %dx%d %d %d %d RECTS\n", + pChild, + pChild->drawable.x, + pChild->drawable.y, + pChild->drawable.width, + pChild->drawable.height, + pChild->visibility, + pChild->overrideRedirect, + REGION_NUM_RECTS(&pChild->clipList)); +#endif + rect.x = scalex(priv, pChild->drawable.x + + dixScreenOrigins[i].x); + rect.y = scaley(priv, pChild->drawable.y + + dixScreenOrigins[i].y); + rect.width = scalex(priv, pChild->drawable.width); + rect.height = scaley(priv, pChild->drawable.height); + XDrawRectangle(dpy, priv->pixmap, priv->gc, + rect.x, rect.y, rect.width, rect.height); + XUnionRectWithRegion(&rect, used, used); + XSubtractRegion(whole, used, avail); + XSetRegion(dpy, priv->gc, avail); + } + } +#ifdef PANORAMIX + if (!noPanoramiXExtension) break; /* Screen 0 valid with Xinerama */ +#endif + } + XDestroyRegion(avail); + XDestroyRegion(used); + XDestroyRegion(whole); + XSetClipMask(dpy, priv->gc, None); +} + +static void dmxConsoleDraw(myPrivate *priv, int updateCursor, int update) +{ + GETDMXINPUTFROMPRIV; + Display *dpy = priv->display; + int i; + + XFillRectangle(dpy, priv->pixmap, priv->gc, 0, 0, + priv->consWidth, priv->consHeight); + + for (i = 0; i < dmxNumScreens; i++) { + DMXScreenInfo *dmxScreen = &dmxScreens[i]; + XFillRectangle(dpy, priv->pixmap, + dmxScreen->beDisplay ? priv->gcRev : priv->gcDet, + scalex(priv, dixScreenOrigins[i].x), + scaley(priv, dixScreenOrigins[i].y), + scalex(priv, screenInfo.screens[i]->width), + scaley(priv, screenInfo.screens[i]->height)); + } + for (i = 0; i < dmxNumScreens; i++) { + XDrawRectangle(dpy, priv->pixmap, priv->gc, + scalex(priv, dixScreenOrigins[i].x), + scaley(priv, dixScreenOrigins[i].y), + scalex(priv, screenInfo.screens[i]->width), + scaley(priv, screenInfo.screens[i]->height)); + } + if (dmxInput->windows) dmxConsoleDrawWindows(priv); + if (priv->fine && updateCursor) dmxConsoleDrawFineCursor(priv, 0); + if (update) { + XCopyArea(priv->display, priv->pixmap, priv->window, priv->gc, + 0, 0, priv->consWidth, priv->consHeight, 0, 0); + XSync(priv->display, False); /* Not a backend display */ + } +} + +static void dmxConsoleClearCursor(myPrivate *priv, int x, int y, + XRectangle *rect) +{ + int cw = 14, ch = 14; /* Clear width and height */ + + rect->x = scalex(priv, x) - cw/2; + rect->y = scaley(priv, y) - ch/2; + rect->width = cw; + rect->height = ch; + XSetClipRectangles(priv->display, priv->gc, 0, 0, rect, 1, Unsorted); + XSetClipRectangles(priv->display, priv->gcDet, 0, 0, rect, 1, Unsorted); + XSetClipRectangles(priv->display, priv->gcRev, 0, 0, rect, 1, Unsorted); + dmxConsoleDraw(priv, 0, 0); + XSetClipMask(priv->display, priv->gc, None); + XSetClipMask(priv->display, priv->gcDet, None); + XSetClipMask(priv->display, priv->gcRev, None); +} + + +static void dmxConsoleUpdateFineCursor(myPrivate *priv) +{ + int leave = 0; + XRectangle rects[2]; + + dmxConsoleClearCursor(priv, priv->globalX, priv->globalY, &rects[0]); + if (priv->dmxLocal->sendsCore) { + dmxGetGlobalPosition(&priv->globalX, &priv->globalY); + } else { + priv->globalX = priv->dmxLocal->lastX; + priv->globalY = priv->dmxLocal->lastY; + } + + priv->lastX = scalex(priv, priv->width / 2); + priv->lastY = scaley(priv, priv->height / 2); + + /* Compute new warp position, which may be + outside the window */ + if (priv->globalX < 1 || priv->globalX >= priv->width) { + if (priv->globalX < 1) priv->lastX = 0; + else priv->lastX = scalex(priv, priv->width); + priv->lastY = scaley(priv, priv->globalY); + ++leave; + } + if (priv->globalY < 1 || priv->globalY >= priv->height) { + if (priv->globalY < 1) priv->lastY = 0; + else priv->lastY = scaley(priv, priv->height); + priv->lastX = scalex(priv, priv->globalX); + ++leave; + } + + /* Draw pseudo cursor in window */ + dmxConsoleDrawFineCursor(priv, &rects[1]); + + XSetClipRectangles(priv->display, priv->gc, 0, 0, rects, 2, Unsorted); + XCopyArea(priv->display, priv->pixmap, priv->window, priv->gc, + 0, 0, priv->consWidth, priv->consHeight, 0, 0); + XSetClipMask(priv->display, priv->gc, None); + + DMXDBG2("dmxConsoleUpdateFineCursor: WARP %d %d\n", + priv->lastX, priv->lastY); + XWarpPointer(priv->display, priv->window, priv->window, + 0, 0, 0, 0, priv->lastX, priv->lastY); + XSync(priv->display, False); /* Not a backend display */ + + if (leave) { + XEvent X; + while (XCheckMaskEvent(priv->display, PointerMotionMask, &X)) { + if (X.type == MotionNotify) { + if (X.xmotion.x != priv->lastX || X.xmotion.y != priv->lastY) { + DMXDBG4("Ignoring motion to %d %d after leave frm %d %d\n", + X.xmotion.x, X.xmotion.y, + priv->lastX, priv->lastY); + } + } else { + dmxLog(dmxInfo, "Ignoring event (%d): %s ****************\n", + X.type, dmxEventName(X.type)); + } + } + } + DMXDBG6("dmxConsoleUpdateFineCursor: Warp %d %d on %d %d [%d %d]\n", + priv->lastX, priv->lastY, + scalex(priv, priv->width), + scaley(priv, priv->height), + priv->globalX, priv->globalY); +} + +/** Whenever the window layout (size, position, stacking order) might be + * changed, this routine is called with the \a pWindow that changed and + * the \a type of change. This routine is called in a conservative + * fashion: the actual layout of the windows of the screen might not + * have had any human-visible changes. */ +void dmxConsoleUpdateInfo(pointer private, DMXUpdateType type, + WindowPtr pWindow) +{ + GETONLYPRIVFROMPRIVATE; + dmxConsoleDraw(priv, 1, 1); +} + +static void dmxConsoleMoveAbsolute(myPrivate *priv, int x, int y, + DevicePtr pDev, dmxMotionProcPtr motion, + DMXBlockType block) +{ + int tmpX, tmpY, v[2]; + + tmpX = unscalex(priv, x); + tmpY = unscalex(priv, y); + DMXDBG6("dmxConsoleMoveAbsolute(,%d,%d) %d %d =? %d %d\n", + x, y, tmpX, tmpY, priv->curX, priv->curY); + if (tmpX == priv->curX && tmpY == priv->curY) return; + v[0] = unscalex(priv, x); + v[1] = unscaley(priv, y); + motion(pDev, v, 0, 2, DMX_ABSOLUTE_CONFINED, block); + /* dmxConsoleUpdatePosition gets called here by dmxCoreMotion */ +} + +static void dmxConsoleMoveRelative(myPrivate *priv, int x, int y, + DevicePtr pDev, dmxMotionProcPtr motion, + DMXBlockType block) +{ + int v[2]; + /* Ignore the event generated from * warping back to middle */ + if (x == priv->lastX && y == priv->lastY) return; + v[0] = priv->lastX - x; + v[1] = priv->lastY - y; + motion(pDev, v, 0, 2, DMX_RELATIVE, block); + /* dmxConsoleUpdatePosition gets called here by dmxCoreMotion */ +} + +/** This routine gets called from #dmxCoreMotion for each motion. This + * allows the console's notion of the cursor postion to change when + * another input device actually caused the change. */ +void dmxConsoleUpdatePosition(pointer private, int x, int y) +{ + GETONLYPRIVFROMPRIVATE; + int tmpX, tmpY; + Display *dpy = priv->display; + static unsigned long dmxGeneration = 0; + + + tmpX = scalex(priv, x); + tmpY = scaley(priv, y); + DMXDBG6("dmxConsoleUpdatePosition(,%d,%d) new=%d,%d dims=%d,%d\n", + x, y, tmpX, tmpY, priv->consWidth, priv->consHeight); + + if (priv->fine) dmxConsoleUpdateFineCursor(priv); + if (tmpX != priv->curX || tmpY != priv->curY) { + if (tmpX < 0) tmpX = 0; + if (tmpY < 0) tmpY = 0; + if (tmpX >= priv->consWidth) tmpX = priv->consWidth - 1; + if (tmpY >= priv->consHeight) tmpY = priv->consHeight - 1; + priv->curX = tmpX; + priv->curY = tmpY; + if (!priv->fine) { + DMXDBG2(" WARP B %d %d\n", priv->curX, priv->curY); + XWarpPointer(dpy, priv->window, + priv->window, 0, 0, 0, 0, tmpX, tmpY); + XSync(dpy, False); /* Not a backend display */ + } + } + + if (dmxGeneration != serverGeneration) { + dmxGeneration = serverGeneration; + dmxConsoleDraw(priv, 1, 1); + } +} + +/** Collect all pending events from the console's display. Plase these + * events on the server event queue using the \a motion and \a enqueue + * routines. The \a checkspecial routine is used to check for special + * keys that need handling. \a block tells if signals should be blocked + * when updating the event queue. */ +void dmxConsoleCollectEvents(DevicePtr pDev, + dmxMotionProcPtr motion, + dmxEnqueueProcPtr enqueue, + dmxCheckSpecialProcPtr checkspecial, + DMXBlockType block) +{ + GETPRIVFROMPDEV; + GETDMXINPUTFROMPRIV; + Display *dpy = priv->display; + Window win = priv->window; + int width = priv->width; + int height = priv->height; + XEvent X, N; + XSetWindowAttributes attribs; + static int rInitialized = 0; + static Region r; + XRectangle rect; + static int raising = 0, raiseX, raiseY; /* FIXME */ + + while (XPending(dpy)) { + XNextEvent(dpy, &X); + switch(X.type) { + case VisibilityNotify: + break; + case Expose: + DMXDBG5("dmxConsoleCollectEvents: Expose #%d %d %d %d %d\n", + X.xexpose.count, + X.xexpose.x, X.xexpose.y, + X.xexpose.width, X.xexpose.height); + if (!rInitialized++) r = XCreateRegion(); + rect.x = X.xexpose.x; + rect.y = X.xexpose.y; + rect.width = X.xexpose.width; + rect.height = X.xexpose.height; + XUnionRectWithRegion(&rect, r, r); + if (X.xexpose.count == 0) { + XSetRegion(dpy, priv->gc, r); + XSetRegion(dpy, priv->gcDet, r); + XSetRegion(dpy, priv->gcRev, r); + dmxConsoleDraw(priv, 1, 1); + XSetClipMask(dpy, priv->gc, None); + XSetClipMask(dpy, priv->gcDet, None); + XSetClipMask(dpy, priv->gcRev, None); + XDestroyRegion(r); + rInitialized = 0; + } + break; + case ResizeRequest: + DMXDBG2("dmxConsoleCollectEvents: Resize %d %d\n", + X.xresizerequest.width, X.xresizerequest.height); + priv->consWidth = X.xresizerequest.width; + priv->consHeight = X.xresizerequest.height; + priv->xScale = (double)priv->consWidth / width; + priv->yScale = (double)priv->consHeight / height; + attribs.override_redirect = True; + XChangeWindowAttributes(dpy, win, CWOverrideRedirect, &attribs); + XResizeWindow(dpy, win, priv->consWidth, priv->consHeight); + XFreePixmap(dpy, priv->pixmap); + priv->pixmap = XCreatePixmap(dpy, + RootWindow(dpy, DefaultScreen(dpy)), + priv->consWidth, + priv->consHeight, + DefaultDepth(dpy,DefaultScreen(dpy))); + dmxConsoleDraw(priv, 1, 1); + attribs.override_redirect = False; + XChangeWindowAttributes(dpy, win, CWOverrideRedirect, &attribs); + break; + case LeaveNotify: + DMXDBG4("dmxConsoleCollectEvents: Leave @ %d,%d; r=%d f=%d\n", + X.xcrossing.x, X.xcrossing.y, raising, priv->fine); + if (!priv->captured) dmxCommonRestoreState(priv); + else { + dmxConsoleUncapture(dmxInput); + dmxCommonRestoreState(priv); + } + break; + case EnterNotify: + DMXDBG6("dmxConsoleCollectEvents: Enter %d,%d r=%d f=%d (%d,%d)\n", + X.xcrossing.x, X.xcrossing.y, raising, priv->fine, + priv->curX, priv->curY); + dmxCommonSaveState(priv); + if (raising) { + raising = 0; + dmxConsoleMoveAbsolute(priv, raiseX, raiseY, + priv->mou, motion, block); + } else { + if (priv->fine) { + /* The raise will generate an event near the center, + * which is not where the cursor should be. So we + * save the real position, do the raise, and move + * the cursor here again after the raise generates + * the event. */ + raising = 1; + raiseX = X.xcrossing.x; + raiseY = X.xcrossing.y; + XRaiseWindow(dpy, priv->window); + } + XSync(dpy, False); /* Not a backend display */ + if (!X.xcrossing.x && !X.xcrossing.y) + dmxConsoleMoveAbsolute(priv, priv->curX, priv->curY, + priv->mou, motion, block); + } + break; + case MotionNotify: + if (priv->curX == X.xmotion.x && priv->curY == X.xmotion.y) + continue; + if (XPending(dpy)) { /* do motion compression */ + XPeekEvent(dpy, &N); + if (N.type == MotionNotify) continue; + } + DMXDBG2("dmxConsoleCollectEvents: Motion %d %d\n", + X.xmotion.x, X.xmotion.y); + if (raising) { + raising = 0; + dmxConsoleMoveAbsolute(priv, raiseX, raiseY, + priv->mou, motion, block); + } else { + if (priv->fine) + dmxConsoleMoveRelative(priv, X.xmotion.x, X.xmotion.y, + priv->mou, motion, block); + else + dmxConsoleMoveAbsolute(priv, X.xmotion.x, X.xmotion.y, + priv->mou, motion, block); + } + break; + case KeyPress: + case KeyRelease: + enqueue(priv->kbd, X.type, X.xkey.keycode, 0, NULL, block); + break; + default: + /* Pass the whole event here, because + * this may be an extension event. */ + enqueue(priv->mou, X.type, X.xbutton.button, 0, &X, block); + break; + } + } +} + +static void dmxCloseConsole(myPrivate *priv) +{ + GETDMXINPUTFROMPRIV; + dmxCommonRestoreState(priv); + if (priv->display) { + XFreeGC(priv->display, priv->gc); + XFreeGC(priv->display, priv->gcDet); + XFreeGC(priv->display, priv->gcRev); + XFreeGC(priv->display, priv->gcCur); + if (!dmxInput->console) XCloseDisplay(priv->display); + } + priv->display = NULL; +} + +static Bool dmxCloseConsoleScreen(int idx, ScreenPtr pScreen) +{ + myPrivate *priv, *last; + + for (last = priv = (myPrivate *)dixLookupPrivate(&pScreen->devPrivates, + dmxScreenPrivateKey); + priv; + priv = priv->next) dmxCloseConsole(last = priv); + + DMX_UNWRAP(CloseScreen, last, pScreen); + return pScreen->CloseScreen(idx, pScreen); +} + +static Cursor dmxConsoleCreateEmptyCursor(myPrivate *priv) +{ + char noCursorData[] = { 0, 0, 0, 0, 0, 0, 0, 0 }; + Pixmap pixmap; + Cursor cursor; + XColor color, tmpColor; + Display *dpy = priv->display; + + /* Create empty cursor for window */ + pixmap = XCreateBitmapFromData(priv->display, priv->window, + noCursorData, 8, 8); + if (!XAllocNamedColor(dpy, DefaultColormap(dpy, DefaultScreen(dpy)), + "black", + &color, + &tmpColor)) + dmxLog(dmxFatal, "Cannot allocate color for cursor\n"); + cursor = XCreatePixmapCursor(dpy, pixmap, pixmap, &color, &color, 0, 0); + XFreePixmap(dpy, pixmap); + return cursor; +} + +static void dmxConsoleComputeWidthHeight(myPrivate *priv, + int *width, int *height, + double *xScale, double *yScale, + int *consWidth, int *consHeight) +{ + int screen; + Display *dpy = priv->display; + + *width = 0; + *height = 0; + *xScale = 1.0; + *yScale = 1.0; + + screen = DefaultScreen(dpy); + *consWidth = DisplayWidth(dpy, screen) * CONSOLE_NUM / CONSOLE_DEN; + *consHeight = DisplayHeight(dpy, screen) * CONSOLE_NUM / CONSOLE_DEN; + + if (*consWidth < 1) *consWidth = 1; + if (*consHeight < 1) *consHeight = 1; + +#if 1 + /* Always keep the console size similar + * to the global bounding box. */ + *width = dmxGlobalWidth; + *height = dmxGlobalHeight; +#else + /* Make the console window as big as + * possible by computing the visible + * bounding box. */ + for (i = 0; i < dmxNumScreens; i++) { + if (dixScreenOrigins[i].x+screenInfo.screens[i]->width > *width) + *width = dixScreenOrigins[i].x+screenInfo.screens[i]->width; + + if (dixScreenOrigins[i].y+screenInfo.screens[i]->height > *height) + *height = dixScreenOrigins[i].y+screenInfo.screens[i]->height; + } +#endif + + if ((double)*consWidth / *width < (double)*consHeight / *height) + *xScale = *yScale = (double)*consWidth / *width; + else + *xScale = *yScale = (double)*consHeight / *height; + + *consWidth = scalex(priv, *width); + *consHeight = scaley(priv, *height); + if (*consWidth < 1) *consWidth = 1; + if (*consHeight < 1) *consHeight = 1; +} + +/** Re-initialized the console device described by \a pDev (after a + * reconfig). */ +void dmxConsoleReInit(DevicePtr pDev) +{ + GETPRIVFROMPDEV; + Display *dpy; + + if (!priv || !priv->initialized) return; + dpy = priv->display; + + dmxConsoleComputeWidthHeight(priv, + &priv->width, &priv->height, + &priv->xScale, &priv->yScale, + &priv->consWidth, &priv->consHeight); + XResizeWindow(dpy, priv->window, priv->consWidth, priv->consHeight); + XFreePixmap(dpy, priv->pixmap); + priv->pixmap = XCreatePixmap(dpy, + RootWindow(dpy, DefaultScreen(dpy)), + priv->consWidth, + priv->consHeight, + DefaultDepth(dpy,DefaultScreen(dpy))); + dmxConsoleDraw(priv, 1, 1); +} + +/** Initialized the console device described by \a pDev. */ +void dmxConsoleInit(DevicePtr pDev) +{ + GETPRIVFROMPDEV; + DMXInputInfo *dmxInput = &dmxInputs[dmxLocal->inputIdx]; + int screen; + unsigned long mask; + XSetWindowAttributes attribs; + Display *dpy; + Window win; + XGCValues gcvals; + XColor color; + XClassHint class_hints; + unsigned long tmp; + + if (dmxLocal->type == DMX_LOCAL_MOUSE) priv->mou = pDev; + if (dmxLocal->type == DMX_LOCAL_KEYBOARD) priv->kbd = pDev; + if (priv->initialized++) return; /* Only do once for mouse/keyboard pair */ + + if (!(dpy = priv->display = XOpenDisplay(dmxInput->name))) + dmxLog(dmxFatal, + "dmxOpenConsole: cannot open console display %s\n", + dmxInput->name); + + /* Set up defaults */ + dmxConsoleComputeWidthHeight(priv, + &priv->width, &priv->height, + &priv->xScale, &priv->yScale, + &priv->consWidth, &priv->consHeight); + + /* Private initialization using computed values or constants. */ + screen = DefaultScreen(dpy); + priv->initPointerX = scalex(priv, priv->width / 2); + priv->initPointerY = scaley(priv, priv->height / 2); + priv->eventMask = (ButtonPressMask + | ButtonReleaseMask + | PointerMotionMask + | EnterWindowMask + | LeaveWindowMask + | KeyPressMask + | KeyReleaseMask + | ExposureMask + | ResizeRedirectMask); + + mask = CWBackPixel | CWEventMask | CWColormap | CWOverrideRedirect; + attribs.colormap = DefaultColormap(dpy, screen); + if (XParseColor(dpy, attribs.colormap, CONSOLE_BG_COLOR, &color) + && XAllocColor(dpy, attribs.colormap, &color)) { + attribs.background_pixel = color.pixel; + } else + attribs.background_pixel = WhitePixel(dpy, screen); + + attribs.event_mask = priv->eventMask; + attribs.override_redirect = False; + + win = priv->window = XCreateWindow(dpy, + RootWindow(dpy, screen), + 0, 0, priv->consWidth, priv->consHeight, + 0, + DefaultDepth(dpy, screen), + InputOutput, + DefaultVisual(dpy, screen), + mask, &attribs); + priv->pixmap = XCreatePixmap(dpy, RootWindow(dpy, screen), + priv->consWidth, priv->consHeight, + DefaultDepth(dpy, screen)); + + /* Set up properties */ + XStoreName(dpy, win, DMX_CONSOLE_NAME); + class_hints.res_name = DMX_RES_NAME; + class_hints.res_class = DMX_RES_CLASS; + XSetClassHint(dpy, win, &class_hints); + + + /* Map the window */ + XMapWindow(dpy, win); + + /* Create cursors */ + priv->cursorNormal = XCreateFontCursor(dpy, XC_circle); + priv->cursorGrabbed = XCreateFontCursor(dpy, XC_spider); + priv->cursorEmpty = dmxConsoleCreateEmptyCursor(priv); + XDefineCursor(dpy, priv->window, priv->cursorNormal); + + /* Create GC */ + mask = (GCFunction | GCPlaneMask | GCClipMask | GCForeground | + GCBackground | GCLineWidth | GCLineStyle | GCCapStyle | + GCFillStyle | GCGraphicsExposures); + gcvals.function = GXcopy; + gcvals.plane_mask = AllPlanes; + gcvals.clip_mask = None; + if (XParseColor(dpy, attribs.colormap, CONSOLE_SCREEN_FG_COLOR, &color) + && XAllocColor(dpy, attribs.colormap, &color)) { + gcvals.foreground = color.pixel; + } else + gcvals.foreground = BlackPixel(dpy, screen); + if (XParseColor(dpy, attribs.colormap, CONSOLE_SCREEN_BG_COLOR, &color) + && XAllocColor(dpy, attribs.colormap, &color)) { + gcvals.background = color.pixel; + } else + gcvals.background = WhitePixel(dpy, screen); + gcvals.line_width = 0; + gcvals.line_style = LineSolid; + gcvals.cap_style = CapNotLast; + gcvals.fill_style = FillSolid; + gcvals.graphics_exposures = False; + + priv->gc = XCreateGC(dpy, win, mask, &gcvals); + + tmp = gcvals.foreground; + if (XParseColor(dpy, attribs.colormap, CONSOLE_SCREEN_DET_COLOR, &color) + && XAllocColor(dpy, attribs.colormap, &color)) { + gcvals.foreground = color.pixel; + } else + gcvals.foreground = BlackPixel(dpy, screen); + priv->gcDet = XCreateGC(dpy, win, mask, &gcvals); + gcvals.foreground = tmp; + + tmp = gcvals.background; + gcvals.background = gcvals.foreground; + gcvals.foreground = tmp; + priv->gcRev = XCreateGC(dpy, win, mask, &gcvals); + + gcvals.background = gcvals.foreground; + if (XParseColor(dpy, attribs.colormap, CONSOLE_SCREEN_CUR_COLOR, &color) + && XAllocColor(dpy, attribs.colormap, &color)) { + gcvals.foreground = color.pixel; + } else + gcvals.foreground = BlackPixel(dpy, screen); + priv->gcCur = XCreateGC(dpy, win, mask, &gcvals); + + dmxConsoleDraw(priv, 1, 1); + + if (dixLookupPrivate(&screenInfo.screens[0]->devPrivates, + dmxScreenPrivateKey)) + priv->next = dixLookupPrivate(&screenInfo.screens[0]->devPrivates, + dmxScreenPrivateKey); + else + DMX_WRAP(CloseScreen, dmxCloseConsoleScreen, + priv, screenInfo.screens[0]); + dixSetPrivate(&screenInfo.screens[0]->devPrivates, dmxScreenPrivateKey, + priv); +} + +/** Fill in the \a info structure for the specified \a pDev. Only used + * for pointers. */ +void dmxConsoleMouGetInfo(DevicePtr pDev, DMXLocalInitInfoPtr info) +{ + GETPRIVFROMPDEV; + + info->buttonClass = 1; + dmxCommonMouGetMap(pDev, info->map, &info->numButtons); + info->valuatorClass = 1; + info->numRelAxes = 2; + info->minval[0] = 0; + info->minval[1] = 0; + /* max possible console window size: */ + info->maxval[0] = DisplayWidth(priv->display, DefaultScreen(priv->display)); + info->maxval[1] = DisplayHeight(priv->display, DefaultScreen(priv->display)); + info->res[0] = 1; + info->minres[0] = 0; + info->maxres[0] = 1; + info->ptrFeedbackClass = 1; +} + +/** Fill in the \a info structure for the specified \a pDev. Only used + * for keyboard. */ +void dmxConsoleKbdGetInfo(DevicePtr pDev, DMXLocalInitInfoPtr info) +{ + dmxCommonKbdGetInfo(pDev, info); + info->keyboard = 1; + info->keyClass = 1; + dmxCommonKbdGetMap(pDev, &info->keySyms, info->modMap); + info->freemap = 1; + info->focusClass = 1; + info->kbdFeedbackClass = 1; +} + +/** Handle special console-only keys. */ +int dmxConsoleFunctions(pointer private, DMXFunctionType function) +{ + GETONLYPRIVFROMPRIVATE; + XRectangle rect; + Display *dpy = priv->display; + + switch (function) { + case DMX_FUNCTION_FINE: + if (priv->fine) { + priv->fine = 0; + dmxConsoleClearCursor(priv, priv->globalX, priv->globalY, &rect); + XSetClipRectangles(dpy, priv->gc, 0, 0, &rect, 1, Unsorted); + XCopyArea(dpy, priv->pixmap, priv->window, priv->gc, + 0, 0, priv->consWidth, priv->consHeight, 0, 0); + XSetClipMask(dpy, priv->gc, None); + + XDefineCursor(dpy, priv->window, + priv->grabbed + ? priv->cursorGrabbed + : priv->cursorNormal); + XWarpPointer(dpy, priv->window, priv->window, + 0, 0, 0, 0, + scalex(priv, priv->globalX), + scaley(priv, priv->globalY)); + XSync(dpy, False); /* Not a backend display */ + } else { + priv->fine = 1; + XRaiseWindow(dpy, priv->window); + XDefineCursor(dpy, priv->window, priv->cursorEmpty); + dmxConsoleUpdateFineCursor(priv); + } + return 1; + case DMX_FUNCTION_GRAB: + if (priv->grabbed) { + XUngrabKeyboard(dpy, CurrentTime); + XUngrabPointer(dpy, CurrentTime); + XDefineCursor(dpy, priv->window, + priv->fine + ? priv->cursorEmpty + : priv->cursorNormal); + } else { + if (XGrabPointer(dpy, priv->window, True, + 0, GrabModeAsync, GrabModeAsync, priv->window, + None, CurrentTime)) { + dmxLog(dmxError, "XGrabPointer failed\n"); + return 0; + } + if (XGrabKeyboard(dpy, priv->window, True, + GrabModeAsync, GrabModeAsync, CurrentTime)) { + dmxLog(dmxError, "XGrabKeyboard failed\n"); + XUngrabPointer(dpy, CurrentTime); + return 0; + } + XDefineCursor(dpy, priv->window, + priv->fine + ? priv->cursorEmpty + : priv->cursorGrabbed); + } + priv->grabbed = !priv->grabbed; + if (priv->fine) dmxConsoleUpdateFineCursor(priv); + return 1; + case DMX_FUNCTION_TERMINATE: + return 1; + default: + return 0; + } +} + +static void dmxDump(void) +{ + int i, j; + DMXInputInfo *dmxInput; + XEvent X; + + for (i = 0, dmxInput = &dmxInputs[0]; i < dmxNumInputs; i++, dmxInput++) { + for (j = 0; j < dmxInput->numDevs; j++) { + DMXLocalInputInfoPtr dmxLocal = dmxInput->devs[j]; + myPrivate *priv = dmxLocal->private; + while (priv + && priv->display + && XCheckTypedEvent(priv->display, MotionNotify, &X)) { + DMXDBG4("dmxDump: %s/%d threw event away %d %s\n", + dmxInput->name, j, X.type, dmxEventName(X.type)); + } + } + } +} + +/** This routine is used to warp the pointer into the console window + * from anywhere on the screen. It is used when backend and console + * input are both being taken from the same X display. */ +void dmxConsoleCapture(DMXInputInfo *dmxInput) +{ + int i; + XEvent X; + + DMXDBG0("dmxConsoleCapture\n"); + dmxSync(NULL, TRUE); + for (i = 0; i < dmxInput->numDevs; i++) { + DMXLocalInputInfoPtr dmxLocal = dmxInput->devs[i]; + myPrivate *priv = dmxLocal->private; + if (dmxLocal->extType != DMX_LOCAL_TYPE_CONSOLE) continue; + if (dmxLocal->type != DMX_LOCAL_MOUSE) continue; + if (priv->captured) continue; + priv->captured = 2; /* Ungrab only after proximal events. */ + XRaiseWindow(priv->display, priv->window); + XSync(priv->display, False); /* Not a backend display */ + while (XCheckTypedEvent(priv->display, MotionNotify, &X)) { + DMXDBG3(" Ignoring motion to %d %d after capture on %s\n", + X.xmotion.x, X.xmotion.y, dmxInput->name); + } + XWarpPointer(priv->display, None, + priv->window, 0, 0, 0, 0, priv->curX, priv->curY); + XSync(priv->display, False); /* Not a backend display */ + dmxDump(); + if (priv->fine) dmxConsoleUpdateFineCursor(priv); + } +} + +/** Undo the capture that was done by #dmxConsoleCapture. */ +void dmxConsoleUncapture(DMXInputInfo *dmxInput) +{ + int i; + + DMXDBG0("dmxConsoleUncapture\n"); + dmxSync(NULL, TRUE); + for (i = 0; i < dmxInput->numDevs; i++) { + DMXLocalInputInfoPtr dmxLocal = dmxInput->devs[i]; + myPrivate *priv = dmxLocal->private; + if (dmxLocal->extType != DMX_LOCAL_TYPE_CONSOLE) continue; + if (dmxLocal->type != DMX_LOCAL_MOUSE) continue; + if (!priv->captured) continue; + priv->captured = 0; + XSync(priv->display, False); /* Not a backend display */ + } +} diff --git a/xorg-server/hw/dmx/input/dmxconsole.h b/xorg-server/hw/dmx/input/dmxconsole.h new file mode 100644 index 000000000..cd545d39b --- /dev/null +++ b/xorg-server/hw/dmx/input/dmxconsole.h @@ -0,0 +1,59 @@ +/* + * Copyright 2002 Red Hat Inc., Durham, North Carolina. + * + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation on the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NON-INFRINGEMENT. IN NO EVENT SHALL RED HAT AND/OR THEIR SUPPLIERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* + * Authors: + * Rickard E. (Rik) Faith <faith@redhat.com> + * + */ + +/** \file + * Interface for console device support. \see dmxconsole.c \see dmxcommon.c */ + +#ifndef _DMXCONSOLE_H_ +#define _DMXCONSOLE_H_ + +extern pointer dmxConsoleCreatePrivate(DeviceIntPtr pDevice); +extern void dmxConsoleDestroyPrivate(pointer private); +extern void dmxConsoleInit(DevicePtr pDev); +extern void dmxConsoleReInit(DevicePtr pDev); +extern void dmxConsoleMouGetInfo(DevicePtr pDev, DMXLocalInitInfoPtr info); +extern void dmxConsoleKbdGetInfo(DevicePtr pDev, DMXLocalInitInfoPtr info); +extern void dmxConsoleCollectEvents(DevicePtr pDev, + dmxMotionProcPtr motion, + dmxEnqueueProcPtr enqueue, + dmxCheckSpecialProcPtr checkspecial, + DMXBlockType block); +extern int dmxConsoleFunctions(pointer private, DMXFunctionType function); +extern void dmxConsoleUpdatePosition(pointer private, int x, int y); +extern void dmxConsoleKbdSetCtrl(pointer private, KeybdCtrl *ctrl); +extern void dmxConsoleCapture(DMXInputInfo *dmxInput); +extern void dmxConsoleUncapture(DMXInputInfo *dmxInput); +extern void dmxConsoleUpdateInfo(pointer private, + DMXUpdateType, WindowPtr pWindow); + +#endif diff --git a/xorg-server/hw/dmx/input/dmxdetach.c b/xorg-server/hw/dmx/input/dmxdetach.c new file mode 100644 index 000000000..cc2250683 --- /dev/null +++ b/xorg-server/hw/dmx/input/dmxdetach.c @@ -0,0 +1,58 @@ +/* + * Copyright 2004 Red Hat Inc., Raleigh, North Carolina. + * + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation on the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NON-INFRINGEMENT. IN NO EVENT SHALL RED HAT AND/OR THEIR SUPPLIERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* + * Authors: + * Rickard E. (Rik) Faith <faith@redhat.com> + * + */ + +/** \file + * Provide support and helper functions for input detach and attach. */ + +#ifdef HAVE_DMX_CONFIG_H +#include <dmx-config.h> +#endif + +#include "dmxinputinit.h" +#include "dmxextension.h" /* For dmxInputCount */ + +/** Search for input associated with \a dmxScreen, and detach. */ +void dmxInputDetach(DMXScreenInfo *dmxScreen, Bool reserveId) +{ + int i; + + for (i = 0; i < dmxNumInputs; i++) { + DMXInputInfo *dmxInput = &dmxInputs[i]; + if (dmxInput->scrnIdx == dmxScreen->index) { + dmxLogInput(dmxInput, "Detaching (%sreserved)\n", + reserveId ? "" : "not "); + dmxInput->detached = True; + return; + } + } +} diff --git a/xorg-server/hw/dmx/input/dmxdummy.c b/xorg-server/hw/dmx/input/dmxdummy.c new file mode 100644 index 000000000..2afe2580d --- /dev/null +++ b/xorg-server/hw/dmx/input/dmxdummy.c @@ -0,0 +1,88 @@ +/* + * Copyright 2002 Red Hat Inc., Durham, North Carolina. + * + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation on the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NON-INFRINGEMENT. IN NO EVENT SHALL RED HAT AND/OR THEIR SUPPLIERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* + * Authors: + * Rickard E. (Rik) Faith <faith@redhat.com> + * + */ + +/** \file + * Provide mouse and keyboard that are sufficient for starting the X + * server, but that don't actually provide any events. This is useful + * for testing. */ + +#ifdef HAVE_DMX_CONFIG_H +#include <dmx-config.h> +#endif + +#include "dmx.h" +#include "dmxinputinit.h" +#include "dmxdummy.h" + +/** Return information about the dummy keyboard device specified in \a pDev + * into the structure pointed to by \a info. The keyboard is set up to + * have 1 valid key code that is \a NoSymbol */ +void dmxDummyKbdGetInfo(DevicePtr pDev, DMXLocalInitInfoPtr info) +{ + static KeySym keyboard_mapping = NoSymbol; + + info->keyboard = 1; + info->keyClass = 1; + info->keySyms.minKeyCode = 8; + info->keySyms.maxKeyCode = 8; + info->keySyms.mapWidth = 1; + info->keySyms.map = &keyboard_mapping; + info->freemap = 0; + info->focusClass = 1; + info->kbdFeedbackClass = 1; +#ifdef XKB + info->force = 1; +#endif +} + +/** Return information about the dummy mouse device specified in \a pDev + * into the structure pointed to by \a info. They mouse has 3 buttons + * and two axes. */ +void dmxDummyMouGetInfo(DevicePtr pDev, DMXLocalInitInfoPtr info) +{ + info->buttonClass = 1; + info->numButtons = 3; + info->map[0] = 1; + info->map[1] = 2; + info->map[2] = 3; + info->valuatorClass = 1; + info->numRelAxes = 2; + info->minval[0] = 0; + info->minval[1] = 0; + info->maxval[0] = 0; + info->maxval[1] = 0; + info->res[0] = 1; + info->minres[0] = 0; + info->maxres[0] = 1; + info->ptrFeedbackClass = 1; +} diff --git a/xorg-server/hw/dmx/input/dmxdummy.h b/xorg-server/hw/dmx/input/dmxdummy.h new file mode 100644 index 000000000..e3a85be95 --- /dev/null +++ b/xorg-server/hw/dmx/input/dmxdummy.h @@ -0,0 +1,43 @@ +/* + * Copyright 2002 Red Hat Inc., Durham, North Carolina. + * + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation on the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NON-INFRINGEMENT. IN NO EVENT SHALL RED HAT AND/OR THEIR SUPPLIERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* + * Authors: + * Rickard E. (Rik) Faith <faith@redhat.com> + * + */ + +/** \file + * Interface to dummy input device support. \see dmxdummy.c */ + +#ifndef _DMXDUMMY_H_ +#define _DMXDUMMY_H_ + +extern void dmxDummyMouGetInfo(DevicePtr pDev, DMXLocalInitInfoPtr info); +extern void dmxDummyKbdGetInfo(DevicePtr pDev, DMXLocalInitInfoPtr info); + +#endif diff --git a/xorg-server/hw/dmx/input/dmxeq.c b/xorg-server/hw/dmx/input/dmxeq.c new file mode 100644 index 000000000..dff0b4423 --- /dev/null +++ b/xorg-server/hw/dmx/input/dmxeq.c @@ -0,0 +1,307 @@ +/* + * + * Copyright 1990, 1998 The Open Group + * + * Permission to use, copy, modify, distribute, and sell this software and its + * documentation for any purpose is hereby granted without fee, provided that + * the above copyright notice appear in all copies and that both that + * copyright notice and this permission notice appear in supporting + * documentation. + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * Except as contained in this notice, the name of The Open Group shall not be + * used in advertising or otherwise to promote the sale, use or other dealings + * in this Software without prior written authorization from The Open Group. + * + * Author: Keith Packard, MIT X Consortium + */ + +/* + * dmxeq.c is derived from mi/mieq.c so that XInput events can be handled + * + * Modified by: Rickard E. (Rik) Faith <faith@redhat.com> + * + * Copyright 2002-2003 Red Hat Inc., Durham, North Carolina. + * + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation on the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NON-INFRINGEMENT. IN NO EVENT SHALL RED HAT AND/OR THEIR SUPPLIERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/** \file + * This file provides an event queue that knows about XInput events. + * All of the code is based on mi/mieq.c and was modified as little as + * possible to provide XInput event support (the copyright and some of + * the comments are from The Open Group, Keith Packard, MIT X + * Consortium). (Another example of similar code is provided in + * hw/xfree86/common/xf86Xinput.c.) */ + +#ifdef HAVE_DMX_CONFIG_H +#include <dmx-config.h> +#endif + +#define DMX_EQ_DEBUG 0 + +#include "dmx.h" +#include "dmxeq.h" +#include "dmxinput.h" +#include "dmxlog.h" +#include "dmxdpms.h" + +#include "inputstr.h" +#include "scrnintstr.h" /* For screenInfo */ + +#ifdef XINPUT +#include <X11/extensions/XIproto.h> +#define EXTENSION_PROC_ARGS void * +#endif + +#if DMX_EQ_DEBUG +#define DMXDBG2(f,a,b) dmxLog(dmxDebug,f,a,b) +#define DMXDBG5(f,a,b,c,d,e) dmxLog(dmxDebug,f,a,b,c,d,e) +#else +#define DMXDBG2(f,a,b) +#define DMXDBG5(f,a,b,c,d,e) +#endif + +/** The size of our queue. (The queue provided by mi/mieq.c has a size + * of 256.) */ +#define QUEUE_SIZE 256 + +/** Information about the event. */ +typedef struct _Event { + xEvent event; /**< Event. */ + ScreenPtr pScreen; /**< Screen on which event occurred. */ +#ifdef XINPUT + deviceValuator valuator; /**< XInput device valuator information. */ +#endif +} EventRec, *EventPtr; + +/** Event queue. */ +typedef struct _EventQueue { + HWEventQueueType head; /**< Queue head; must be long for SetInputCheck. */ + HWEventQueueType tail; /**< Queue tail; must be long for SetInputCheck. */ + CARD32 lastEventTime; /**< To avoid time running backwards. */ + Bool lastMotion; /**< True if last event was motion. */ + EventRec events[QUEUE_SIZE]; /**< Static allocation for signals. */ + DevicePtr pKbd, pPtr; /**< Device pointers (to get funcs) */ + ScreenPtr pEnqueueScreen;/**< Screen events are delivered to. */ + ScreenPtr pDequeueScreen;/**< Screen events are dispatched to. */ +} EventQueueRec, *EventQueuePtr; + +static EventQueueRec dmxEventQueue; +static Bool dmxeqInitializedFlag = FALSE; + +Bool dmxeqInitialized(void) +{ + return dmxeqInitializedFlag; +} + +Bool dmxeqInit(DevicePtr pKbd, DevicePtr pPtr) +{ + static unsigned long dmxGeneration = 0; + + if (dmxGeneration == serverGeneration && dmxeqInitializedFlag) + return FALSE; + dmxGeneration = serverGeneration; + dmxeqInitializedFlag = TRUE; + dmxEventQueue.head = 0; + dmxEventQueue.tail = 0; + dmxEventQueue.lastEventTime = GetTimeInMillis(); + dmxEventQueue.pKbd = pKbd; + dmxEventQueue.pPtr = pPtr; + dmxEventQueue.lastMotion = FALSE; + dmxEventQueue.pEnqueueScreen = screenInfo.screens[0]; + dmxEventQueue.pDequeueScreen = dmxEventQueue.pEnqueueScreen; + SetInputCheck(&dmxEventQueue.head, &dmxEventQueue.tail); + return TRUE; +} + +/** + * This function adds an event to the end of the queue. If the event is + * an XInput event, then the next event (the valuator event) is also + * stored in the queue. If the new event has a time before the time of + * the last event currently on the queue, then the time is updated for + * the new event. + * + * Must be reentrant with ProcessInputEvents. Assumption: dmxeqEnqueue + * will never be interrupted. If this is called from both signal + * handlers and regular code, make sure the signal is suspended when + * called from regular code. + */ + +void dmxeqEnqueue(xEvent *e) +{ + HWEventQueueType oldtail, newtail; + Bool isMotion; + + oldtail = dmxEventQueue.tail; + isMotion = e->u.u.type == MotionNotify; + if (isMotion + && dmxEventQueue.lastMotion + && oldtail != dmxEventQueue.head) { + if (oldtail == 0) oldtail = QUEUE_SIZE; + oldtail = oldtail - 1; + } else { + newtail = oldtail + 1; + if (newtail == QUEUE_SIZE) newtail = 0; + /* Toss events which come in late */ + if (newtail == dmxEventQueue.head) return; + dmxEventQueue.tail = newtail; + } + DMXDBG2("dmxeqEnqueue %d %d\n", dmxEventQueue.head, dmxEventQueue.tail); + dmxEventQueue.lastMotion = isMotion; + dmxEventQueue.events[oldtail].pScreen = dmxEventQueue.pEnqueueScreen; + + /* Store the event in the queue */ + dmxEventQueue.events[oldtail].event = *e; +#ifdef XINPUT + { + /* If this is an XInput event, store the + * valuator event, too */ + deviceKeyButtonPointer *ev = (deviceKeyButtonPointer *)e; + if (e->u.u.type >= LASTEvent && (ev->deviceid & MORE_EVENTS)) + dmxEventQueue.events[oldtail].valuator = *(deviceValuator *)(ev+1); + } +#endif + + /* Make sure that event times don't go + * backwards - this is "unnecessary", + * but very useful */ + if (e->u.keyButtonPointer.time < dmxEventQueue.lastEventTime + && dmxEventQueue.lastEventTime - e->u.keyButtonPointer.time < 10000) { + dmxEventQueue.events[oldtail].event.u.keyButtonPointer.time = + dmxEventQueue.lastEventTime; + } +} + +/** Make \a pScreen the new screen for enqueueing events. If \a fromDIX + * is TRUE, also make \a pScreen the new screen for dequeuing events. */ +void dmxeqSwitchScreen(ScreenPtr pScreen, Bool fromDIX) +{ + dmxEventQueue.pEnqueueScreen = pScreen; + if (fromDIX) dmxEventQueue.pDequeueScreen = pScreen; +} + +#ifdef XINPUT +static void dmxeqProcessXInputEvent(xEvent *xe, EventRec *e) +{ + deviceKeyButtonPointer *ev = (deviceKeyButtonPointer *)xe; + int id = ev->deviceid & DEVICE_BITS; + DeviceIntPtr pDevice; + + dixLookupDevice(&pDevice, id, serverClient, DixUnknownAccess); + if (!pDevice) { + dmxLog(dmxError, "dmxeqProcessInputEvents: id %d not found\n", id); + return; + } + + if (!pDevice->public.processInputProc) { + dmxLog(dmxError, + "dmxeqProcessInputEvents: no processInputProc for" + " device id %d (%s)\n", id, pDevice->name); + return; + } + + if (ev->deviceid & MORE_EVENTS) { + xe[1] = *(xEvent *)(&e->valuator); + pDevice->public.processInputProc(xe, pDevice, 2); + } else { + pDevice->public.processInputProc(xe, pDevice, 1); + } +} +#endif + +/** + * This function is called from #ProcessInputEvents() to remove events + * from the queue and process them. + */ +void dmxeqProcessInputEvents(void) +{ + EventRec *e; + int x, y; + xEvent xe[2]; + + while (dmxEventQueue.head != dmxEventQueue.tail) { + dmxDPMSWakeup(); /* Handles screen saver and DPMS */ + e = &dmxEventQueue.events[dmxEventQueue.head]; + DMXDBG5("dmxeqProcessInputEvents: type=%d screen=%p,%p root=%d,%d\n", + e->event.u.u.type, + e->pScreen, dmxEventQueue.pDequeueScreen, + e->event.u.keyButtonPointer.rootX, + e->event.u.keyButtonPointer.rootY); + /* + * Assumption - screen switching can only occur on core motion events + */ + if (e->event.u.u.type == MotionNotify + && e->pScreen != dmxEventQueue.pDequeueScreen) { + dmxEventQueue.pDequeueScreen = e->pScreen; + x = e->event.u.keyButtonPointer.rootX; + y = e->event.u.keyButtonPointer.rootY; + if (dmxEventQueue.head == QUEUE_SIZE - 1) dmxEventQueue.head = 0; + else ++dmxEventQueue.head; + NewCurrentScreen(dmxEventQueue.pDequeueScreen, x, y); + } else { + xe[0] = e->event; + if (dmxEventQueue.head == QUEUE_SIZE - 1) dmxEventQueue.head = 0; + else ++dmxEventQueue.head; + switch (xe[0].u.u.type) { + case KeyPress: + case KeyRelease: + if (!dmxEventQueue.pKbd) { + dmxLog(dmxError, "dmxeqProcessInputEvents: No keyboard\n"); + return; + } + dmxEventQueue.pKbd + ->processInputProc(xe, + (DeviceIntPtr)dmxEventQueue.pKbd, 1); + break; + default: +#ifdef XINPUT + dmxeqProcessXInputEvent(xe, e); + break; +#endif + /* ifndef XINPUT, fall through */ + case ButtonPress: + case ButtonRelease: + case MotionNotify: + if (!dmxEventQueue.pPtr) { + dmxLog(dmxError, "dmxeqProcessInputEvents: No mouse\n"); + return; + } + dmxEventQueue.pPtr + ->processInputProc(xe, + (DeviceIntPtr)dmxEventQueue.pPtr, 1); + break; + } + } + } +} diff --git a/xorg-server/hw/dmx/input/dmxeq.h b/xorg-server/hw/dmx/input/dmxeq.h new file mode 100644 index 000000000..b38c519df --- /dev/null +++ b/xorg-server/hw/dmx/input/dmxeq.h @@ -0,0 +1,43 @@ +/* + * Copyright 2002 Red Hat Inc., Durham, North Carolina. + * + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation on the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NON-INFRINGEMENT. IN NO EVENT SHALL RED HAT AND/OR THEIR SUPPLIERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* + * Authors: + * Rickard E. (Rik) Faith <faith@redhat.com> + * + */ + +/** \file + * Interface to the event queue support. Some of these functions are + * included in dmxinput.h, since they are used by top-level .c + * files. \see dmxeq.c \see dmxinput.h */ + +#ifndef _DMXEQ_H_ +#define _DMXEQ_H_ +extern Bool dmxeqInit(DevicePtr pKbd, DevicePtr pPtr); +extern void dmxeqProcessInputEvents(void); +#endif diff --git a/xorg-server/hw/dmx/input/dmxevents.c b/xorg-server/hw/dmx/input/dmxevents.c new file mode 100644 index 000000000..26dc067dc --- /dev/null +++ b/xorg-server/hw/dmx/input/dmxevents.c @@ -0,0 +1,834 @@ +/* + * Copyright 2002-2003 Red Hat Inc., Durham, North Carolina. + * + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation on the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NON-INFRINGEMENT. IN NO EVENT SHALL RED HAT AND/OR THEIR SUPPLIERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* + * Authors: + * Rickard E. (Rik) Faith <faith@redhat.com> + * + */ + +/** \file + * Provide support and helper functions for enqueing events received by + * the low-level input drivers. */ + +#ifdef HAVE_DMX_CONFIG_H +#include <dmx-config.h> +#endif + +#define DMX_EVENTS_DEBUG 0 + +#include "dmxinputinit.h" +#include "dmxevents.h" +#include "dmxcb.h" +#include "dmxcommon.h" +#include "dmxcursor.h" +#include "dmxmotion.h" +#include "dmxeq.h" +#include "dmxsigio.h" +#include "dmxmap.h" + +#include <X11/keysym.h> +#include "opaque.h" +#include "inputstr.h" +#include "mipointer.h" +#include "mi.h" + +#ifdef XINPUT +#include "XIstubs.h" +#endif + +static int dmxGlobalX, dmxGlobalY; /* Global cursor position */ +static int dmxGlobalInvalid; /* Flag indicating dmxCoreMotion + * should move the mouse anyway. */ + +#if DMX_EVENTS_DEBUG +#define DMXDBG0(f) dmxLog(dmxDebug,f) +#define DMXDBG1(f,a) dmxLog(dmxDebug,f,a) +#define DMXDBG2(f,a,b) dmxLog(dmxDebug,f,a,b) +#define DMXDBG3(f,a,b,c) dmxLog(dmxDebug,f,a,b,c) +#define DMXDBG4(f,a,b,c,d) dmxLog(dmxDebug,f,a,b,c,d) +#define DMXDBG5(f,a,b,c,d,e) dmxLog(dmxDebug,f,a,b,c,d,e) +#define DMXDBG6(f,a,b,c,d,e,g) dmxLog(dmxDebug,f,a,b,c,d,e,g) +#define DMXDBG7(f,a,b,c,d,e,g,h) dmxLog(dmxDebug,f,a,b,c,d,e,g,h) +#else +#define DMXDBG0(f) +#define DMXDBG1(f,a) +#define DMXDBG2(f,a,b) +#define DMXDBG3(f,a,b,c) +#define DMXDBG4(f,a,b,c,d) +#define DMXDBG5(f,a,b,c,d,e) +#define DMXDBG6(f,a,b,c,d,e,g) +#define DMXDBG7(f,a,b,c,d,e,g,h) +#endif + +static int dmxApplyFunctions(DMXInputInfo *dmxInput, DMXFunctionType f) +{ + int i; + int rc = 0; + + for (i = 0; i < dmxInput->numDevs; i+= dmxInput->devs[i]->binding) + if (dmxInput->devs[i]->functions) + rc += dmxInput->devs[i]->functions(dmxInput->devs[i]->private, f); + return rc; +} + +static int dmxCheckFunctionKeys(DMXLocalInputInfoPtr dmxLocal, + int type, + KeySym keySym) +{ + DMXInputInfo *dmxInput = &dmxInputs[dmxLocal->inputIdx]; + unsigned short state = 0; + +#if 1 /* hack to detect ctrl-alt-q, etc */ + static int ctrl = 0, alt = 0; + /* keep track of ctrl/alt key status */ + if (type == KeyPress && keySym == 0xffe3) { + ctrl = 1; + } + else if (type == KeyRelease && keySym == 0xffe3) { + ctrl = 0; + } + else if (type == KeyPress && keySym == 0xffe9) { + alt = 1; + } + else if (type == KeyRelease && keySym == 0xffe9) { + alt = 0; + } + if (!ctrl || !alt) + return 0; +#else + if (dmxLocal->sendsCore) + state = dmxLocalCoreKeyboard->pDevice->key->state; + else if (dmxLocal->pDevice->key) + state = dmxLocal->pDevice->key->state; + + DMXDBG3("dmxCheckFunctionKeys: keySym=0x%04x %s state=0x%04x\n", + keySym, type == KeyPress ? "press" : "release", state); + + if ((state & (ControlMask|Mod1Mask)) != (ControlMask|Mod1Mask)) + return 0; +#endif + + switch (keySym) { + case XK_g: + if (type == KeyPress) + dmxApplyFunctions(dmxInput, DMX_FUNCTION_GRAB); + return 1; + case XK_f: + if (type == KeyPress) + dmxApplyFunctions(dmxInput, DMX_FUNCTION_FINE); + return 1; + case XK_q: + if (type == KeyPress && dmxLocal->sendsCore) + if (dmxApplyFunctions(dmxInput, DMX_FUNCTION_TERMINATE)) { + dmxLog(dmxInfo, "User request for termination\n"); + dispatchException |= DE_TERMINATE; + } + return 1; + } + + return 0; +} + +#ifdef XINPUT +static void dmxEnqueueExtEvent(DMXLocalInputInfoPtr dmxLocal, xEvent *e, + DMXBlockType block) +{ + xEvent xE[2]; + deviceKeyButtonPointer *xev = (deviceKeyButtonPointer *)xE; + deviceValuator *xv = (deviceValuator *)xev+1; + DeviceIntPtr pDevice = dmxLocal->pDevice; + DMXInputInfo *dmxInput = &dmxInputs[dmxLocal->inputIdx]; + int type = e->u.u.type; + + switch (e->u.u.type) { + case KeyPress: + type = DeviceKeyPress; + break; + case KeyRelease: + type = DeviceKeyRelease; + break; + case ButtonPress: + type = DeviceButtonPress; + break; + case ButtonRelease: + type = DeviceButtonRelease; + break; + case MotionNotify: + dmxLog(dmxError, + "dmxEnqueueExtEvent: MotionNotify not allowed here\n"); + return; + default: + if (e->u.u.type == ProximityIn || e->u.u.type == ProximityOut) + break; + dmxLogInput(dmxInput, + "dmxEnqueueExtEvent: Unhandled %s event (%d)\n", + e->u.u.type >= LASTEvent ? "extension" : "non-extension", + e->u.u.type); + return; + } + + xev->type = type; + xev->detail = e->u.u.detail; + xev->deviceid = pDevice->id | MORE_EVENTS; + xev->time = e->u.keyButtonPointer.time; + + xv->type = DeviceValuator; + xv->deviceid = pDevice->id; + xv->num_valuators = 0; + xv->first_valuator = 0; + + if (block) + dmxSigioBlock(); + dmxeqEnqueue(xE); + if (block) + dmxSigioUnblock(); +} +#endif + +DMXScreenInfo *dmxFindFirstScreen(int x, int y) +{ + int i; + + for (i = 0; i < dmxNumScreens; i++) { + DMXScreenInfo *dmxScreen = &dmxScreens[i]; + if (dmxOnScreen(x, y, dmxScreen)) + return dmxScreen; + } + return NULL; +} + + +/** + * Enqueue a motion event. + */ +static void enqueueMotion(DevicePtr pDev, int x, int y) +{ + GETDMXLOCALFROMPDEV; + DeviceIntPtr p = dmxLocal->pDevice; + int i, nevents, valuators[3]; + xEvent *events = Xcalloc(sizeof(xEvent), GetMaximumEventsNum()); + int detail = 0; /* XXX should this be mask of pressed buttons? */ + valuators[0] = x; + valuators[1] = y; + nevents = GetPointerEvents(events, p, MotionNotify, detail, + POINTER_ABSOLUTE, 0, 2, valuators); + for (i = 0; i < nevents; i++) + mieqEnqueue(p, events + i); + xfree(events); + return; +} + + +void +dmxCoreMotion(DevicePtr pDev, int x, int y, int delta, DMXBlockType block) +{ + DMXScreenInfo *dmxScreen; + DMXInputInfo *dmxInput; + ScreenPtr pScreen; + int localX; + int localY; + int i; + + if (!dmxGlobalInvalid && dmxGlobalX == x && dmxGlobalY == y) + return; + + DMXDBG5("dmxCoreMotion(%d,%d,%d) dmxGlobalX=%d dmxGlobalY=%d\n", + x, y, delta, dmxGlobalX, dmxGlobalY); + + dmxGlobalInvalid = 0; + dmxGlobalX = x; + dmxGlobalY = y; + + if (dmxGlobalX < 0) + dmxGlobalX = 0; + if (dmxGlobalY < 0) + dmxGlobalY = 0; + if (dmxGlobalX >= dmxGlobalWidth) + dmxGlobalX = dmxGlobalWidth + delta -1; + if (dmxGlobalY >= dmxGlobalHeight) + dmxGlobalY = dmxGlobalHeight + delta -1; + + if ((dmxScreen = dmxFindFirstScreen(dmxGlobalX, dmxGlobalY))) { + localX = dmxGlobalX - dmxScreen->rootXOrigin; + localY = dmxGlobalY - dmxScreen->rootYOrigin; + if ((pScreen = miPointerGetScreen(inputInfo.pointer)) + && pScreen->myNum == dmxScreen->index) { + /* Screen is old screen */ + if (block) + dmxSigioBlock(); + if (pDev) + enqueueMotion(pDev, localX, localY); + if (block) + dmxSigioUnblock(); + } else { + /* Screen is new */ + DMXDBG4(" New screen: old=%d new=%d localX=%d localY=%d\n", + pScreen->myNum, dmxScreen->index, localX, localY); + if (block) + dmxSigioBlock(); + dmxeqProcessInputEvents(); + miPointerSetScreen(inputInfo.pointer, dmxScreen->index, + localX, localY); + if (pDev) + enqueueMotion(pDev, localX, localY); + if (block) + dmxSigioUnblock(); + } +#if 00 + miPointerGetPosition(inputInfo.pointer, &localX, &localY); + + if ((pScreen = miPointerGetScreen(inputInfo.pointer))) { + dmxGlobalX = localX + dmxScreens[pScreen->myNum].rootXOrigin; + dmxGlobalY = localY + dmxScreens[pScreen->myNum].rootYOrigin; + ErrorF("Global is now %d, %d %d, %d\n", dmxGlobalX, dmxGlobalY, + localX, localY); + DMXDBG6(" Moved to dmxGlobalX=%d dmxGlobalY=%d" + " on screen index=%d/%d localX=%d localY=%d\n", + dmxGlobalX, dmxGlobalY, + dmxScreen ? dmxScreen->index : -1, pScreen->myNum, + localX, localY); + } +#endif + } + /* Send updates down to all core input + * drivers */ + for (i = 0, dmxInput = &dmxInputs[0]; i < dmxNumInputs; i++, dmxInput++) { + int j; + for (j = 0; j < dmxInput->numDevs; j += dmxInput->devs[j]->binding) + if (!dmxInput->detached + && dmxInput->devs[j]->sendsCore + && dmxInput->devs[j]->update_position) + dmxInput->devs[j]->update_position(dmxInput->devs[j]->private, + dmxGlobalX, dmxGlobalY); + } + if (!dmxScreen) ProcessInputEvents(); +} + + + +#ifdef XINPUT +#define DMX_MAX_AXES 32 /* Max axes reported by this routine */ +static void dmxExtMotion(DMXLocalInputInfoPtr dmxLocal, + int *v, int firstAxis, int axesCount, + DMXMotionType type, DMXBlockType block) +{ + DeviceIntPtr pDevice = dmxLocal->pDevice; + xEvent xE[2 * DMX_MAX_AXES/6]; + deviceKeyButtonPointer *xev = (deviceKeyButtonPointer *)xE; + deviceValuator *xv = (deviceValuator *)xev+1; + int thisX = 0; + int thisY = 0; + int i; + int count; + + memset(xE, 0, sizeof(xE)); + + if (axesCount > DMX_MAX_AXES) axesCount = DMX_MAX_AXES; + + if (!pDevice->valuator->mode && axesCount == 2) { + /* The dmx console is a relative mode + * device that sometimes reports + * absolute motion. It only has two + * axes. */ + if (type == DMX_RELATIVE) { + thisX = -v[0]; + thisY = -v[1]; + dmxLocal->lastX += thisX; + dmxLocal->lastY += thisY; + if (dmxLocal->update_position) + dmxLocal->update_position(dmxLocal->private, + dmxLocal->lastX, dmxLocal->lastY); + } else { /* Convert to relative */ + if (dmxLocal->lastX || dmxLocal->lastY) { + thisX = v[0] - dmxLocal->lastX; + thisY = v[1] - dmxLocal->lastY; + } + dmxLocal->lastX = v[0]; + dmxLocal->lastY = v[1]; + } + v[0] = thisX; + v[1] = thisY; + } + + if (axesCount <= 6) { + /* Optimize for the common case when + * only 1 or 2 axes change. */ + xev->time = GetTimeInMillis(); + xev->type = DeviceMotionNotify; + xev->detail = 0; + xev->deviceid = pDevice->id | MORE_EVENTS; + + xv->type = DeviceValuator; + xv->deviceid = pDevice->id; + xv->num_valuators = axesCount; + xv->first_valuator = firstAxis; + switch (xv->num_valuators) { + case 6: xv->valuator5 = v[5]; + case 5: xv->valuator4 = v[4]; + case 4: xv->valuator3 = v[3]; + case 3: xv->valuator2 = v[2]; + case 2: xv->valuator1 = v[1]; + case 1: xv->valuator0 = v[0]; + } + count = 2; + } else { + for (i = 0, count = 0; i < axesCount; i += 6) { + xev->time = GetTimeInMillis(); + xev->type = DeviceMotionNotify; + xev->detail = 0; + xev->deviceid = pDevice->id | MORE_EVENTS; + xev += 2; + + xv->type = DeviceValuator; + xv->deviceid = pDevice->id; + xv->num_valuators = (i+6 >= axesCount ? axesCount - i : 6); + xv->first_valuator = firstAxis + i; + switch (xv->num_valuators) { + case 6: xv->valuator5 = v[i+5]; + case 5: xv->valuator4 = v[i+4]; + case 4: xv->valuator3 = v[i+3]; + case 3: xv->valuator2 = v[i+2]; + case 2: xv->valuator1 = v[i+1]; + case 1: xv->valuator0 = v[i+0]; + } + xv += 2; + count += 2; + } + } + + if (block) + dmxSigioBlock(); + dmxPointerPutMotionEvent(pDevice, firstAxis, axesCount, v, xev->time); + dmxeqEnqueue(xE); + if (block) + dmxSigioUnblock(); +} + +static int dmxTranslateAndEnqueueExtEvent(DMXLocalInputInfoPtr dmxLocal, + XEvent *e, DMXBlockType block) +{ + xEvent xE[2]; + deviceKeyButtonPointer *xev = (deviceKeyButtonPointer *)xE; + deviceValuator *xv = (deviceValuator *)xev+1; + int type; + int event = -1; + XDeviceKeyEvent *ke = (XDeviceKeyEvent *)e; + XDeviceMotionEvent *me = (XDeviceMotionEvent *)e; + + if (!e) + return -1; /* No extended event passed, cannot handle */ + + if ((XID)dmxLocal->deviceId != ke->deviceid) { + /* Search for the correct dmxLocal, + * since backend and console events are + * picked up for the first device on + * that X server. */ + int i; + DMXInputInfo *dmxInput = &dmxInputs[dmxLocal->inputIdx]; + for (i = 0; i < dmxInput->numDevs; i++) { + dmxLocal = dmxInput->devs[i]; + if ((XID)dmxLocal->deviceId == ke->deviceid) + break; + } + } + + if ((XID)dmxLocal->deviceId != ke->deviceid + || (type = dmxMapLookup(dmxLocal, e->type)) < 0) + return -1; /* No mapping, so this event is unhandled */ + + switch (type) { + case XI_DeviceValuator: event = DeviceValuator; break; + case XI_DeviceKeyPress: event = DeviceKeyPress; break; + case XI_DeviceKeyRelease: event = DeviceKeyRelease; break; + case XI_DeviceButtonPress: event = DeviceButtonPress; break; + case XI_DeviceButtonRelease: event = DeviceButtonRelease; break; + case XI_DeviceMotionNotify: event = DeviceMotionNotify; break; + case XI_DeviceFocusIn: event = DeviceFocusIn; break; + case XI_DeviceFocusOut: event = DeviceFocusOut; break; + case XI_ProximityIn: event = ProximityIn; break; + case XI_ProximityOut: event = ProximityOut; break; + case XI_DeviceStateNotify: event = DeviceStateNotify; break; + case XI_DeviceMappingNotify: event = DeviceMappingNotify; break; + case XI_ChangeDeviceNotify: event = ChangeDeviceNotify; break; + case XI_DeviceKeystateNotify: event = DeviceStateNotify; break; + case XI_DeviceButtonstateNotify: event = DeviceStateNotify; break; + } + + switch (type) { + case XI_DeviceKeyPress: + case XI_DeviceKeyRelease: + case XI_DeviceButtonPress: + case XI_DeviceButtonRelease: + case XI_ProximityIn: + case XI_ProximityOut: + xev->type = event; + xev->detail = ke->keycode; /* same as ->button */ + xev->deviceid = dmxLocal->pDevice->id | MORE_EVENTS; + xev->time = GetTimeInMillis(); + + xv->type = DeviceValuator; + xv->deviceid = dmxLocal->pDevice->id; + xv->num_valuators = ke->axes_count; + xv->first_valuator = ke->first_axis; + xv->valuator0 = ke->axis_data[0]; + xv->valuator1 = ke->axis_data[1]; + xv->valuator2 = ke->axis_data[2]; + xv->valuator3 = ke->axis_data[3]; + xv->valuator4 = ke->axis_data[4]; + xv->valuator5 = ke->axis_data[5]; + + if (block) + dmxSigioBlock(); + dmxeqEnqueue(xE); + if (block) + dmxSigioUnblock(); + break; + + case XI_DeviceMotionNotify: + dmxExtMotion(dmxLocal, me->axis_data, me->first_axis, me->axes_count, + DMX_ABSOLUTE, block); + break; + case XI_DeviceFocusIn: + case XI_DeviceFocusOut: + case XI_DeviceStateNotify: + case XI_DeviceMappingNotify: + case XI_ChangeDeviceNotify: + case XI_DeviceKeystateNotify: + case XI_DeviceButtonstateNotify: + /* These are ignored, since DMX will + * generate its own events of these + * types, as necessary. + + * Perhaps ChangeDeviceNotify should + * generate an error, because it is + * unexpected? */ + break; + case XI_DeviceValuator: + default: + dmxLog(dmxWarning, + "XInput extension event (remote=%d -> zero-based=%d)" + " not supported yet\n", e->type, type); + return -1; + } + return 0; +} +#endif + +static int dmxGetButtonMapping(DMXLocalInputInfoPtr dmxLocal, int button) +{ + ButtonClassPtr b = dmxLocal->pDevice->button; + + if (button > b->numButtons) { /* This shouldn't happen. */ + dmxLog(dmxWarning, "Button %d pressed, but only %d buttons?!?\n", + button, b->numButtons); + return button; + } + return b->map[button]; +} + +/** Return DMX's notion of the pointer position in the global coordinate + * space. */ +void dmxGetGlobalPosition(int *x, int *y) +{ + *x = dmxGlobalX; + *y = dmxGlobalY; +} + +/** Invalidate the global position for #dmxCoreMotion. */ +void dmxInvalidateGlobalPosition(void) +{ + dmxGlobalInvalid = 1; +} + +/** Enqueue a motion event for \a pDev. The \a v vector has length \a + * axesCount, and contains values for each of the axes, starting at \a + * firstAxes. + * + * The \a type of the motion may be \a DMX_RELATIVE, \a DMX_ABSOLUTE, or + * \a DMX_ABSOLUTE_CONFINED (in the latter case, the pointer will not be + * allowed to move outside the global boundaires). + * + * If \a block is set to \a DMX_BLOCK, then the SIGIO handler will be + * blocked around calls to #dmxeqEnqueue(). */ +void dmxMotion(DevicePtr pDev, int *v, int firstAxes, int axesCount, + DMXMotionType type, DMXBlockType block) +{ +#ifdef XINPUT + GETDMXLOCALFROMPDEV; + + if (!dmxLocal->sendsCore) { + dmxExtMotion(dmxLocal, v, firstAxes, axesCount, type, block); + return; + } +#endif + if (axesCount == 2) { + switch (type) { + case DMX_RELATIVE: + dmxCoreMotion(pDev, dmxGlobalX - v[0], dmxGlobalY - v[1], 0, block); + break; + case DMX_ABSOLUTE: + dmxCoreMotion(pDev, v[0], v[1], 0, block); + break; + case DMX_ABSOLUTE_CONFINED: + dmxCoreMotion(pDev, v[0], v[1], -1, block); + break; + } + } +} + +static KeySym dmxKeyCodeToKeySym(DMXLocalInputInfoPtr dmxLocal, + KeyCode keyCode) +{ + KeySymsPtr pKeySyms = NULL; + + if (!dmxLocal || !dmxLocal->pDevice || !dmxLocal->pDevice->key) + return NoSymbol; + pKeySyms = &dmxLocal->pDevice->key->curKeySyms; + if (!pKeySyms) + return NoSymbol; + + if (keyCode > pKeySyms->minKeyCode && keyCode <= pKeySyms->maxKeyCode) { + DMXDBG2("dmxKeyCodeToKeySym: Translated keyCode=%d to keySym=0x%04x\n", + keyCode, + pKeySyms->map[(keyCode - pKeySyms->minKeyCode) + * pKeySyms->mapWidth]); + + return pKeySyms->map[(keyCode - pKeySyms->minKeyCode) + * pKeySyms->mapWidth]; + } + return NoSymbol; +} + +static KeyCode dmxKeySymToKeyCode(DMXLocalInputInfoPtr dmxLocal, KeySym keySym, + int tryFirst) +{ + KeySymsPtr pKeySyms = &dmxLocal->pDevice->key->curKeySyms; + int i; + + /* Optimize for similar maps */ + if (tryFirst >= pKeySyms->minKeyCode + && tryFirst <= pKeySyms->maxKeyCode + && pKeySyms->map[(tryFirst - pKeySyms->minKeyCode) + * pKeySyms->mapWidth] == keySym) + return tryFirst; + + for (i = pKeySyms->minKeyCode; i <= pKeySyms->maxKeyCode; i++) { + if (pKeySyms->map[(i - pKeySyms->minKeyCode) + * pKeySyms->mapWidth] == keySym) { + DMXDBG3("dmxKeySymToKeyCode: Translated keySym=0x%04x to" + " keyCode=%d (reverses to core keySym=0x%04x)\n", + keySym, i, dmxKeyCodeToKeySym(dmxLocalCoreKeyboard,i)); + return i; + } + } + return 0; +} + +static int dmxFixup(DevicePtr pDev, int detail, KeySym keySym) +{ + GETDMXLOCALFROMPDEV; + int keyCode; + + if (!dmxLocal->pDevice->key) { + dmxLog(dmxWarning, "dmxFixup: not a keyboard device (%s)\n", + dmxLocal->pDevice->name); + return NoSymbol; + } + if (!keySym) + keySym = dmxKeyCodeToKeySym(dmxLocal, detail); + if (keySym == NoSymbol) + return detail; + keyCode = dmxKeySymToKeyCode(dmxLocalCoreKeyboard, keySym, detail); + + return keyCode ? keyCode : detail; +} + +/** Enqueue an event from the \a pDev device with the + * specified \a type and \a detail. If the event is a KeyPress or + * KeyRelease event, then the \a keySym is also specified. + * + * If \a block is set to \a DMX_BLOCK, then the SIGIO handler will be + * blocked around calls to #dmxeqEnqueue(). */ + +void dmxEnqueue(DevicePtr pDev, int type, int detail, KeySym keySym, + XEvent *e, DMXBlockType block) +{ + GETDMXINPUTFROMPDEV; + xEvent xE; + DeviceIntPtr p = dmxLocal->pDevice; + int i, nevents, valuators[3]; + xEvent *events; + + DMXDBG2("dmxEnqueue: Enqueuing type=%d detail=0x%0x\n", type, detail); + + switch (type) { + case KeyPress: + case KeyRelease: + if (!keySym) + keySym = dmxKeyCodeToKeySym(dmxLocal, detail); + if (dmxCheckFunctionKeys(dmxLocal, type, keySym)) + return; + if (dmxLocal->sendsCore && dmxLocal != dmxLocalCoreKeyboard) + xE.u.u.detail = dmxFixup(pDev, detail, keySym); + + events = Xcalloc(sizeof(xEvent), GetMaximumEventsNum()); + /*ErrorF("KEY %d sym %d\n", detail, (int) keySym);*/ + nevents = GetKeyboardEvents(events, p, type, detail); + for (i = 0; i < nevents; i++) + mieqEnqueue(p, events + i); + xfree(events); + return; + + case ButtonPress: + case ButtonRelease: + detail = dmxGetButtonMapping(dmxLocal, detail); + events = Xcalloc(sizeof(xEvent), GetMaximumEventsNum()); + nevents = GetPointerEvents(events, p, type, detail, + POINTER_ABSOLUTE, + 0, /* first_valuator = 0 */ + 0, /* num_valuators = 0 */ + valuators); + for (i = 0; i < nevents; i++) + mieqEnqueue(p, events + i); + xfree(events); + return; + + case MotionNotify: + events = Xcalloc(sizeof(xEvent), GetMaximumEventsNum()); + valuators[0] = e->xmotion.x; + valuators[1] = e->xmotion.y; + valuators[2] = e->xmotion.state; + nevents = GetPointerEvents(events, p, type, detail, + POINTER_ABSOLUTE, 0, 3, valuators); + for (i = 0; i < nevents; i++) + mieqEnqueue(p, events + i); + xfree(events); + return; + + case EnterNotify: + case LeaveNotify: + case KeymapNotify: + case MappingNotify: /* This is sent because we change the + * modifier map on the backend/console + * input device so that we have complete + * control of the input device LEDs. */ + return; + default: +#ifdef XINPUT + if (type == ProximityIn || type == ProximityOut) { + if (dmxLocal->sendsCore) + return; /* Not a core event */ + break; + } +#endif + if (type >= LASTEvent) { +#ifdef XINPUT + if (dmxTranslateAndEnqueueExtEvent(dmxLocal, e, block)) +#endif + dmxLogInput(dmxInput, "Unhandled extension event: %d\n", type); + } else { + dmxLogInput(dmxInput, "Unhandled event: %d (%s)\n", + type, dmxEventName(type)); + } + return; + } + +#if 00 /* dead code? */ + memset(&xE, 0, sizeof(xE)); + xE.u.u.type = type; + xE.u.u.detail = detail; + xE.u.keyButtonPointer.time = GetTimeInMillis(); + +#ifdef XINPUT + if (!dmxLocal->sendsCore) + dmxEnqueueExtEvent(dmxLocal, &xE, block); + else +#endif + dmxeqEnqueue(&xE); +#endif /*00*/ +} + +/** A pointer to this routine is passed to low-level input drivers so + * that all special keychecking is unified to this file. This function + * returns 0 if no special keys have been pressed. If the user has + * requested termination of the DMX server, -1 is returned. If the user + * has requested a switch to a VT, then the (1-based) number of that VT + * is returned. */ +int dmxCheckSpecialKeys(DevicePtr pDev, KeySym keySym) +{ + GETDMXINPUTFROMPDEV; + int vt = 0; + unsigned short state = 0; + + if (dmxLocal->sendsCore) + state = dmxLocalCoreKeyboard->pDevice->key->state; + else if (dmxLocal->pDevice->key) + state = dmxLocal->pDevice->key->state; + + if (!dmxLocal->sendsCore) return 0; /* Only for core devices */ + + DMXDBG2("dmxCheckSpecialKeys: keySym=0x%04x state=0x%04x\n", keySym,state); + + if ((state & (ControlMask|Mod1Mask)) != (ControlMask|Mod1Mask)) return 0; + + switch (keySym) { + case XK_F1: + case XK_F2: + case XK_F3: + case XK_F4: + case XK_F5: + case XK_F6: + case XK_F7: + case XK_F8: + case XK_F9: + case XK_F10: + vt = keySym - XK_F1 + 1; + break; + + case XK_F11: + case XK_F12: + vt = keySym - XK_F11 + 11; + break; + + case XK_q: /* To avoid confusion */ + case XK_BackSpace: + case XK_Delete: + case XK_KP_Delete: + dmxLog(dmxInfo, "User request for termination\n"); + dispatchException |= DE_TERMINATE; + return -1; /* Terminate */ + } + + if (vt) { + dmxLog(dmxInfo, "Request to switch to VT %d\n", vt); + dmxInput->vt_switch_pending = vt; + return vt; + } + + return 0; /* Do nothing */ +} diff --git a/xorg-server/hw/dmx/input/dmxevents.h b/xorg-server/hw/dmx/input/dmxevents.h new file mode 100644 index 000000000..fe8712ebe --- /dev/null +++ b/xorg-server/hw/dmx/input/dmxevents.h @@ -0,0 +1,46 @@ +/* + * Copyright 2001 Red Hat Inc., Durham, North Carolina. + * + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation on the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NON-INFRINGEMENT. IN NO EVENT SHALL RED HAT AND/OR THEIR SUPPLIERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* + * Authors: + * Rickard E. (Rik) Faith <faith@redhat.com> + * + */ + +/** \file + * Interface to event processing functions. \see dmxevents.h */ + +#ifndef _DMXEVENTS_H_ +#define _DMXEVENTS_H_ + +extern void dmxMotion(DevicePtr pDev, int *v, int firstAxis, int axesCount, + DMXMotionType type, DMXBlockType block); +extern void dmxEnqueue(DevicePtr pDev, int type, int detail, KeySym keySym, + XEvent *e, DMXBlockType block); +extern int dmxCheckSpecialKeys(DevicePtr pDev, KeySym keySym); +extern void dmxInvalidateGlobalPosition(void); +#endif diff --git a/xorg-server/hw/dmx/input/dmxinputinit.c b/xorg-server/hw/dmx/input/dmxinputinit.c new file mode 100644 index 000000000..fd4eeaacb --- /dev/null +++ b/xorg-server/hw/dmx/input/dmxinputinit.c @@ -0,0 +1,1368 @@ +/* + * Copyright 2002-2003 Red Hat Inc., Durham, North Carolina. + * + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation on the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NON-INFRINGEMENT. IN NO EVENT SHALL RED HAT AND/OR THEIR SUPPLIERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* + * Authors: + * Rickard E. (Rik) Faith <faith@redhat.com> + * + */ + +/** \file + * This file provides generic input support. Functions here set up + * input and lead to the calling of low-level device drivers for + * input. */ + +#ifdef HAVE_DMX_CONFIG_H +#include <dmx-config.h> +#endif + +#define DMX_WINDOW_DEBUG 0 + +#include "dmxinputinit.h" +#include "dmxextension.h" /* For dmxInputCount */ + +#include "dmxdummy.h" +#include "dmxbackend.h" +#include "dmxconsole.h" +#include "dmxcommon.h" +#include "dmxevents.h" +#include "dmxmotion.h" +#include "dmxeq.h" +#include "dmxprop.h" +#include "config/dmxconfig.h" +#include "dmxcursor.h" + +#include "lnx-keyboard.h" +#include "lnx-ms.h" +#include "lnx-ps2.h" +#include "usb-keyboard.h" +#include "usb-mouse.h" +#include "usb-other.h" +#include "usb-common.h" + +#include "dmxsigio.h" +#include "dmxarg.h" + +#include "inputstr.h" +#include "input.h" +#include "mipointer.h" +#include "windowstr.h" +#include "mi.h" + +#ifdef XINPUT +#include <X11/extensions/XI.h> +#include <X11/extensions/XIproto.h> +#include "exevents.h" +#define EXTENSION_PROC_ARGS void * +#include "extinit.h" +#endif + +/* From XI.h */ +#ifndef Relative +#define Relative 0 +#endif +#ifndef Absolute +#define Absolute 1 +#endif + +DMXLocalInputInfoPtr dmxLocalCorePointer, dmxLocalCoreKeyboard; + +static DMXLocalInputInfoRec DMXDummyMou = { + "dummy-mou", DMX_LOCAL_MOUSE, DMX_LOCAL_TYPE_LOCAL, 1, + NULL, NULL, NULL, NULL, NULL, dmxDummyMouGetInfo +}; + +static DMXLocalInputInfoRec DMXDummyKbd = { + "dummy-kbd", DMX_LOCAL_KEYBOARD, DMX_LOCAL_TYPE_LOCAL, 1, + NULL, NULL, NULL, NULL, NULL, dmxDummyKbdGetInfo +}; + +static DMXLocalInputInfoRec DMXBackendMou = { + "backend-mou", DMX_LOCAL_MOUSE, DMX_LOCAL_TYPE_BACKEND, 2, + dmxBackendCreatePrivate, dmxBackendDestroyPrivate, + dmxBackendInit, NULL, dmxBackendLateReInit, dmxBackendMouGetInfo, + dmxCommonMouOn, dmxCommonMouOff, dmxBackendUpdatePosition, + NULL, NULL, NULL, + dmxBackendCollectEvents, dmxBackendProcessInput, dmxBackendFunctions, NULL, + dmxCommonMouCtrl +}; + +static DMXLocalInputInfoRec DMXBackendKbd = { + "backend-kbd", DMX_LOCAL_KEYBOARD, DMX_LOCAL_TYPE_BACKEND, + 1, /* With backend-mou or console-mou */ + dmxCommonCopyPrivate, NULL, + dmxBackendInit, NULL, NULL, dmxBackendKbdGetInfo, + dmxCommonKbdOn, dmxCommonKbdOff, NULL, + NULL, NULL, NULL, + NULL, NULL, NULL, NULL, + NULL, dmxCommonKbdCtrl, dmxCommonKbdBell +}; + +static DMXLocalInputInfoRec DMXConsoleMou = { + "console-mou", DMX_LOCAL_MOUSE, DMX_LOCAL_TYPE_CONSOLE, 2, + dmxConsoleCreatePrivate, dmxConsoleDestroyPrivate, + dmxConsoleInit, dmxConsoleReInit, NULL, dmxConsoleMouGetInfo, + dmxCommonMouOn, dmxCommonMouOff, dmxConsoleUpdatePosition, + NULL, NULL, NULL, + dmxConsoleCollectEvents, NULL, dmxConsoleFunctions, dmxConsoleUpdateInfo, + dmxCommonMouCtrl +}; + +static DMXLocalInputInfoRec DMXConsoleKbd = { + "console-kbd", DMX_LOCAL_KEYBOARD, DMX_LOCAL_TYPE_CONSOLE, + 1, /* With backend-mou or console-mou */ + dmxCommonCopyPrivate, NULL, + dmxConsoleInit, dmxConsoleReInit, NULL, dmxConsoleKbdGetInfo, + dmxCommonKbdOn, dmxCommonKbdOff, NULL, + NULL, NULL, NULL, + NULL, NULL, NULL, NULL, + NULL, dmxCommonKbdCtrl, dmxCommonKbdBell +}; + +static DMXLocalInputInfoRec DMXCommonOth = { + "common-oth", DMX_LOCAL_OTHER, DMX_LOCAL_TYPE_COMMON, 1, + dmxCommonCopyPrivate, NULL, + NULL, NULL, NULL, dmxCommonOthGetInfo, + dmxCommonOthOn, dmxCommonOthOff +}; + + +static DMXLocalInputInfoRec DMXLocalDevices[] = { + /* Dummy drivers that can compile on any OS */ +#ifdef __linux__ + /* Linux-specific drivers */ + { + "kbd", DMX_LOCAL_KEYBOARD, DMX_LOCAL_TYPE_LOCAL, 1, + kbdLinuxCreatePrivate, kbdLinuxDestroyPrivate, + kbdLinuxInit, NULL, NULL, kbdLinuxGetInfo, + kbdLinuxOn, kbdLinuxOff, NULL, + kbdLinuxVTPreSwitch, kbdLinuxVTPostSwitch, kbdLinuxVTSwitch, + kbdLinuxRead, NULL, NULL, NULL, + NULL, kbdLinuxCtrl, kbdLinuxBell + }, + { + "ms", DMX_LOCAL_MOUSE, DMX_LOCAL_TYPE_LOCAL, 1, + msLinuxCreatePrivate, msLinuxDestroyPrivate, + msLinuxInit, NULL, NULL, msLinuxGetInfo, + msLinuxOn, msLinuxOff, NULL, + msLinuxVTPreSwitch, msLinuxVTPostSwitch, NULL, + msLinuxRead + }, + { + "ps2", DMX_LOCAL_MOUSE, DMX_LOCAL_TYPE_LOCAL, 1, + ps2LinuxCreatePrivate, ps2LinuxDestroyPrivate, + ps2LinuxInit, NULL, NULL, ps2LinuxGetInfo, + ps2LinuxOn, ps2LinuxOff, NULL, + ps2LinuxVTPreSwitch, ps2LinuxVTPostSwitch, NULL, + ps2LinuxRead + }, +#endif +#ifdef __linux__ + /* USB drivers, currently only for + Linux, but relatively easy to port to + other OSs */ + { + "usb-kbd", DMX_LOCAL_KEYBOARD, DMX_LOCAL_TYPE_LOCAL, 1, + usbCreatePrivate, usbDestroyPrivate, + kbdUSBInit, NULL, NULL, kbdUSBGetInfo, + kbdUSBOn, usbOff, NULL, + NULL, NULL, NULL, + kbdUSBRead, NULL, NULL, NULL, + NULL, kbdUSBCtrl + }, + { + "usb-mou", DMX_LOCAL_MOUSE, DMX_LOCAL_TYPE_LOCAL, 1, + usbCreatePrivate, usbDestroyPrivate, + mouUSBInit, NULL, NULL, mouUSBGetInfo, + mouUSBOn, usbOff, NULL, + NULL, NULL, NULL, + mouUSBRead + }, + { + "usb-oth", DMX_LOCAL_OTHER, DMX_LOCAL_TYPE_LOCAL, 1, + usbCreatePrivate, usbDestroyPrivate, + othUSBInit, NULL, NULL, othUSBGetInfo, + othUSBOn, usbOff, NULL, + NULL, NULL, NULL, + othUSBRead + }, +#endif + { + "dummy-mou", DMX_LOCAL_MOUSE, DMX_LOCAL_TYPE_LOCAL, 1, + NULL, NULL, NULL, NULL, NULL, dmxDummyMouGetInfo + }, + { + "dummy-kbd", DMX_LOCAL_KEYBOARD, DMX_LOCAL_TYPE_LOCAL, 1, + NULL, NULL, NULL, NULL, NULL, dmxDummyKbdGetInfo + }, + { NULL } /* Must be last */ +}; + + +#if 11 /*BP*/ +void +DDXRingBell(int volume, int pitch, int duration) +{ + /* NO-OP */ +} + +/* taken from kdrive/src/kinput.c: */ +static void +dmxKbdCtrl (DeviceIntPtr pDevice, KeybdCtrl *ctrl) +{ +#if 0 + KdKeyboardInfo *ki; + + for (ki = kdKeyboards; ki; ki = ki->next) { + if (ki->dixdev && ki->dixdev->id == pDevice->id) + break; + } + + if (!ki || !ki->dixdev || ki->dixdev->id != pDevice->id || !ki->driver) + return; + + KdSetLeds(ki, ctrl->leds); + ki->bellPitch = ctrl->bell_pitch; + ki->bellDuration = ctrl->bell_duration; +#endif +} + +/* taken from kdrive/src/kinput.c: */ +static void +dmxBell(int volume, DeviceIntPtr pDev, pointer arg, int something) +{ +#if 0 + KeybdCtrl *ctrl = arg; + KdKeyboardInfo *ki = NULL; + + for (ki = kdKeyboards; ki; ki = ki->next) { + if (ki->dixdev && ki->dixdev->id == pDev->id) + break; + } + + if (!ki || !ki->dixdev || ki->dixdev->id != pDev->id || !ki->driver) + return; + + KdRingBell(ki, volume, ctrl->bell_pitch, ctrl->bell_duration); +#endif +} + +#endif /*BP*/ + +static void _dmxChangePointerControl(DMXLocalInputInfoPtr dmxLocal, + PtrCtrl *ctrl) +{ + if (!dmxLocal) return; + dmxLocal->mctrl = *ctrl; + if (dmxLocal->mCtrl) dmxLocal->mCtrl(&dmxLocal->pDevice->public, ctrl); +} + +/** Change the pointer control information for the \a pDevice. If the + * device sends core events, then also change the control information + * for all of the pointer devices that send core events. */ +void dmxChangePointerControl(DeviceIntPtr pDevice, PtrCtrl *ctrl) +{ + GETDMXLOCALFROMPDEVICE; + int i, j; + + if (dmxLocal->sendsCore) { /* Do for all core devices */ + for (i = 0; i < dmxNumInputs; i++) { + DMXInputInfo *dmxInput = &dmxInputs[i]; + if (dmxInput->detached) continue; + for (j = 0; j < dmxInput->numDevs; j++) + if (dmxInput->devs[j]->sendsCore) + _dmxChangePointerControl(dmxInput->devs[j], ctrl); + } + } else { /* Do for this device only */ + _dmxChangePointerControl(dmxLocal, ctrl); + } +} + +static void _dmxKeyboardKbdCtrlProc(DMXLocalInputInfoPtr dmxLocal, + KeybdCtrl *ctrl) +{ + dmxLocal->kctrl = *ctrl; + if (dmxLocal->kCtrl) { + dmxLocal->kCtrl(&dmxLocal->pDevice->public, ctrl); +#ifdef XKB + if (!noXkbExtension && dmxLocal->pDevice->kbdfeed) { + XkbEventCauseRec cause; + XkbSetCauseUnknown(&cause); + /* Generate XKB events, as necessary */ + XkbUpdateIndicators(dmxLocal->pDevice, XkbAllIndicatorsMask, False, + NULL, &cause); + } +#endif + } +} + + +/** Change the keyboard control information for the \a pDevice. If the + * device sends core events, then also change the control information + * for all of the keyboard devices that send core events. */ +void dmxKeyboardKbdCtrlProc(DeviceIntPtr pDevice, KeybdCtrl *ctrl) +{ + GETDMXLOCALFROMPDEVICE; + int i, j; + + if (dmxLocal->sendsCore) { /* Do for all core devices */ + for (i = 0; i < dmxNumInputs; i++) { + DMXInputInfo *dmxInput = &dmxInputs[i]; + if (dmxInput->detached) continue; + for (j = 0; j < dmxInput->numDevs; j++) + if (dmxInput->devs[j]->sendsCore) + _dmxKeyboardKbdCtrlProc(dmxInput->devs[j], ctrl); + } + } else { /* Do for this device only */ + _dmxKeyboardKbdCtrlProc(dmxLocal, ctrl); + } +} + +static void _dmxKeyboardBellProc(DMXLocalInputInfoPtr dmxLocal, int percent) +{ + if (dmxLocal->kBell) dmxLocal->kBell(&dmxLocal->pDevice->public, + percent, + dmxLocal->kctrl.bell, + dmxLocal->kctrl.bell_pitch, + dmxLocal->kctrl.bell_duration); +} + +/** Sound the bell on the device. If the device send core events, then + * sound the bell on all of the devices that send core events. */ +void dmxKeyboardBellProc(int percent, DeviceIntPtr pDevice, + pointer ctrl, int unknown) +{ + GETDMXLOCALFROMPDEVICE; + int i, j; + + if (dmxLocal->sendsCore) { /* Do for all core devices */ + for (i = 0; i < dmxNumInputs; i++) { + DMXInputInfo *dmxInput = &dmxInputs[i]; + if (dmxInput->detached) continue; + for (j = 0; j < dmxInput->numDevs; j++) + if (dmxInput->devs[j]->sendsCore) + _dmxKeyboardBellProc(dmxInput->devs[j], percent); + } + } else { /* Do for this device only */ + _dmxKeyboardBellProc(dmxLocal, percent); + } +} + +#ifdef XKB +static void dmxKeyboardFreeNames(XkbComponentNamesPtr names) +{ + if (names->keymap) XFree(names->keymap); + if (names->keycodes) XFree(names->keycodes); + if (names->types) XFree(names->types); + if (names->compat) XFree(names->compat); + if (names->symbols) XFree(names->symbols); + if (names->geometry) XFree(names->geometry); +} +#endif + + +static int dmxKeyboardOn(DeviceIntPtr pDevice, DMXLocalInitInfo *info) +{ +#ifdef XKB + GETDMXINPUTFROMPDEVICE; +#else + DevicePtr pDev = &pDevice->public; +#endif + +#ifdef XKB + if (noXkbExtension) { +#endif + if (!InitKeyboardDeviceStruct(pDev, &info->keySyms, info->modMap, + dmxKeyboardBellProc, + dmxKeyboardKbdCtrlProc)) + return BadImplementation; +#ifdef XKB + } else { + XkbSetRulesDflts(dmxConfigGetXkbRules(), + dmxConfigGetXkbModel(), + dmxConfigGetXkbLayout(), + dmxConfigGetXkbVariant(), + dmxConfigGetXkbOptions()); + if (!info->force && (dmxInput->keycodes + || dmxInput->symbols + || dmxInput->geometry)) { + if (info->freenames) dmxKeyboardFreeNames(&info->names); + info->freenames = 0; + info->names.keycodes = dmxInput->keycodes; + info->names.types = NULL; + info->names.compat = NULL; + info->names.symbols = dmxInput->symbols; + info->names.geometry = dmxInput->geometry; + + dmxLogInput(dmxInput, "XKEYBOARD: From command line: %s", + info->names.keycodes); + if (info->names.symbols && *info->names.symbols) + dmxLogInputCont(dmxInput, " %s", info->names.symbols); + if (info->names.geometry && *info->names.geometry) + dmxLogInputCont(dmxInput, " %s", info->names.geometry); + dmxLogInputCont(dmxInput, "\n"); + } else if (info->names.keycodes) { + dmxLogInput(dmxInput, "XKEYBOARD: From device: %s", + info->names.keycodes); + if (info->names.symbols && *info->names.symbols) + dmxLogInputCont(dmxInput, " %s", info->names.symbols); + if (info->names.geometry && *info->names.geometry) + dmxLogInputCont(dmxInput, " %s", info->names.geometry); + dmxLogInputCont(dmxInput, "\n"); + } else { + dmxLogInput(dmxInput, "XKEYBOARD: Defaults: %s %s %s %s %s\n", + dmxConfigGetXkbRules(), + dmxConfigGetXkbLayout(), + dmxConfigGetXkbModel(), + dmxConfigGetXkbVariant() + ? dmxConfigGetXkbVariant() : "", + dmxConfigGetXkbOptions() + ? dmxConfigGetXkbOptions() : ""); + } + XkbInitKeyboardDeviceStruct(pDevice, + &info->names, + &info->keySyms, + info->modMap, + dmxKeyboardBellProc, + dmxKeyboardKbdCtrlProc); + } + if (info->freenames) dmxKeyboardFreeNames(&info->names); +#endif + + return Success; +} + + +static int dmxDeviceOnOff(DeviceIntPtr pDevice, int what) +{ + GETDMXINPUTFROMPDEVICE; + int fd; + DMXLocalInitInfo info; +#ifdef XINPUT + int i; +#endif + + if (dmxInput->detached) return Success; + + memset(&info, 0, sizeof(info)); + switch (what) { + case DEVICE_INIT: + if (dmxLocal->init) + dmxLocal->init(pDev); + if (dmxLocal->get_info) + dmxLocal->get_info(pDev, &info); + if (info.keyboard) { /* XKEYBOARD makes this a special case */ + dmxKeyboardOn(pDevice, &info); + break; + } + if (info.keyClass) { +#if 00 /*BP*/ + InitKeyClassDeviceStruct(pDevice, &info.keySyms, info.modMap); +#else + DevicePtr pDev = (DevicePtr) pDevice; + InitKeyboardDeviceStruct(pDev, + &info.keySyms, + info.modMap, + dmxBell, dmxKbdCtrl); +#endif + } + if (info.buttonClass) { + InitButtonClassDeviceStruct(pDevice, info.numButtons, info.map); + } + if (info.valuatorClass) { + if (info.numRelAxes && dmxLocal->sendsCore) { + InitValuatorClassDeviceStruct(pDevice, info.numRelAxes, +#if 00 /*BP*/ + miPointerGetMotionEvents, + miPointerGetMotionBufferSize(), +#else + GetMotionHistory, + GetMaximumEventsNum(), +#endif + Relative); +#ifdef XINPUT + for (i = 0; i < info.numRelAxes; i++) + InitValuatorAxisStruct(pDevice, i, info.minval[0], + info.maxval[0], info.res[0], + info.minres[0], info.maxres[0]); +#endif + } else if (info.numRelAxes) { + InitValuatorClassDeviceStruct(pDevice, info.numRelAxes, + dmxPointerGetMotionEvents, + dmxPointerGetMotionBufferSize(), + Relative); +#ifdef XINPUT + for (i = 0; i < info.numRelAxes; i++) + InitValuatorAxisStruct(pDevice, i, info.minval[0], + info.maxval[0], info.res[0], + info.minres[0], info.maxres[0]); +#endif + } else if (info.numAbsAxes) { + InitValuatorClassDeviceStruct(pDevice, info.numAbsAxes, + dmxPointerGetMotionEvents, + dmxPointerGetMotionBufferSize(), + Absolute); +#ifdef XINPUT + for (i = 0; i < info.numAbsAxes; i++) + InitValuatorAxisStruct(pDevice, i+info.numRelAxes, + info.minval[i+1], info.maxval[i+1], + info.res[i+1], info.minres[i+1], + info.maxres[i+1]); +#endif + } + } + if (info.focusClass) InitFocusClassDeviceStruct(pDevice); +#ifdef XINPUT + if (info.proximityClass) InitProximityClassDeviceStruct(pDevice); +#endif + if (info.ptrFeedbackClass) + InitPtrFeedbackClassDeviceStruct(pDevice, dmxChangePointerControl); + if (info.kbdFeedbackClass) + InitKbdFeedbackClassDeviceStruct(pDevice, dmxKeyboardBellProc, + dmxKeyboardKbdCtrlProc); + if (info.intFeedbackClass || info.strFeedbackClass) + dmxLog(dmxWarning, + "Integer and string feedback not supported for %s\n", + pDevice->name); + if (!info.keyboard && (info.ledFeedbackClass || info.belFeedbackClass)) + dmxLog(dmxWarning, + "Led and bel feedback not supported for non-keyboard %s\n", + pDevice->name); + break; + case DEVICE_ON: + if (!pDev->on) { + if (dmxLocal->on && (fd = dmxLocal->on(pDev)) >= 0) + dmxSigioRegister(dmxInput, fd); + pDev->on = TRUE; + } + break; + case DEVICE_OFF: + case DEVICE_CLOSE: + /* This can get called twice consecutively: once for a + * detached screen (DEVICE_OFF), and then again at server + * generation time (DEVICE_CLOSE). */ + if (pDev->on) { + dmxSigioUnregister(dmxInput); + if (dmxLocal->off) dmxLocal->off(pDev); + pDev->on = FALSE; + } + break; + } + if (info.keySyms.map && info.freemap) { + XFree(info.keySyms.map); + info.keySyms.map = NULL; + } +#ifdef XKB + if (info.xkb) XkbFreeKeyboard(info.xkb, 0, True); +#endif + return Success; +} + +static void dmxProcessInputEvents(DMXInputInfo *dmxInput) +{ + int i; + + dmxeqProcessInputEvents(); +#if 00 /*BP*/ + miPointerUpdate(); +#endif + if (dmxInput->detached) + return; + for (i = 0; i < dmxInput->numDevs; i += dmxInput->devs[i]->binding) + if (dmxInput->devs[i]->process_input) { +#if 11 /*BP*/ + miPointerUpdateSprite(dmxInput->devs[i]->pDevice); +#endif + dmxInput->devs[i]->process_input(dmxInput->devs[i]->private); + } + +#if 11 /*BP*/ + mieqProcessInputEvents(); +#endif +} + +static void dmxUpdateWindowInformation(DMXInputInfo *dmxInput, + DMXUpdateType type, + WindowPtr pWindow) +{ + int i; + +#ifdef PANORAMIX + if (!noPanoramiXExtension && pWindow && pWindow->parent != WindowTable[0]) + return; +#endif +#if DMX_WINDOW_DEBUG + { + const char *name = "Unknown"; + switch (type) { + case DMX_UPDATE_REALIZE: name = "Realize"; break; + case DMX_UPDATE_UNREALIZE: name = "Unrealize"; break; + case DMX_UPDATE_RESTACK: name = "Restack"; break; + case DMX_UPDATE_COPY: name = "Copy"; break; + case DMX_UPDATE_RESIZE: name = "Resize"; break; + case DMX_UPDATE_REPARENT: name = "Repaint"; break; + } + dmxLog(dmxDebug, "Window %p changed: %s\n", pWindow, name); + } +#endif + + if (dmxInput->detached) + return; + for (i = 0; i < dmxInput->numDevs; i += dmxInput->devs[i]->binding) + if (dmxInput->devs[i]->update_info) + dmxInput->devs[i]->update_info(dmxInput->devs[i]->private, + type, pWindow); +} + +static void dmxCollectAll(DMXInputInfo *dmxInput) +{ + int i; + + if (dmxInput->detached) + return; + for (i = 0; i < dmxInput->numDevs; i += dmxInput->devs[i]->binding) + if (dmxInput->devs[i]->collect_events) + dmxInput->devs[i]->collect_events(&dmxInput->devs[i] + ->pDevice->public, + dmxMotion, + dmxEnqueue, + dmxCheckSpecialKeys, DMX_BLOCK); +} + +static void dmxBlockHandler(pointer blockData, OSTimePtr pTimeout, + pointer pReadMask) +{ + DMXInputInfo *dmxInput = &dmxInputs[(int)blockData]; + static unsigned long generation = 0; + + if (generation != serverGeneration) { + generation = serverGeneration; + dmxCollectAll(dmxInput); + } +} + +static void dmxSwitchReturn(pointer p) +{ + DMXInputInfo *dmxInput = p; + int i; + + dmxLog(dmxInfo, "Returning from VT %d\n", dmxInput->vt_switched); + + if (!dmxInput->vt_switched) + dmxLog(dmxFatal, "dmxSwitchReturn called, but not switched\n"); + dmxSigioEnableInput(); + for (i = 0; i < dmxInput->numDevs; i++) + if (dmxInput->devs[i]->vt_post_switch) + dmxInput->devs[i]->vt_post_switch(dmxInput->devs[i]->private); + dmxInput->vt_switched = 0; +} + +static void dmxWakeupHandler(pointer blockData, int result, pointer pReadMask) +{ + DMXInputInfo *dmxInput = &dmxInputs[(int)blockData]; + int i; + + if (dmxInput->vt_switch_pending) { + dmxLog(dmxInfo, "Switching to VT %d\n", dmxInput->vt_switch_pending); + for (i = 0; i < dmxInput->numDevs; i++) + if (dmxInput->devs[i]->vt_pre_switch) + dmxInput->devs[i]->vt_pre_switch(dmxInput->devs[i]->private); + dmxInput->vt_switched = dmxInput->vt_switch_pending; + dmxInput->vt_switch_pending = 0; + for (i = 0; i < dmxInput->numDevs; i++) { + if (dmxInput->devs[i]->vt_switch) { + dmxSigioDisableInput(); + if (!dmxInput->devs[i]->vt_switch(dmxInput->devs[i]->private, + dmxInput->vt_switched, + dmxSwitchReturn, + dmxInput)) + dmxSwitchReturn(dmxInput); + break; /* Only call one vt_switch routine */ + } + } + } + dmxCollectAll(dmxInput); +} + +static char *dmxMakeUniqueDeviceName(DMXLocalInputInfoPtr dmxLocal) +{ + static int k = 0; + static int m = 0; + static int o = 0; + static unsigned long dmxGeneration = 0; +#define LEN 32 + char * buf = xalloc(LEN); + + if (dmxGeneration != serverGeneration) { + k = m = o = 0; + dmxGeneration = serverGeneration; + } + + switch (dmxLocal->type) { + case DMX_LOCAL_KEYBOARD: XmuSnprintf(buf, LEN, "Keyboard%d", k++); break; + case DMX_LOCAL_MOUSE: XmuSnprintf(buf, LEN, "Mouse%d", m++); break; + default: XmuSnprintf(buf, LEN, "Other%d", o++); break; + } + + return buf; +} + +static DeviceIntPtr dmxAddDevice(DMXLocalInputInfoPtr dmxLocal) +{ + DeviceIntPtr pDevice; + Atom atom; + const char *name = NULL; + void (*registerProcPtr)(DeviceIntPtr) = NULL; + char *devname; + DMXInputInfo *dmxInput; + + if (!dmxLocal) + return NULL; + dmxInput = &dmxInputs[dmxLocal->inputIdx]; + + if (dmxLocal->sendsCore) { + if (dmxLocal->type == DMX_LOCAL_KEYBOARD && !dmxLocalCoreKeyboard) { + dmxLocal->isCore = 1; + dmxLocalCoreKeyboard = dmxLocal; + name = "keyboard"; + registerProcPtr = RegisterKeyboardDevice; + } + if (dmxLocal->type == DMX_LOCAL_MOUSE && !dmxLocalCorePointer) { + dmxLocal->isCore = 1; + dmxLocalCorePointer = dmxLocal; + name = "pointer"; + registerProcPtr = RegisterPointerDevice; + } + } + +#ifdef XINPUT + if (!name) { + name = "extension"; + registerProcPtr = RegisterOtherDevice; + } +#else + if (!name) + dmxLog(dmxFatal, + "Server not build with XINPUT support (cannot add %s)\n", + dmxLocal->name); +#endif + + if (!name || !registerProcPtr) + dmxLog(dmxFatal, "Cannot add device %s\n", dmxLocal->name); + + pDevice = AddInputDevice(dmxDeviceOnOff, TRUE); + if (!pDevice) { + dmxLog(dmxError, "Too many devices -- cannot add device %s\n", + dmxLocal->name); + return NULL; + } + pDevice->public.devicePrivate = dmxLocal; + dmxLocal->pDevice = pDevice; + + devname = dmxMakeUniqueDeviceName(dmxLocal); + atom = MakeAtom((char *)devname, strlen(devname), TRUE); + pDevice->type = atom; + pDevice->name = devname; + + registerProcPtr(pDevice); + + if (dmxLocal->isCore && dmxLocal->type == DMX_LOCAL_MOUSE) { +#if 00 /*BP*/ + miRegisterPointerDevice(screenInfo.screens[0], pDevice); +#else + /* Nothing? dmxDeviceOnOff() should get called to init, right? */ +#endif + } + + if (dmxLocal->create_private) + dmxLocal->private = dmxLocal->create_private(pDevice); + + dmxLogInput(dmxInput, "Added %s as %s device called %s%s\n", + dmxLocal->name, name, devname, + dmxLocal->isCore + ? " [core]" + : (dmxLocal->sendsCore + ? " [sends core events]" + : "")); + + return pDevice; +} + +static DMXLocalInputInfoPtr dmxLookupLocal(const char *name) +{ + DMXLocalInputInfoPtr pt; + + for (pt = &DMXLocalDevices[0]; pt->name; ++pt) + if (!strcmp(pt->name, name)) return pt; /* search for device name */ + return NULL; +} + +/** Copy the local input information from \a s into a new \a devs slot + * in \a dmxInput. */ +DMXLocalInputInfoPtr dmxInputCopyLocal(DMXInputInfo *dmxInput, + DMXLocalInputInfoPtr s) +{ + DMXLocalInputInfoPtr dmxLocal = xalloc(sizeof(*dmxLocal)); + + if (!dmxLocal) + dmxLog(dmxFatal, "DMXLocalInputInfoPtr: out of memory\n"); + + memcpy(dmxLocal, s, sizeof(*dmxLocal)); + dmxLocal->inputIdx = dmxInput->inputIdx; + dmxLocal->sendsCore = dmxInput->core; + dmxLocal->savedSendsCore = dmxInput->core; + dmxLocal->deviceId = -1; + + ++dmxInput->numDevs; + dmxInput->devs = xrealloc(dmxInput->devs, + dmxInput->numDevs * sizeof(*dmxInput->devs)); + dmxInput->devs[dmxInput->numDevs-1] = dmxLocal; + + return dmxLocal; +} + +static void dmxPopulateLocal(DMXInputInfo *dmxInput, dmxArg a) +{ + int i; + int help = 0; + DMXLocalInputInfoRec *pt; + + for (i = 1; i < dmxArgC(a); i++) { + const char *name = dmxArgV(a, i); + if ((pt = dmxLookupLocal(name))) { + dmxInputCopyLocal(dmxInput, pt); + } else { + if (strlen(name)) + dmxLog(dmxWarning, + "Could not find a driver called %s\n", name); + ++help; + } + } + if (help) { + dmxLog(dmxInfo, "Available local device drivers:\n"); + for (pt = &DMXLocalDevices[0]; pt->name; ++pt) { + const char *type; + switch (pt->type) { + case DMX_LOCAL_KEYBOARD: type = "keyboard"; break; + case DMX_LOCAL_MOUSE: type = "pointer"; break; + default: type = "unknown"; break; + } + dmxLog(dmxInfo, " %s (%s)\n", pt->name, type); + } + dmxLog(dmxFatal, "Must have valid local device driver\n"); + } +} + +int dmxInputExtensionErrorHandler(Display *dsp, char *name, char *reason) +{ + return 0; +} + +static void dmxInputScanForExtensions(DMXInputInfo *dmxInput, int doXI) +{ + XExtensionVersion *ext; + XDeviceInfo *devices; + Display *display; + int num; + int i, j; + DMXLocalInputInfoPtr dmxLocal; + int (*handler)(Display *, char *, char *); + + if (!(display = XOpenDisplay(dmxInput->name))) return; + + /* Print out information about the XInput Extension. */ + handler = XSetExtensionErrorHandler(dmxInputExtensionErrorHandler); + ext = XGetExtensionVersion(display, INAME); + XSetExtensionErrorHandler(handler); + + if (!ext || ext == (XExtensionVersion *)NoSuchExtension) { + dmxLogInput(dmxInput, "%s is not available\n", INAME); + } else { + dmxLogInput(dmxInput, "Locating devices on %s (%s version %d.%d)\n", + dmxInput->name, INAME, + ext->major_version, ext->minor_version); + devices = XListInputDevices(display, &num); + + XFree(ext); + ext = NULL; + + /* Print a list of all devices */ + for (i = 0; i < num; i++) { + const char *use = "Unknown"; + switch (devices[i].use) { + case IsXPointer: use = "XPointer"; break; + case IsXKeyboard: use = "XKeyboard"; break; + case IsXExtensionDevice: use = "XExtensionDevice"; break; + } + dmxLogInput(dmxInput, " %2d %-10.10s %-16.16s\n", + devices[i].id, + devices[i].name ? devices[i].name : "", + use); + } + + /* Search for extensions */ + for (i = 0; i < num; i++) { + switch (devices[i].use) { + case IsXKeyboard: + for (j = 0; j < dmxInput->numDevs; j++) { + DMXLocalInputInfoPtr dmxL = dmxInput->devs[j]; + if (dmxL->type == DMX_LOCAL_KEYBOARD + && dmxL->deviceId < 0) { + dmxL->deviceId = devices[i].id; + dmxL->deviceName = (devices[i].name + ? xstrdup(devices[i].name) + : NULL); + } + } + break; + case IsXPointer: + for (j = 0; j < dmxInput->numDevs; j++) { + DMXLocalInputInfoPtr dmxL = dmxInput->devs[j]; + if (dmxL->type == DMX_LOCAL_MOUSE && dmxL->deviceId < 0) { + dmxL->deviceId = devices[i].id; + dmxL->deviceName = (devices[i].name + ? xstrdup(devices[i].name) + : NULL); + } + } + break; + case IsXExtensionDevice: + if (doXI) { + if (!dmxInput->numDevs) { + dmxLog(dmxWarning, + "Cannot use remote (%s) XInput devices if" + " not also using core devices\n", + dmxInput->name); + } else { + dmxLocal = dmxInputCopyLocal(dmxInput, + &DMXCommonOth); + dmxLocal->isCore = FALSE; + dmxLocal->sendsCore = FALSE; + dmxLocal->deviceId = devices[i].id; + dmxLocal->deviceName = (devices[i].name + ? xstrdup(devices[i].name) + : NULL); + } + } + break; + } + } + XFreeDeviceList(devices); + } + XCloseDisplay(display); +} + +/** Re-initialize all the devices described in \a dmxInput. Called from + #dmxReconfig before the cursor is redisplayed. */ +void dmxInputReInit(DMXInputInfo *dmxInput) +{ + int i; + + for (i = 0; i < dmxInput->numDevs; i++) { + DMXLocalInputInfoPtr dmxLocal = dmxInput->devs[i]; + if (dmxLocal->reinit) + dmxLocal->reinit(&dmxLocal->pDevice->public); + } +} + +/** Re-initialize all the devices described in \a dmxInput. Called from + #dmxReconfig after the cursor is redisplayed. */ +void dmxInputLateReInit(DMXInputInfo *dmxInput) +{ + int i; + + for (i = 0; i < dmxInput->numDevs; i++) { + DMXLocalInputInfoPtr dmxLocal = dmxInput->devs[i]; + if (dmxLocal->latereinit) + dmxLocal->latereinit(&dmxLocal->pDevice->public); + } +} + +/** Initialize all of the devices described in \a dmxInput. */ +void dmxInputInit(DMXInputInfo *dmxInput) +{ + DeviceIntPtr pPointer = NULL, pKeyboard = NULL; + dmxArg a; + const char *name; + int i; + int doXI = 1; /* Include by default */ + int forceConsole = 0; + int doWindows = 1; /* On by default */ + int hasXkb = 0; + + a = dmxArgParse(dmxInput->name); + + for (i = 1; i < dmxArgC(a); i++) { + switch (hasXkb) { + case 1: + dmxInput->keycodes = xstrdup(dmxArgV(a, i)); + ++hasXkb; + break; + case 2: + dmxInput->symbols = xstrdup(dmxArgV(a, i)); + ++hasXkb; + break; + case 3: + dmxInput->geometry = xstrdup(dmxArgV(a, i)); + hasXkb = 0; + break; + case 0: + if (!strcmp(dmxArgV(a, i), "noxi")) doXI = 0; + else if (!strcmp(dmxArgV(a, i), "xi")) doXI = 1; + else if (!strcmp(dmxArgV(a, i), "console")) forceConsole = 1; + else if (!strcmp(dmxArgV(a, i), "noconsole")) forceConsole = 0; + else if (!strcmp(dmxArgV(a, i), "windows")) doWindows = 1; + else if (!strcmp(dmxArgV(a, i), "nowindows")) doWindows = 0; + else if (!strcmp(dmxArgV(a, i), "xkb")) hasXkb = 1; + else { + dmxLog(dmxFatal, + "Unknown input argument: %s\n", dmxArgV(a, i)); + } + } + } + + name = dmxArgV(a, 0); + + if (!strcmp(name, "local")) { + dmxPopulateLocal(dmxInput, a); + } else if (!strcmp(name, "dummy")) { + dmxInputCopyLocal(dmxInput, &DMXDummyMou); + dmxInputCopyLocal(dmxInput, &DMXDummyKbd); + dmxLogInput(dmxInput, "Using dummy input\n"); + } else { + int found; + + for (found = 0, i = 0; i < dmxNumScreens; i++) { + if (dmxPropertySameDisplay(&dmxScreens[i], name)) { + if (dmxScreens[i].shared) + dmxLog(dmxFatal, + "Cannot take input from shared backend (%s)\n", + name); + if (!dmxInput->core) { + dmxLog(dmxWarning, + "Cannot use core devices on a backend (%s)" + " as XInput devices\n", name); + } else { + char *pt; + for (pt = (char *)dmxInput->name; pt && *pt; pt++) + if (*pt == ',') *pt = '\0'; + dmxInputCopyLocal(dmxInput, &DMXBackendMou); + dmxInputCopyLocal(dmxInput, &DMXBackendKbd); + dmxInput->scrnIdx = i; + dmxLogInput(dmxInput, + "Using backend input from %s\n", name); + } + ++found; + break; + } + } + if (!found || forceConsole) { + char *pt; + if (found) dmxInput->console = TRUE; + for (pt = (char *)dmxInput->name; pt && *pt; pt++) + if (*pt == ',') *pt = '\0'; + dmxInputCopyLocal(dmxInput, &DMXConsoleMou); + dmxInputCopyLocal(dmxInput, &DMXConsoleKbd); + if (doWindows) { + dmxInput->windows = TRUE; + dmxInput->updateWindowInfo = dmxUpdateWindowInformation; + } + dmxLogInput(dmxInput, + "Using console input from %s (%s windows)\n", + name, doWindows ? "with" : "without"); + } + } + + dmxArgFree(a); + + /* Locate extensions we may be interested in */ + dmxInputScanForExtensions(dmxInput, doXI); + + for (i = 0; i < dmxInput->numDevs; i++) { + DMXLocalInputInfoPtr dmxLocal = dmxInput->devs[i]; +#ifndef XINPUT + if (!dmxLocal->isCore) + dmxLog(dmxFatal, + "This server was not compiled to support the XInput" + " extension, but %s is not a core device.\n", + dmxLocal->name); +#endif + dmxLocal->pDevice = dmxAddDevice(dmxLocal); + if (dmxLocal->isCore) { + if (dmxLocal->type == DMX_LOCAL_MOUSE) + pPointer = dmxLocal->pDevice; + if (dmxLocal->type == DMX_LOCAL_KEYBOARD) + pKeyboard = dmxLocal->pDevice; + } + } + + if (pPointer && pKeyboard) { + if (dmxeqInit(&pKeyboard->public, &pPointer->public)) + dmxLogInput(dmxInput, "Using %s and %s as true core devices\n", + pKeyboard->name, pPointer->name); + } + + dmxInput->processInputEvents = dmxProcessInputEvents; + dmxInput->detached = False; + + RegisterBlockAndWakeupHandlers(dmxBlockHandler, + dmxWakeupHandler, + (void *)dmxInput->inputIdx); +} + +static void dmxInputFreeLocal(DMXLocalInputInfoRec *local) +{ + if (!local) return; + if (local->isCore && local->type == DMX_LOCAL_MOUSE) + dmxLocalCorePointer = NULL; + if (local->isCore && local->type == DMX_LOCAL_KEYBOARD) + dmxLocalCoreKeyboard = NULL; + if (local->destroy_private) local->destroy_private(local->private); + if (local->history) xfree(local->history); + if (local->valuators) xfree(local->valuators); + if (local->deviceName) xfree(local->deviceName); + local->private = NULL; + local->history = NULL; + local->deviceName = NULL; + xfree(local); +} + +/** Free all of the memory associated with \a dmxInput */ +void dmxInputFree(DMXInputInfo *dmxInput) +{ + int i; + + if (!dmxInput) return; + + if (dmxInput->keycodes) xfree(dmxInput->keycodes); + if (dmxInput->symbols) xfree(dmxInput->symbols); + if (dmxInput->geometry) xfree(dmxInput->geometry); + + for (i = 0; i < dmxInput->numDevs; i++) { + dmxInputFreeLocal(dmxInput->devs[i]); + dmxInput->devs[i] = NULL; + } + xfree(dmxInput->devs); + dmxInput->devs = NULL; + dmxInput->numDevs = 0; + if (dmxInput->freename) xfree(dmxInput->name); + dmxInput->name = NULL; +} + +/** Log information about all of the known devices using #dmxLog(). */ +void dmxInputLogDevices(void) +{ + int i, j; + + dmxLog(dmxInfo, "%d devices:\n", dmxGetInputCount()); + dmxLog(dmxInfo, " Id Name Classes\n"); + for (j = 0; j < dmxNumInputs; j++) { + DMXInputInfo *dmxInput = &dmxInputs[j]; + const char *pt = strchr(dmxInput->name, ','); + int len = (pt + ? (size_t)(pt-dmxInput->name) + : strlen(dmxInput->name)); + + for (i = 0; i < dmxInput->numDevs; i++) { + DeviceIntPtr pDevice = dmxInput->devs[i]->pDevice; + if (pDevice) { + dmxLog(dmxInfo, " %2d%c %-20.20s", + pDevice->id, + dmxInput->detached ? 'D' : ' ', + pDevice->name); + if (pDevice->key) dmxLogCont(dmxInfo, " key"); + if (pDevice->valuator) dmxLogCont(dmxInfo, " val"); + if (pDevice->button) dmxLogCont(dmxInfo, " btn"); + if (pDevice->focus) dmxLogCont(dmxInfo, " foc"); + if (pDevice->kbdfeed) dmxLogCont(dmxInfo, " fb/kbd"); + if (pDevice->ptrfeed) dmxLogCont(dmxInfo, " fb/ptr"); + if (pDevice->intfeed) dmxLogCont(dmxInfo, " fb/int"); + if (pDevice->stringfeed) dmxLogCont(dmxInfo, " fb/str"); + if (pDevice->bell) dmxLogCont(dmxInfo, " fb/bel"); + if (pDevice->leds) dmxLogCont(dmxInfo, " fb/led"); + if (!pDevice->key && !pDevice->valuator && !pDevice->button + && !pDevice->focus && !pDevice->kbdfeed + && !pDevice->ptrfeed && !pDevice->intfeed + && !pDevice->stringfeed && !pDevice->bell + && !pDevice->leds) dmxLogCont(dmxInfo, " (none)"); + + dmxLogCont(dmxInfo, "\t[i%d/%*.*s", + dmxInput->inputIdx, len, len, dmxInput->name); + if (dmxInput->devs[i]->deviceId >= 0) + dmxLogCont(dmxInfo, "/id%d", dmxInput->devs[i]->deviceId); + if (dmxInput->devs[i]->deviceName) + dmxLogCont(dmxInfo, "=%s", dmxInput->devs[i]->deviceName); + dmxLogCont(dmxInfo, "] %s\n", + dmxInput->devs[i]->isCore + ? "core" + : (dmxInput->devs[i]->sendsCore + ? "extension (sends core events)" + : "extension")); + } + } + } +} + +/** Detach an input */ +int dmxInputDetach(DMXInputInfo *dmxInput) +{ + int i; + + if (dmxInput->detached) return BadAccess; + + for (i = 0; i < dmxInput->numDevs; i++) { + DMXLocalInputInfoPtr dmxLocal = dmxInput->devs[i]; + dmxLogInput(dmxInput, "Detaching device id %d: %s%s\n", + dmxLocal->pDevice->id, + dmxLocal->pDevice->name, + dmxLocal->isCore + ? " [core]" + : (dmxLocal->sendsCore + ? " [sends core events]" + : "")); + DisableDevice(dmxLocal->pDevice); + } + dmxInput->detached = True; + dmxInputLogDevices(); + return 0; +} + +/** Search for input associated with \a dmxScreen, and detach. */ +void dmxInputDetachAll(DMXScreenInfo *dmxScreen) +{ + int i; + + for (i = 0; i < dmxNumInputs; i++) { + DMXInputInfo *dmxInput = &dmxInputs[i]; + if (dmxInput->scrnIdx == dmxScreen->index) dmxInputDetach(dmxInput); + } +} + +/** Search for input associated with \a deviceId, and detach. */ +int dmxInputDetachId(int id) +{ + DMXInputInfo *dmxInput = dmxInputLocateId(id); + + if (!dmxInput) return BadValue; + + return dmxInputDetach(dmxInput); +} + +DMXInputInfo *dmxInputLocateId(int id) +{ + int i, j; + + for (i = 0; i < dmxNumInputs; i++) { + DMXInputInfo *dmxInput = &dmxInputs[i]; + for (j = 0; j < dmxInput->numDevs; j++) { + DMXLocalInputInfoPtr dmxLocal = dmxInput->devs[j]; + if (dmxLocal->pDevice->id == id) return dmxInput; + } + } + return NULL; +} + +static int dmxInputAttachNew(DMXInputInfo *dmxInput, int *id) +{ + dmxInputInit(dmxInput); + InitAndStartDevices(); + if (id && dmxInput->devs) *id = dmxInput->devs[0]->pDevice->id; + dmxInputLogDevices(); + return 0; +} + +static int dmxInputAttachOld(DMXInputInfo *dmxInput, int *id) +{ + int i; + + dmxInput->detached = False; + for (i = 0; i < dmxInput->numDevs; i++) { + DMXLocalInputInfoPtr dmxLocal = dmxInput->devs[i]; + if (id) *id = dmxLocal->pDevice->id; + dmxLogInput(dmxInput, + "Attaching device id %d: %s%s\n", + dmxLocal->pDevice->id, + dmxLocal->pDevice->name, + dmxLocal->isCore + ? " [core]" + : (dmxLocal->sendsCore + ? " [sends core events]" + : "")); + EnableDevice(dmxLocal->pDevice); + } + dmxInputLogDevices(); + return 0; +} + +int dmxInputAttachConsole(const char *name, int isCore, int *id) +{ + DMXInputInfo *dmxInput; + int i; + + for (i = 0; i < dmxNumInputs; i++) { + dmxInput = &dmxInputs[i]; + if (dmxInput->scrnIdx == -1 + && dmxInput->detached + && !strcmp(dmxInput->name, name)) { + /* Found match */ + dmxLogInput(dmxInput, "Reattaching detached console input\n"); + return dmxInputAttachOld(dmxInput, id); + } + } + + /* No match found */ + dmxInput = dmxConfigAddInput(xstrdup(name), isCore); + dmxInput->freename = TRUE; + dmxLogInput(dmxInput, "Attaching new console input\n"); + return dmxInputAttachNew(dmxInput, id); +} + +int dmxInputAttachBackend(int physicalScreen, int isCore, int *id) +{ + DMXInputInfo *dmxInput; + DMXScreenInfo *dmxScreen; + int i; + + if (physicalScreen < 0 || physicalScreen >= dmxNumScreens) return BadValue; + for (i = 0; i < dmxNumInputs; i++) { + dmxInput = &dmxInputs[i]; + if (dmxInput->scrnIdx != -1 && dmxInput->scrnIdx == physicalScreen) { + /* Found match */ + if (!dmxInput->detached) return BadAccess; /* Already attached */ + dmxScreen = &dmxScreens[physicalScreen]; + if (!dmxScreen->beDisplay) return BadAccess; /* Screen detached */ + dmxLogInput(dmxInput, "Reattaching detached backend input\n"); + return dmxInputAttachOld(dmxInput, id); + } + } + /* No match found */ + dmxScreen = &dmxScreens[physicalScreen]; + if (!dmxScreen->beDisplay) return BadAccess; /* Screen detached */ + dmxInput = dmxConfigAddInput(dmxScreen->name, isCore); + dmxLogInput(dmxInput, "Attaching new backend input\n"); + return dmxInputAttachNew(dmxInput, id); +} diff --git a/xorg-server/hw/dmx/input/dmxinputinit.h b/xorg-server/hw/dmx/input/dmxinputinit.h new file mode 100644 index 000000000..6f491edf9 --- /dev/null +++ b/xorg-server/hw/dmx/input/dmxinputinit.h @@ -0,0 +1,293 @@ +/* + * Copyright 2002 Red Hat Inc., Durham, North Carolina. + * + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation on the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NON-INFRINGEMENT. IN NO EVENT SHALL RED HAT AND/OR THEIR SUPPLIERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* + * Authors: + * Rickard E. (Rik) Faith <faith@redhat.com> + * + */ + +/** \file + * Interface for low-level input support. \see dmxinputinit.c */ + +#ifndef _DMXINPUTINIT_H_ +#define _DMXINPUTINIT_H_ + +#include "dmx.h" +#include "dmxinput.h" +#include "dmxlog.h" + + +#define DMX_LOCAL_DEFAULT_KEYBOARD "kbd" +#define DMX_LOCAL_DEFAULT_POINTER "ps2" +#define DMX_MAX_BUTTONS 256 +#define DMX_MOTION_SIZE 256 +#define DMX_MAX_VALUATORS 32 +#define DMX_MAX_AXES 32 +#define DMX_MAX_XINPUT_EVENT_TYPES 100 +#define DMX_MAP_ENTRIES 16 /* Must be a power of 2 */ +#define DMX_MAP_MASK (DMX_MAP_ENTRIES - 1) + +typedef enum { + DMX_FUNCTION_GRAB, + DMX_FUNCTION_TERMINATE, + DMX_FUNCTION_FINE +} DMXFunctionType; + +typedef enum { + DMX_LOCAL_HIGHLEVEL, + DMX_LOCAL_KEYBOARD, + DMX_LOCAL_MOUSE, + DMX_LOCAL_OTHER +} DMXLocalInputType; + +typedef enum { + DMX_LOCAL_TYPE_LOCAL, + DMX_LOCAL_TYPE_CONSOLE, + DMX_LOCAL_TYPE_BACKEND, + DMX_LOCAL_TYPE_COMMON +} DMXLocalInputExtType; + +typedef enum { + DMX_RELATIVE, + DMX_ABSOLUTE, + DMX_ABSOLUTE_CONFINED +} DMXMotionType; + +/** Stores information from low-level device that is used to initialize + * the device at the dix level. */ +typedef struct _DMXLocalInitInfo { + int keyboard; /**< Non-zero if the device is a keyboard */ + + int keyClass; /**< Non-zero if keys are present */ + KeySymsRec keySyms; /**< Key symbols */ + int freemap; /**< If non-zero, free keySyms.map */ + CARD8 modMap[MAP_LENGTH]; /**< Modifier map */ +#ifdef XKB + XkbDescPtr xkb; /**< XKB description */ + XkbComponentNamesRec names; /**< XKB component names */ + int freenames; /**< Non-zero if names should be free'd */ + int force; /**< Do not allow command line override */ +#endif + + int buttonClass; /**< Non-zero if buttons are present */ + int numButtons; /**< Number of buttons */ + unsigned char map[DMX_MAX_BUTTONS]; /**< Button map */ + + int valuatorClass; /**< Non-zero if valuators are + * present */ + int numRelAxes; /**< Number of relative axes */ + int numAbsAxes; /**< Number of absolute axes */ + int minval[DMX_MAX_AXES]; /**< Minimum values */ + int maxval[DMX_MAX_AXES]; /**< Maximum values */ + int res[DMX_MAX_AXES]; /**< Resolution */ + int minres[DMX_MAX_AXES]; /**< Minimum resolutions */ + int maxres[DMX_MAX_AXES]; /**< Maximum resolutions */ + + int focusClass; /**< Non-zero if device can + * cause focus */ + int proximityClass; /**< Non-zero if device + * causes proximity events */ + int kbdFeedbackClass; /**< Non-zero if device has + * keyboard feedback */ + int ptrFeedbackClass; /**< Non-zero if device has + * pointer feedback */ + int ledFeedbackClass; /**< Non-zero if device has + * LED indicators */ + int belFeedbackClass; /**< Non-zero if device has a + * bell */ + int intFeedbackClass; /**< Non-zero if device has + * integer feedback */ + int strFeedbackClass; /**< Non-zero if device has + * string feedback */ + + int maxSymbols; /**< Maximum symbols */ + int maxSymbolsSupported; /**< Maximum symbols supported */ + KeySym *symbols; /**< Key symbols */ +} DMXLocalInitInfo, *DMXLocalInitInfoPtr; + +typedef pointer (*dmxCreatePrivateProcPtr)(DeviceIntPtr); +typedef void (*dmxDestroyPrivateProcPtr)(pointer); + +typedef void (*dmxInitProcPtr)(DevicePtr); +typedef void (*dmxReInitProcPtr)(DevicePtr); +typedef void (*dmxLateReInitProcPtr)(DevicePtr); +typedef void (*dmxGetInfoProcPtr)(DevicePtr, DMXLocalInitInfoPtr); +typedef int (*dmxOnProcPtr)(DevicePtr); +typedef void (*dmxOffProcPtr)(DevicePtr); +typedef void (*dmxUpdatePositionProcPtr)(pointer, int x, int y); + +typedef void (*dmxVTPreSwitchProcPtr)(pointer); /* Turn I/O Off */ +typedef void (*dmxVTPostSwitchProcPtr)(pointer); /* Turn I/O On */ +typedef void (*dmxVTSwitchReturnProcPtr)(pointer); +typedef int (*dmxVTSwitchProcPtr)(pointer, int vt, + dmxVTSwitchReturnProcPtr, pointer); + +typedef void (*dmxMotionProcPtr)(DevicePtr, + int *valuators, + int firstAxis, + int axesCount, + DMXMotionType type, + DMXBlockType block); +typedef void (*dmxEnqueueProcPtr)(DevicePtr, int type, int detail, + KeySym keySym, XEvent *e, + DMXBlockType block); +typedef int (*dmxCheckSpecialProcPtr)(DevicePtr, KeySym keySym); +typedef void (*dmxCollectEventsProcPtr)(DevicePtr, + dmxMotionProcPtr, + dmxEnqueueProcPtr, + dmxCheckSpecialProcPtr, + DMXBlockType); +typedef void (*dmxProcessInputProcPtr)(pointer); +typedef void (*dmxUpdateInfoProcPtr)(pointer, DMXUpdateType, WindowPtr); +typedef int (*dmxFunctionsProcPtr)(pointer, DMXFunctionType); + +typedef void (*dmxKBCtrlProcPtr)(DevicePtr, KeybdCtrl *ctrl); +typedef void (*dmxMCtrlProcPtr)(DevicePtr, PtrCtrl *ctrl); +typedef void (*dmxKBBellProcPtr)(DevicePtr, int percent, + int volume, int pitch, int duration); + +/** Stores a mapping between the device id on the remote X server and + * the id on the DMX server */ +typedef struct _DMXEventMap { + int remote; /**< Event number on remote X server */ + int server; /**< Event number (unbiased) on DMX server */ +} DMXEventMap; + +/** This is the device-independent structure used by the low-level input + * routines. The contents are not exposed to top-level .c files (except + * dmxextensions.c). \see dmxinput.h \see dmxextensions.c */ +typedef struct _DMXLocalInputInfo { + const char *name; /**< Device name */ + DMXLocalInputType type; /**< Device type */ + DMXLocalInputExtType extType; /**< Extended device type */ + int binding; /**< Count of how many consecutive + * structs are bound to the same + * device */ + + /* Low-level (e.g., keyboard/mouse drivers) */ + + dmxCreatePrivateProcPtr create_private; /**< Create + * device-dependent + * private */ + dmxDestroyPrivateProcPtr destroy_private; /**< Destroy + * device-dependent + * private */ + dmxInitProcPtr init; /**< Initialize device */ + dmxReInitProcPtr reinit; /**< Reinitialize device + * (during a + * reconfiguration) */ + dmxLateReInitProcPtr latereinit; /**< Reinitialize a device + * (called very late + * during a + * reconfiguration) */ + dmxGetInfoProcPtr get_info; /**< Get device information */ + dmxOnProcPtr on; /**< Turn device on */ + dmxOffProcPtr off; /**< Turn device off */ + dmxUpdatePositionProcPtr update_position; /**< Called when another + * device updates the + * cursor position */ + dmxVTPreSwitchProcPtr vt_pre_switch; /**< Called before a VT switch */ + dmxVTPostSwitchProcPtr vt_post_switch; /**< Called after a VT switch */ + dmxVTSwitchProcPtr vt_switch; /**< Causes a VT switch */ + + dmxCollectEventsProcPtr collect_events; /**< Collect and enqueue + * events from the + * device*/ + dmxProcessInputProcPtr process_input; /**< Process event (from + * queue) */ + dmxFunctionsProcPtr functions; + dmxUpdateInfoProcPtr update_info; /**< Update window layout + * information */ + + dmxMCtrlProcPtr mCtrl; /**< Pointer control */ + dmxKBCtrlProcPtr kCtrl; /**< Keyboard control */ + dmxKBBellProcPtr kBell; /**< Bell control */ + + pointer private; /**< Device-dependent private */ + int isCore; /**< Is a DMX core device */ + int sendsCore; /**< Sends DMX core events */ + KeybdCtrl kctrl; /**< Keyboard control */ + PtrCtrl mctrl; /**< Pointer control */ + + DeviceIntPtr pDevice; /**< X-level device */ + int inputIdx; /**< High-level index */ + int lastX, lastY; /**< Last known position; + * for XInput in + * dmxevents.c */ + + int head; /**< XInput motion history + * head */ + int tail; /**< XInput motion history + * tail */ + unsigned long *history; /**< XInput motion history */ + int *valuators; /**< Cache of previous values */ + + /* for XInput ChangePointerDevice */ + int (*savedMotionProc)(DeviceIntPtr, + xTimecoord *, + unsigned long, + unsigned long, + ScreenPtr); + int savedMotionEvents; /**< Saved motion events */ + int savedSendsCore; /**< Saved sends-core flag */ + + DMXEventMap map[DMX_MAP_ENTRIES]; /**< XInput device id map */ + int mapOptimize; /**< XInput device id + * map + * optimization */ + + long deviceId; /**< device id on remote side, + * if any */ + const char *deviceName; /**< devive name on remote + * side, if any */ +} DMXLocalInputInfoRec; + +extern DMXLocalInputInfoPtr dmxLocalCorePointer, dmxLocalCoreKeyboard; + +extern void dmxLocalInitInput(DMXInputInfo *dmxInput); +extern DMXLocalInputInfoPtr dmxInputCopyLocal(DMXInputInfo *dmxInput, + DMXLocalInputInfoPtr s); + +extern void dmxChangePointerControl(DeviceIntPtr pDevice, PtrCtrl *ctrl); +extern void dmxKeyboardKbdCtrlProc(DeviceIntPtr pDevice, KeybdCtrl *ctrl); +extern void dmxKeyboardBellProc(int percent, DeviceIntPtr pDevice, + pointer ctrl, int unknown); + +extern int dmxInputExtensionErrorHandler(Display *dsp, char *name, + char *reason); + +extern int dmxInputDetach(DMXInputInfo *dmxInput); +extern void dmxInputDetachAll(DMXScreenInfo *dmxScreen); +extern int dmxInputDetachId(int id); +extern DMXInputInfo *dmxInputLocateId(int id); +extern int dmxInputAttachConsole(const char *name, int isCore, + int *id); +extern int dmxInputAttachBackend(int physicalScreen, int isCore, + int *id); + +#endif diff --git a/xorg-server/hw/dmx/input/dmxmap.c b/xorg-server/hw/dmx/input/dmxmap.c new file mode 100644 index 000000000..1eccd3d28 --- /dev/null +++ b/xorg-server/hw/dmx/input/dmxmap.c @@ -0,0 +1,121 @@ +/* + * Copyright 2003 Red Hat Inc., Durham, North Carolina. + * + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation on the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NON-INFRINGEMENT. IN NO EVENT SHALL RED HAT AND/OR THEIR SUPPLIERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* + * Authors: + * Rickard E. (Rik) Faith <faith@redhat.com> + */ + +/** \file + * + * This file implements a mapping from remote XInput event types to Xdmx + * XInput event types. + * + * The exglobals.h file defines global server-side variables with names + * Device* to be integers that hold the value of the type of the + * server-side XInput extension event. + * + * The client-side X11/extensions/XInput.h file defines macros with THE + * EXACT SAME Device* names! + * + * Using those macros to extract remote server event type values from + * the (opaque) XDevice structure is appropriate, but makes a direct + * mapping to the Device* integers impossible. So we use the normalized + * XI_Device* names for these routines. + */ + +#ifdef HAVE_DMX_CONFIG_H +#include <dmx-config.h> +#endif + +#include "dmxinputinit.h" +#include "dmxmap.h" + +/** Create a mapping from \a remoteEvent to \a serverEvent. The \a + * remoteEvent is the type returned from the remote server. The \a + * serverEvent is from the XI_* list of events in + * include/extensions/XIproto.h. */ +void dmxMapInsert(DMXLocalInputInfoPtr dmxLocal, + int remoteEvent, int serverEvent) +{ + int hash = remoteEvent & DMX_MAP_MASK; + int i; + + /* Return if this has already been mapped */ + if (dmxLocal->map[hash].remote == remoteEvent + && dmxLocal->map[hash].server == serverEvent) return; + + if (dmxLocal->map[hash].remote) { + dmxLocal->mapOptimize = 0; + for (i = 0; i < DMX_MAP_ENTRIES; i++) { + if (!dmxLocal->map[i].remote) { + dmxLocal->map[i].remote = remoteEvent; + dmxLocal->map[i].server = serverEvent; + return; + } + } + dmxLog(dmxWarning, + "Out of map entries, cannot map remove event type %d\n", + remoteEvent); + } else { + dmxLocal->map[hash].remote = remoteEvent; + dmxLocal->map[hash].server = serverEvent; + } +} + +/** Remove all mappings there were inserted with #dmxMapInsert. */ +void dmxMapClear(DMXLocalInputInfoPtr dmxLocal) +{ + int i; + + for (i = 0; i < DMX_MAP_ENTRIES; i++) dmxLocal->map[i].remote = 0; + dmxLocal->mapOptimize = 1; +} + +/** Lookup a mapping for \a remoteEvent. The \a remoteEvent is the type + * returned from the remote server. The return value is that which was + * passed into #dmxMapInsert (i.e., a value from the XI_* list in + * include/extensions/XIproto.h). If a mapping is not available, -1 is + * returned. */ +int dmxMapLookup(DMXLocalInputInfoPtr dmxLocal, int remoteEvent) +{ + int hash = remoteEvent & DMX_MAP_MASK; + int serverEvent = -1; + int i; + + if (dmxLocal->mapOptimize && dmxLocal->map[hash].remote == remoteEvent) { + serverEvent = dmxLocal->map[hash].server; + } else { + for (i = 0; i < DMX_MAP_ENTRIES; i++) + if (dmxLocal->map[i].remote == remoteEvent) { + serverEvent = dmxLocal->map[hash].server; + break; + } + } + + return serverEvent; +} diff --git a/xorg-server/hw/dmx/input/dmxmap.h b/xorg-server/hw/dmx/input/dmxmap.h new file mode 100644 index 000000000..aad30d1bd --- /dev/null +++ b/xorg-server/hw/dmx/input/dmxmap.h @@ -0,0 +1,42 @@ +/* + * Copyright 2003 Red Hat Inc., Durham, North Carolina. + * + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation on the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NON-INFRINGEMENT. IN NO EVENT SHALL RED HAT AND/OR THEIR SUPPLIERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* + * Authors: + * Rickard E. (Rik) Faith <faith@redhat.com> + */ + +/** \file + * Interface to XInput event mapping support. \see dmxmap.c */ + +#ifndef _DMXMAP_H_ +#define _DMXMAP_H_ +extern void dmxMapInsert(DMXLocalInputInfoPtr dmxLocal, + int remoteEvent, int serverEvent); +extern void dmxMapClear(DMXLocalInputInfoPtr dmxLocal); +extern int dmxMapLookup(DMXLocalInputInfoPtr dmxLocal, int remoteEvent); +#endif diff --git a/xorg-server/hw/dmx/input/dmxmotion.c b/xorg-server/hw/dmx/input/dmxmotion.c new file mode 100644 index 000000000..cc55eedff --- /dev/null +++ b/xorg-server/hw/dmx/input/dmxmotion.c @@ -0,0 +1,143 @@ +/* + * Copyright 2002-2003 Red Hat Inc., Durham, North Carolina. + * + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation on the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NON-INFRINGEMENT. IN NO EVENT SHALL RED HAT AND/OR THEIR SUPPLIERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* + * Authors: + * Rickard E. (Rik) Faith <faith@redhat.com> + * + */ + +/** \file + * This file provides functions similar to miPointerGetMotionEvents and + * miPointerPutMotionEvents, with the exception that devices with more + * than two axes are fully supported. These routines may be used only + * for motion buffers for extension devices, and are \a not compatible + * replacements for the mi routines. */ + +#ifdef HAVE_DMX_CONFIG_H +#include <dmx-config.h> +#endif + +#include "inputstr.h" +#include "dmxinputinit.h" +#include "dmxcommon.h" +#include "dmxmotion.h" + +#define OFFSET(offset,element) ((offset) * (numAxes + 1) + (element)) + +/** Return size of motion buffer. \see DMX_MOTION_SIZE */ +int dmxPointerGetMotionBufferSize(void) +{ + return DMX_MOTION_SIZE; +} + +/** This routine performs the same function as \a miPointerGetMotionEvents: + * the events in the motion history that are between the start and stop + * times (in mS) are placed in the coords vector, and the count of the + * number of items so placed is returned. This routine is called from + * dix/devices.c so that coords can hold valuator->numMotionEvents + * events. This routine is called from \a Xi/gtmotion.c with coords large + * enough to hold the same number of events in a variable-length + * extended \a xTimecoord structure. This provides sufficient data for the + * \a XGetDeviceMotionEvents library call, and would be identical to + * \a miPointerGetMotionEvents for devices with only 2 axes (i.e., core + * pointers) if \a xTimecoord used 32bit integers. + * + * Because DMX uses the mi* routines for all core devices, this routine + * only has to support extension devices using the polymorphic coords. + * Because compatibility with miPointerGetMotionEvents is not possible, + * it is not provided. */ +int dmxPointerGetMotionEvents(DeviceIntPtr pDevice, + xTimecoord *coords, + unsigned long start, + unsigned long stop, + ScreenPtr pScreen) +{ + GETDMXLOCALFROMPDEVICE; + int numAxes = pDevice->valuator->numAxes; + unsigned long *c = (unsigned long *)coords; + int count = 0; + int i, j; + + if (!dmxLocal->history) return 0; + for (i = dmxLocal->head; i != dmxLocal->tail;) { + if (dmxLocal->history[OFFSET(i,0)] >= stop) break; + if (dmxLocal->history[OFFSET(i,0)] >= start) { + for (j = 0; j < numAxes + 1; j++) + c[OFFSET(count,j)] = dmxLocal->history[OFFSET(i,j)]; + ++count; + } + if (++i >= DMX_MOTION_SIZE) i = 0; + } + return count; +} + +/** This routine adds an event to the motion history. A similar + * function is performed by miPointerMove for the mi versions of these + * routines. */ +void dmxPointerPutMotionEvent(DeviceIntPtr pDevice, + int firstAxis, int axesCount, int *v, + unsigned long time) +{ + GETDMXLOCALFROMPDEVICE; + int numAxes = pDevice->valuator->numAxes; + int i; + + if (!dmxLocal->history) { + dmxLocal->history = xalloc(sizeof(*dmxLocal->history) + * (numAxes + 1) + * DMX_MOTION_SIZE); + dmxLocal->head = 0; + dmxLocal->tail = 0; + dmxLocal->valuators = xalloc(sizeof(*dmxLocal->valuators) * numAxes); + memset(dmxLocal->valuators, 0, sizeof(*dmxLocal->valuators) * numAxes); + } else { + if (++dmxLocal->tail >= DMX_MOTION_SIZE) dmxLocal->tail = 0; + if (dmxLocal->head == dmxLocal->tail) + if (++dmxLocal->head >= DMX_MOTION_SIZE) dmxLocal->head = 0; + } + + dmxLocal->history[OFFSET(dmxLocal->tail,0)] = time; + + /* Initialize the data from the known + * values (if Absolute) or to zero (if + * Relative) */ + if (pDevice->valuator->mode == Absolute) { + for (i = 0; i < numAxes; i++) + dmxLocal->history[OFFSET(dmxLocal->tail,i+1)] + = dmxLocal->valuators[i]; + } else { + for (i = 0; i < numAxes; i++) + dmxLocal->history[OFFSET(dmxLocal->tail,i+1)] = 0; + } + + for (i = firstAxis; i < axesCount; i++) { + dmxLocal->history[OFFSET(dmxLocal->tail,i+i)] + = (unsigned long)v[i-firstAxis]; + dmxLocal->valuators[i] = v[i-firstAxis]; + } +} diff --git a/xorg-server/hw/dmx/input/dmxmotion.h b/xorg-server/hw/dmx/input/dmxmotion.h new file mode 100644 index 000000000..88aeb3d09 --- /dev/null +++ b/xorg-server/hw/dmx/input/dmxmotion.h @@ -0,0 +1,49 @@ +/* + * Copyright 2002 Red Hat Inc., Durham, North Carolina. + * + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation on the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NON-INFRINGEMENT. IN NO EVENT SHALL RED HAT AND/OR THEIR SUPPLIERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* + * Authors: + * Rickard E. (Rik) Faith <faith@redhat.com> + * + */ + +/** \file + * Interface to functions supporting motion events. \see dmxmotion.c */ + +#ifndef _DMXMOTION_H_ +#define _DMXMOTION_H_ + +extern int dmxPointerGetMotionBufferSize(void); +extern int dmxPointerGetMotionEvents(DeviceIntPtr pDevice, + xTimecoord *coords, + unsigned long start, + unsigned long stop, + ScreenPtr pScreen); +extern void dmxPointerPutMotionEvent(DeviceIntPtr pDevice, + int firstAxis, int axesCount, int *v, + unsigned long time); +#endif diff --git a/xorg-server/hw/dmx/input/dmxsigio.c b/xorg-server/hw/dmx/input/dmxsigio.c new file mode 100644 index 000000000..03c3070d7 --- /dev/null +++ b/xorg-server/hw/dmx/input/dmxsigio.c @@ -0,0 +1,233 @@ +/* + * Copyright 2002-2003 Red Hat Inc., Durham, North Carolina. + * + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation on the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NON-INFRINGEMENT. IN NO EVENT SHALL RED HAT AND/OR THEIR SUPPLIERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* + * Authors: + * Rickard E. (Rik) Faith <faith@redhat.com> + * + */ + +/** \file + * + * Provides an interface for handling SIGIO signals for input devices. */ + +#ifdef HAVE_DMX_CONFIG_H +#include <dmx-config.h> +#endif + +#include "inputstr.h" +#include "dmxinputinit.h" +#include "dmxsigio.h" +#include "dmxevents.h" +#include <signal.h> +#include <unistd.h> +#include <fcntl.h> + +static int dmxFdCount = 0; +static Bool dmxInputEnabled = TRUE; + +/* Define equivalents for non-POSIX systems (e.g., SGI IRIX, Solaris) */ +#ifndef O_ASYNC +# ifdef FASYNC +# define O_ASYNC FASYNC +# else +# define O_ASYNC 0 +# endif +#endif +#ifndef O_NONBLOCK +#define O_NONBLOCK FNONBLK +#endif + +static void dmxSigioHandler(int sig) +{ + int i, j; + DMXInputInfo *dmxInput; + + for (i = 0, dmxInput = &dmxInputs[0]; i < dmxNumInputs; i++, dmxInput++) { + if (dmxInput->sigioState == DMX_ACTIVESIGIO) { + for (j = 0; j < dmxInput->numDevs; j++) { + DMXLocalInputInfoPtr dmxLocal = dmxInput->devs[j]; + if (dmxLocal->collect_events) { + dmxLocal->collect_events(&dmxLocal->pDevice->public, + dmxMotion, + dmxEnqueue, + dmxCheckSpecialKeys, + DMX_NO_BLOCK); + } + } + } + } +} + +/** Block SIGIO handling. */ +void dmxSigioBlock(void) +{ + sigset_t s; + + sigemptyset(&s); + sigaddset(&s, SIGIO); + sigprocmask(SIG_BLOCK, &s, 0); +} + +/** Unblock SIGIO handling. */ +void dmxSigioUnblock(void) +{ + sigset_t s; + + sigemptyset(&s); + sigaddset(&s, SIGIO); + sigprocmask(SIG_UNBLOCK, &s, 0); +} + +static void dmxSigioHook(void) +{ + struct sigaction a; + sigset_t s; + + memset(&a, 0, sizeof(a)); + a.sa_handler = dmxSigioHandler; + sigemptyset(&a.sa_mask); + sigaddset(&a.sa_mask, SIGIO); + sigaddset(&a.sa_mask, SIGALRM); + sigaddset(&a.sa_mask, SIGVTALRM); + sigaction(SIGIO, &a, 0); + + sigemptyset(&s); + sigprocmask(SIG_SETMASK, &s, 0); +} + +static void dmxSigioUnhook(void) +{ + struct sigaction a; + + memset (&a, 0, sizeof(a)); + a.sa_handler = SIG_IGN; + sigemptyset(&a.sa_mask); + sigaction(SIGIO, &a, 0); +} + +static void dmxSigioAdd(DMXInputInfo *dmxInput) +{ + int flags; + int i; + + switch (dmxInput->sigioState) { + case DMX_NOSIGIO: return; + case DMX_USESIGIO: dmxInput->sigioState = DMX_ACTIVESIGIO; break; + case DMX_ACTIVESIGIO: return; + } + + for (i = 0; i < dmxInput->sigioFdCount; i++) { + if (!dmxInput->sigioAdded[i]) { + int fd = dmxInput->sigioFd[i]; + + fcntl(fd, F_SETOWN, getpid()); + flags = fcntl(fd, F_GETFL); + flags |= O_ASYNC|O_NONBLOCK; + fcntl(fd, F_SETFL, flags); + + AddEnabledDevice(fd); + dmxInput->sigioAdded[i] = TRUE; + + if (++dmxFdCount == 1) dmxSigioHook(); + } + } +} + +static void dmxSigioRemove(DMXInputInfo *dmxInput) +{ + int flags; + int i; + + switch (dmxInput->sigioState) { + case DMX_NOSIGIO: return; + case DMX_USESIGIO: return; + case DMX_ACTIVESIGIO: dmxInput->sigioState = DMX_USESIGIO; break; + } + + for (i = 0; i < dmxInput->sigioFdCount; i++) { + if (dmxInput->sigioAdded[i]) { + int fd = dmxInput->sigioFd[i]; + + dmxInput->sigioAdded[i] = FALSE; + RemoveEnabledDevice(fd); + + flags = fcntl(fd, F_GETFL); + flags &= ~(O_ASYNC|O_NONBLOCK); + fcntl(fd, F_SETFL, flags); + + if (!--dmxFdCount) dmxSigioUnhook(); + } + } +} + +/** Enable SIGIO handling. This instantiates the handler with the OS. */ +void dmxSigioEnableInput(void) +{ + int i; + DMXInputInfo *dmxInput; + + dmxInputEnabled = TRUE; + for (i = 0, dmxInput = &dmxInputs[0]; i < dmxNumInputs; i++, dmxInput++) + dmxSigioAdd(dmxInput); +} + +/** Disable SIGIO handling. This removes the hanlder from the OS. */ +void dmxSigioDisableInput(void) +{ + int i; + DMXInputInfo *dmxInput; + + dmxInputEnabled = FALSE; + for (i = 0, dmxInput = &dmxInputs[0]; i < dmxNumInputs; i++, dmxInput++) + dmxSigioRemove(dmxInput); +} + +/** Make a note that the input device described in \a dmxInput will be + * using the file descriptor \a fd for SIGIO signals. Calls + * AddEnabledDevice ifi SIGIO handling has been enabled with + * #dmxSigioEnableInput(). */ +void dmxSigioRegister(DMXInputInfo *dmxInput, int fd) +{ + dmxInput->sigioState = DMX_USESIGIO; + if (dmxInput->sigioFdCount >= DMX_MAX_SIGIO_FDS) + dmxLog(dmxFatal, "Too many SIGIO file descriptors (%d >= %d)\n", + dmxInput->sigioFdCount, DMX_MAX_SIGIO_FDS); + + dmxInput->sigioFd[dmxInput->sigioFdCount++] = fd; + if (dmxInputEnabled) dmxSigioAdd(dmxInput); +} + +/** Remove the notes that \a dmxInput is using any file descriptors for + * SIGIO signals. Calls RemoveEnabledDevice. */ +void dmxSigioUnregister(DMXInputInfo *dmxInput) +{ + if (dmxInput->sigioState == DMX_NOSIGIO) return; + dmxSigioRemove(dmxInput); + dmxInput->sigioState = DMX_NOSIGIO; + dmxInput->sigioFdCount = 0; +} diff --git a/xorg-server/hw/dmx/input/dmxsigio.h b/xorg-server/hw/dmx/input/dmxsigio.h new file mode 100644 index 000000000..83f8060ae --- /dev/null +++ b/xorg-server/hw/dmx/input/dmxsigio.h @@ -0,0 +1,45 @@ +/* + * Copyright 2001 Red Hat Inc., Durham, North Carolina. + * + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation on the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NON-INFRINGEMENT. IN NO EVENT SHALL RED HAT AND/OR THEIR SUPPLIERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* + * Authors: + * Rickard E. (Rik) Faith <faith@redhat.com> + * + */ + +/** \file + * Interface to SIGIO handling support. \see dmxsigio.c */ + +#ifndef _DMXSIGIO_H_ +#define _DMXSIGIO_H_ +extern void dmxSigioBlock(void); +extern void dmxSigioUnblock(void); +extern void dmxSigioEnableInput(void); +extern void dmxSigioDisableInput(void); +extern void dmxSigioRegister(DMXInputInfo *dmxInput, int fd); +extern void dmxSigioUnregister(DMXInputInfo *dmxInput); +#endif diff --git a/xorg-server/hw/dmx/input/dmxxinput.c b/xorg-server/hw/dmx/input/dmxxinput.c new file mode 100644 index 000000000..97bea7596 --- /dev/null +++ b/xorg-server/hw/dmx/input/dmxxinput.c @@ -0,0 +1,159 @@ +/* + * Copyright 2002-2003 Red Hat Inc., Durham, North Carolina. + * + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation on the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NON-INFRINGEMENT. IN NO EVENT SHALL RED HAT AND/OR THEIR SUPPLIERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* + * Authors: + * Rickard E. (Rik) Faith <faith@redhat.com> + * + */ + +/** \file + * + * This file implements support required by the XINPUT extension. + */ + +#ifdef HAVE_DMX_CONFIG_H +#include <dmx-config.h> +#endif + +#define NEED_EVENTS +#include <X11/X.h> +#include <X11/Xproto.h> +#include "inputstr.h" +#include <X11/extensions/XI.h> +#include <X11/extensions/XIproto.h> +#include "XIstubs.h" + +#include "mipointer.h" +#include "dmxinputinit.h" +#include "exevents.h" + +/** Change the core keyboard from \a old_dev to \a new_dev. Currently + * this is not implemented. */ +int ChangeKeyboardDevice(DeviceIntPtr old_dev, DeviceIntPtr new_dev) +{ +#if 0 + DMXLocalInputInfoPtr dmxLocalOld = old_dev->public.devicePrivate; + DMXLocalInputInfoPtr dmxLocalNew = new_dev->public.devicePrivate; + + /* Switch our notion of core keyboard */ + dmxLocalOld->isCore = 0; + dmxLocalOld->sendsCore = dmxLocalOld->savedSendsCore; + + dmxLocalNew->isCore = 1; + dmxLocalNew->savedSendsCore = dmxLocalNew->sendsCore; + dmxLocalNew->sendsCore = 1; + dmxLocalCorePointer = dmxLocalNew; + + RegisterKeyboardDevice(new_dev); + RegisterOtherDevice(old_dev); + + return Success; +#endif + return BadMatch; +} + +/** Change the core pointer from \a old_dev to \a new_dev. */ +int ChangePointerDevice(DeviceIntPtr old_dev, + DeviceIntPtr new_dev, + unsigned char x, + unsigned char y) +{ + DMXLocalInputInfoPtr dmxLocalOld = old_dev->public.devicePrivate; + DMXLocalInputInfoPtr dmxLocalNew = new_dev->public.devicePrivate; + + if (x != 0 || y != 1) return BadMatch; + + /* Make sure the new device can focus */ + InitFocusClassDeviceStruct(old_dev); + + /* Switch the motion history buffers */ + if (dmxLocalOld->savedMotionProc) { + old_dev->valuator->GetMotionProc = dmxLocalOld->savedMotionProc; + old_dev->valuator->numMotionEvents = dmxLocalOld->savedMotionEvents; + } + dmxLocalNew->savedMotionProc = new_dev->valuator->GetMotionProc; + dmxLocalNew->savedMotionEvents = new_dev->valuator->numMotionEvents; +#if 00 /*BP*/ + new_dev->valuator->GetMotionProc = miPointerGetMotionEvents; + new_dev->valuator->numMotionEvents = miPointerGetMotionBufferSize(); +#else + new_dev->valuator->GetMotionProc = GetMotionHistory; + new_dev->valuator->numMotionEvents = GetMaximumEventsNum(); +#endif + /* Switch our notion of core pointer */ + dmxLocalOld->isCore = 0; + dmxLocalOld->sendsCore = dmxLocalOld->savedSendsCore; + + dmxLocalNew->isCore = 1; + dmxLocalNew->savedSendsCore = dmxLocalNew->sendsCore; + dmxLocalNew->sendsCore = 1; + dmxLocalCorePointer = dmxLocalNew; + + return Success; +} + +/** Close the input device. This is not required by the XINPUT model + * that DMX uses. */ +void CloseInputDevice (DeviceIntPtr d, ClientPtr client) +{ +} + +/** This is not required by the XINPUT model that DMX uses. */ +void AddOtherInputDevices(void) +{ +} + +/** Open an input device. This is not required by the XINPUT model that + * DMX uses. */ +void OpenInputDevice (DeviceIntPtr dev, ClientPtr client, int *status) +{ +} + +/** Set device mode to \a mode. This is not implemented. */ +int SetDeviceMode(ClientPtr client, DeviceIntPtr dev, int mode) +{ + return BadMatch; +} + +/** Set device valuators. This is not implemented. */ +int SetDeviceValuators (ClientPtr client, + DeviceIntPtr dev, + int *valuators, + int first_valuator, + int num_valuators) +{ + return BadMatch; +} + +/** Change device control. This is not implemented. */ +int ChangeDeviceControl(ClientPtr client, + DeviceIntPtr dev, + xDeviceCtl *control) +{ + return BadMatch; +} diff --git a/xorg-server/hw/dmx/input/lnx-keyboard.c b/xorg-server/hw/dmx/input/lnx-keyboard.c new file mode 100644 index 000000000..42a807b11 --- /dev/null +++ b/xorg-server/hw/dmx/input/lnx-keyboard.c @@ -0,0 +1,986 @@ +/* Portions of this file were derived from the following files: + * + ********************************************************************** + * + * xfree86/common/{xf86Io.c,xf86Kbd.c,xf86Events.c} + * + * Copyright 1990,91 by Thomas Roell, Dinkelscherben, Germany. + * + * Permission to use, copy, modify, distribute, and sell this software and its + * documentation for any purpose is hereby granted without fee, provided that + * the above copyright notice appear in all copies and that both that + * copyright notice and this permission notice appear in supporting + * documentation, and that the name of Thomas Roell not be used in + * advertising or publicity pertaining to distribution of the software without + * specific, written prior permission. Thomas Roell makes no representations + * about the suitability of this software for any purpose. It is provided + * "as is" without express or implied warranty. + * + * THOMAS ROELL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO + * EVENT SHALL THOMAS ROELL BE LIABLE FOR ANY SPECIAL, INDIRECT OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, + * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + * + ********************************************************************** + * + * xfree86/common/xf86KbdLnx.c + * + * Linux version of keymapping setup. The kernel (since 0.99.14) has support + * for fully remapping the keyboard, but there are some differences between + * the Linux map and the SVR4 map (esp. in the extended keycodes). We also + * remove the restriction on what keycodes can be remapped. + * Orest Zborowski. + * + * Copyright 1990,91 by Thomas Roell, Dinkelscherben, Germany. + * + * Permission to use, copy, modify, distribute, and sell this software and its + * documentation for any purpose is hereby granted without fee, provided that + * the above copyright notice appear in all copies and that both that + * copyright notice and this permission notice appear in supporting + * documentation, and that the name of Thomas Roell not be used in + * advertising or publicity pertaining to distribution of the software without + * specific, written prior permission. Thomas Roell makes no representations + * about the suitability of this software for any purpose. It is provided + * "as is" without express or implied warranty. + * + * THOMAS ROELL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO + * EVENT SHALL THOMAS ROELL BE LIABLE FOR ANY SPECIAL, INDIRECT OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, + * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + * + ********************************************************************** + * + * xfree86/os-support/linux/lnx_io.c + * + * Copyright 1992 by Orest Zborowski <obz@Kodak.com> + * Copyright 1993 by David Dawes <dawes@xfree86.org> + * + * Permission to use, copy, modify, distribute, and sell this software and its + * documentation for any purpose is hereby granted without fee, provided that + * the above copyright notice appear in all copies and that both that + * copyright notice and this permission notice appear in supporting + * documentation, and that the names of Orest Zborowski and David Dawes + * not be used in advertising or publicity pertaining to distribution of + * the software without specific, written prior permission. Orest Zborowski + * and David Dawes make no representations about the suitability of this + * software for any purpose. It is provided "as is" without express or + * implied warranty. + * + * OREST ZBOROWSKI AND DAVID DAWES DISCLAIMS ALL WARRANTIES WITH REGARD + * TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL OREST ZBOROWSKI OR DAVID DAWES BE LIABLE + * FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + */ + +/* + * Copyright 2001-2003 Red Hat Inc., Durham, North Carolina. + * + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation on the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NON-INFRINGEMENT. IN NO EVENT SHALL RED HAT AND/OR THEIR SUPPLIERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* + * Authors: + * Rickard E. (Rik) Faith <faith@redhat.com> + * + */ + +/** \file + * + * This code implements a low-level device driver for the Linux + * keyboard. The code is derived from code by Thomas Roell, Orest + * Zborowski, and David Dawes (see the source code for complete + * references). */ + +#ifdef HAVE_DMX_CONFIG_H +#include <dmx-config.h> +#endif + +/*****************************************************************************/ +/* Define some macros to make it easier to move this file to another + * part of the Xserver tree. All calls to the dmx* layer are #defined + * here for the .c file. The .h file will also have to be edited. */ +#include "dmxinputinit.h" +#include "lnx-keyboard.h" + +#define GETPRIV myPrivate *priv \ + = ((DMXLocalInputInfoPtr)(pDev->devicePrivate))->private + +#define LOG0(f) dmxLog(dmxDebug,f) +#define LOG1(f,a) dmxLog(dmxDebug,f,a) +#define LOG2(f,a,b) dmxLog(dmxDebug,f,a,b) +#define LOG3(f,a,b,c) dmxLog(dmxDebug,f,a,b,c) +#define FATAL0(f) dmxLog(dmxFatal,f) +#define FATAL1(f,a) dmxLog(dmxFatal,f,a) +#define FATAL2(f,a,b) dmxLog(dmxFatal,f,a,b) +#define MOTIONPROC dmxMotionProcPtr +#define ENQUEUEPROC dmxEnqueueProcPtr +#define CHECKPROC dmxCheckSpecialProcPtr +#define SWITCHRETPROC dmxVTSwitchReturnProcPtr +#define BLOCK DMXBlockType +#define MESSAGE "\033c\n\n\nDMX taking input from this console..." +#define FINALMESSAGE "\033cDMX terminated." + +/* End of interface definitions. */ +/*****************************************************************************/ + +#include "inputstr.h" +#include <X11/Xos.h> +#include <sys/ioctl.h> +#include <errno.h> +#include <signal.h> +#include <sys/vt.h> +#include <sys/kd.h> +#include <termios.h> +#include "atKeynames.h" +#if 00 +#include "xf86Keymap.h" +#endif +#include <linux/keyboard.h> + +#define NUM_AT2LNX (sizeof(at2lnx) / sizeof(at2lnx[0])) +#define NUM_STATE_ENTRIES (256/32) + + +/* Private area for Linux-style keyboards. */ +typedef struct _myPrivate { + int fd; + int vtno; + int vtcurrent; + int kbdtrans; + struct termios kbdtty; + int kbdType; + CARD32 kbdState[NUM_STATE_ENTRIES]; + DeviceIntPtr pKeyboard; + unsigned char prefix; + + int switched; + SWITCHRETPROC switch_return; + void *switch_return_data; + + /* For bell */ + int pitch; + unsigned long duration; +} myPrivate; + +static myPrivate *PRIV = NULL; + +#undef SYSCALL +#define SYSCALL(call) while(((call) == -1) && (errno == EINTR)) + +static int kbdLinuxKeyDown(myPrivate *priv, int keyCode) +{ + CARD8 byte = keyCode >> 5; + CARD32 bit = 1 << (keyCode & 0x1f); + + if (byte > NUM_STATE_ENTRIES) return 0; + return priv->kbdState[byte] & bit; +} + +static void kbdLinuxKeyState(myPrivate *priv, int type, int keyCode) +{ + CARD8 byte = keyCode >> 5; + CARD32 bit = 1 << (keyCode & 0x1f); + + if (byte > NUM_STATE_ENTRIES) return; + if (type == KeyPress) priv->kbdState[byte] |= bit; + else priv->kbdState[byte] &= ~bit; +} + +static KeySym linux_to_x[256] = { + NoSymbol, NoSymbol, NoSymbol, NoSymbol, + NoSymbol, NoSymbol, NoSymbol, NoSymbol, + XK_BackSpace, XK_Tab, XK_Linefeed, NoSymbol, + NoSymbol, NoSymbol, NoSymbol, NoSymbol, + NoSymbol, NoSymbol, NoSymbol, NoSymbol, + NoSymbol, NoSymbol, NoSymbol, NoSymbol, + NoSymbol, NoSymbol, NoSymbol, XK_Escape, + NoSymbol, NoSymbol, NoSymbol, NoSymbol, + XK_space, XK_exclam, XK_quotedbl, XK_numbersign, + XK_dollar, XK_percent, XK_ampersand, XK_apostrophe, + XK_parenleft, XK_parenright, XK_asterisk, XK_plus, + XK_comma, XK_minus, XK_period, XK_slash, + XK_0, XK_1, XK_2, XK_3, + XK_4, XK_5, XK_6, XK_7, + XK_8, XK_9, XK_colon, XK_semicolon, + XK_less, XK_equal, XK_greater, XK_question, + XK_at, XK_A, XK_B, XK_C, + XK_D, XK_E, XK_F, XK_G, + XK_H, XK_I, XK_J, XK_K, + XK_L, XK_M, XK_N, XK_O, + XK_P, XK_Q, XK_R, XK_S, + XK_T, XK_U, XK_V, XK_W, + XK_X, XK_Y, XK_Z, XK_bracketleft, + XK_backslash, XK_bracketright,XK_asciicircum, XK_underscore, + XK_grave, XK_a, XK_b, XK_c, + XK_d, XK_e, XK_f, XK_g, + XK_h, XK_i, XK_j, XK_k, + XK_l, XK_m, XK_n, XK_o, + XK_p, XK_q, XK_r, XK_s, + XK_t, XK_u, XK_v, XK_w, + XK_x, XK_y, XK_z, XK_braceleft, + XK_bar, XK_braceright, XK_asciitilde, XK_BackSpace, + NoSymbol, NoSymbol, NoSymbol, NoSymbol, + NoSymbol, NoSymbol, NoSymbol, NoSymbol, + NoSymbol, NoSymbol, NoSymbol, NoSymbol, + NoSymbol, NoSymbol, NoSymbol, NoSymbol, + NoSymbol, NoSymbol, NoSymbol, NoSymbol, + NoSymbol, NoSymbol, NoSymbol, NoSymbol, + NoSymbol, NoSymbol, NoSymbol, NoSymbol, + NoSymbol, NoSymbol, NoSymbol, NoSymbol, + XK_nobreakspace,XK_exclamdown, XK_cent, XK_sterling, + XK_currency, XK_yen, XK_brokenbar, XK_section, + XK_diaeresis, XK_copyright, XK_ordfeminine, XK_guillemotleft, + XK_notsign, XK_hyphen, XK_registered, XK_macron, + XK_degree, XK_plusminus, XK_twosuperior, XK_threesuperior, + XK_acute, XK_mu, XK_paragraph, XK_periodcentered, + XK_cedilla, XK_onesuperior, XK_masculine, XK_guillemotright, + XK_onequarter, XK_onehalf, XK_threequarters,XK_questiondown, + XK_Agrave, XK_Aacute, XK_Acircumflex, XK_Atilde, + XK_Adiaeresis, XK_Aring, XK_AE, XK_Ccedilla, + XK_Egrave, XK_Eacute, XK_Ecircumflex, XK_Ediaeresis, + XK_Igrave, XK_Iacute, XK_Icircumflex, XK_Idiaeresis, + XK_ETH, XK_Ntilde, XK_Ograve, XK_Oacute, + XK_Ocircumflex, XK_Otilde, XK_Odiaeresis, XK_multiply, + XK_Ooblique, XK_Ugrave, XK_Uacute, XK_Ucircumflex, + XK_Udiaeresis, XK_Yacute, XK_THORN, XK_ssharp, + XK_agrave, XK_aacute, XK_acircumflex, XK_atilde, + XK_adiaeresis, XK_aring, XK_ae, XK_ccedilla, + XK_egrave, XK_eacute, XK_ecircumflex, XK_ediaeresis, + XK_igrave, XK_iacute, XK_icircumflex, XK_idiaeresis, + XK_eth, XK_ntilde, XK_ograve, XK_oacute, + XK_ocircumflex, XK_otilde, XK_odiaeresis, XK_division, + XK_oslash, XK_ugrave, XK_uacute, XK_ucircumflex, + XK_udiaeresis, XK_yacute, XK_thorn, XK_ydiaeresis +}; + +/* + * Maps the AT keycodes to Linux keycodes + */ +static unsigned char at2lnx[NUM_KEYCODES] = +{ + 0x01, /* KEY_Escape */ 0x02, /* KEY_1 */ + 0x03, /* KEY_2 */ 0x04, /* KEY_3 */ + 0x05, /* KEY_4 */ 0x06, /* KEY_5 */ + 0x07, /* KEY_6 */ 0x08, /* KEY_7 */ + 0x09, /* KEY_8 */ 0x0a, /* KEY_9 */ + 0x0b, /* KEY_0 */ 0x0c, /* KEY_Minus */ + 0x0d, /* KEY_Equal */ 0x0e, /* KEY_BackSpace */ + 0x0f, /* KEY_Tab */ 0x10, /* KEY_Q */ + 0x11, /* KEY_W */ 0x12, /* KEY_E */ + 0x13, /* KEY_R */ 0x14, /* KEY_T */ + 0x15, /* KEY_Y */ 0x16, /* KEY_U */ + 0x17, /* KEY_I */ 0x18, /* KEY_O */ + 0x19, /* KEY_P */ 0x1a, /* KEY_LBrace */ + 0x1b, /* KEY_RBrace */ 0x1c, /* KEY_Enter */ + 0x1d, /* KEY_LCtrl */ 0x1e, /* KEY_A */ + 0x1f, /* KEY_S */ 0x20, /* KEY_D */ + 0x21, /* KEY_F */ 0x22, /* KEY_G */ + 0x23, /* KEY_H */ 0x24, /* KEY_J */ + 0x25, /* KEY_K */ 0x26, /* KEY_L */ + 0x27, /* KEY_SemiColon */ 0x28, /* KEY_Quote */ + 0x29, /* KEY_Tilde */ 0x2a, /* KEY_ShiftL */ + 0x2b, /* KEY_BSlash */ 0x2c, /* KEY_Z */ + 0x2d, /* KEY_X */ 0x2e, /* KEY_C */ + 0x2f, /* KEY_V */ 0x30, /* KEY_B */ + 0x31, /* KEY_N */ 0x32, /* KEY_M */ + 0x33, /* KEY_Comma */ 0x34, /* KEY_Period */ + 0x35, /* KEY_Slash */ 0x36, /* KEY_ShiftR */ + 0x37, /* KEY_KP_Multiply */ 0x38, /* KEY_Alt */ + 0x39, /* KEY_Space */ 0x3a, /* KEY_CapsLock */ + 0x3b, /* KEY_F1 */ 0x3c, /* KEY_F2 */ + 0x3d, /* KEY_F3 */ 0x3e, /* KEY_F4 */ + 0x3f, /* KEY_F5 */ 0x40, /* KEY_F6 */ + 0x41, /* KEY_F7 */ 0x42, /* KEY_F8 */ + 0x43, /* KEY_F9 */ 0x44, /* KEY_F10 */ + 0x45, /* KEY_NumLock */ 0x46, /* KEY_ScrollLock */ + 0x47, /* KEY_KP_7 */ 0x48, /* KEY_KP_8 */ + 0x49, /* KEY_KP_9 */ 0x4a, /* KEY_KP_Minus */ + 0x4b, /* KEY_KP_4 */ 0x4c, /* KEY_KP_5 */ + 0x4d, /* KEY_KP_6 */ 0x4e, /* KEY_KP_Plus */ + 0x4f, /* KEY_KP_1 */ 0x50, /* KEY_KP_2 */ + 0x51, /* KEY_KP_3 */ 0x52, /* KEY_KP_0 */ + 0x53, /* KEY_KP_Decimal */ 0x54, /* KEY_SysReqest */ + 0x00, /* 0x55 */ 0x56, /* KEY_Less */ + 0x57, /* KEY_F11 */ 0x58, /* KEY_F12 */ + 0x66, /* KEY_Home */ 0x67, /* KEY_Up */ + 0x68, /* KEY_PgUp */ 0x69, /* KEY_Left */ + 0x5d, /* KEY_Begin */ 0x6a, /* KEY_Right */ + 0x6b, /* KEY_End */ 0x6c, /* KEY_Down */ + 0x6d, /* KEY_PgDown */ 0x6e, /* KEY_Insert */ + 0x6f, /* KEY_Delete */ 0x60, /* KEY_KP_Enter */ + 0x61, /* KEY_RCtrl */ 0x77, /* KEY_Pause */ + 0x63, /* KEY_Print */ 0x62, /* KEY_KP_Divide */ + 0x64, /* KEY_AltLang */ 0x65, /* KEY_Break */ + 0x00, /* KEY_LMeta */ 0x00, /* KEY_RMeta */ + 0x7A, /* KEY_Menu/FOCUS_PF11*/0x00, /* 0x6e */ + 0x7B, /* FOCUS_PF12 */ 0x00, /* 0x70 */ + 0x00, /* 0x71 */ 0x00, /* 0x72 */ + 0x59, /* FOCUS_PF2 */ 0x78, /* FOCUS_PF9 */ + 0x00, /* 0x75 */ 0x00, /* 0x76 */ + 0x5A, /* FOCUS_PF3 */ 0x5B, /* FOCUS_PF4 */ + 0x5C, /* FOCUS_PF5 */ 0x5D, /* FOCUS_PF6 */ + 0x5E, /* FOCUS_PF7 */ 0x5F, /* FOCUS_PF8 */ + 0x7C, /* JAP_86 */ 0x79, /* FOCUS_PF10 */ + 0x00, /* 0x7f */ +}; + +/** Create a private structure for use within this file. */ +pointer kbdLinuxCreatePrivate(DeviceIntPtr pKeyboard) +{ + myPrivate *priv = xalloc(sizeof(*priv)); + memset(priv, 0, sizeof(*priv)); + priv->fd = -1; + priv->pKeyboard = pKeyboard; + return priv; +} + +/** Destroy a private structure. */ +void kbdLinuxDestroyPrivate(pointer priv) +{ + if (priv) xfree(priv); +} + +/** Ring the bell. + * + * Note: we completely ignore the \a volume, since Linux's ioctl() + * interface does not provide a way to control it. If it did, the XBell + * manpage tells how the actual volume is a function of the percent and + * the (base) volume. + * + * Note that most of the other PC-based bell drivers compute the + * duration for KDMKTONE as a function of the volume and the duration. + * For some drivers, the duration is only measured in mS if the volume + * is 50, and is scaled by the volume for other values. This seems + * confusing and possibly incorrect (the xset man page says that the + * bell will be "as closely as it can to the user's specifications" -- + * if we ignore the volume and set the duration correctly, then we'll + * get one parameter "wrong" -- but if we use the volume to scale the + * duration, then we'll get both parameters "wrong"). */ +void kbdLinuxBell(DevicePtr pDev, int percent, + int volume, int pitch, int duration) +{ + GETPRIV; + + if (duration && pitch) { + ioctl(priv->fd, + KDMKTONE, + ((1193190 / pitch) & 0xffff) /* Low bits specify cycle time */ + | (duration << 16)); /* High bits are duration in msec */ + } +} + +/** Set the LEDs. */ +void kbdLinuxCtrl(DevicePtr pDev, KeybdCtrl *ctrl) +{ + GETPRIV; + + ioctl(priv->fd, KDSETLED, ctrl->leds & 0x07); +} + +static int kbdLinuxGetFreeVTNumber(void) +{ + int fd = -1; + int vtno; + int i; + const char *tty0[] = { "/dev/tty0", "/dev/vc/0", NULL }; + + for (i = 0; tty0[i]; i++) + if ((fd = open(tty0[i], O_WRONLY, 0)) >= 0) break; + if (fd < 0) + FATAL1("kbdLinuxGetFreeVTNumber: Cannot open tty0 (%s)\n", + strerror(errno)); + if (ioctl(fd, VT_OPENQRY, &vtno) < 0 || vtno < 0) + FATAL0("kbdLinuxGetFreeVTNumber: Cannot find a free VT\n"); + return vtno; +} + +static int kbdLinuxOpenVT(int vtno) +{ + int fd = -1; + int i; + const char *vcs[] = { "/dev/vc/%d", "/dev/tty%d", NULL }; + char name[64]; /* RATS: Only used in XmuSnprintf */ + + for (i = 0; vcs[i]; i++) { + XmuSnprintf(name, sizeof(name), vcs[i], vtno); + if ((fd = open(name, O_RDWR | O_NONBLOCK, 0)) >= 0) break; + } + if (fd < 0) + FATAL2("kbdLinuxOpenVT: Cannot open VT %d (%s)\n", + vtno, strerror(errno)); + return fd; +} + +static int kbdLinuxGetCurrentVTNumber(int fd) +{ + struct vt_stat vts; + + if (!ioctl(fd, VT_GETSTATE, &vts)) return vts.v_active; + return -1; +} + +static int kbdLinuxActivate(int fd, int vtno, int setSig); + +/** Currently unused hook called prior to an VT switch. */ +void kbdLinuxVTPreSwitch(pointer p) +{ +} + +/** Currently unused hook called after returning from a VT switch. */ +void kbdLinuxVTPostSwitch(pointer p) +{ +} + +/** Tell the operating system to switch to \a vt. The \a switch_return + * function is called with the \a switch_return_data when the VT is + * switched back to the pre-switch VT (i.e., the user returns to the DMX + * session). */ +int kbdLinuxVTSwitch(pointer p, int vt, + void (*switch_return)(pointer), + pointer switch_return_data) +{ + myPrivate *priv = p; + + if (priv->switched) FATAL0("kbdLinuxVTSwitch: already switched...\n"); + if (priv->vtno == vt) return 0; + + PRIV = priv; + priv->switched = 0; /* Will switch to 1 in handler */ + priv->switch_return = switch_return; + priv->switch_return_data = switch_return_data; + kbdLinuxActivate(priv->fd, vt, 0); + return 1; +} + +/* RATS: This function is only ever used to handle SIGUSR1. */ +static void kbdLinuxVTSignalHandler(int sig) +{ + myPrivate *priv = PRIV; + + signal(sig, kbdLinuxVTSignalHandler); + if (priv) { + ioctl(priv->fd, VT_RELDISP, VT_ACKACQ); + priv->switched = !priv->switched; + LOG2("kbdLinuxVTSignalHandler: got signal %d, switched = %d\n", + sig, priv->switched); + if (!priv->switched && priv->switch_return) + priv->switch_return(priv->switch_return_data); + } +} + +static int kbdLinuxActivate(int fd, int vtno, int setSig) +{ + int result; + struct vt_mode VT; + + SYSCALL(result = ioctl(fd, VT_ACTIVATE, vtno)); + if (result) FATAL0("kbdLinuxActivate: VT_ACTIVATE failed\n"); + SYSCALL(result = ioctl(fd, VT_WAITACTIVE, vtno)); + if (result) FATAL0("kbdLinuxActivate: VT_WAITACTIVE failed\n"); + if (setSig) { + SYSCALL(result = ioctl(fd, VT_GETMODE, &VT)); + if (result < 0) FATAL0("kbdLinuxActivate: VT_GETMODE failed\n"); + VT.mode = VT_PROCESS; + VT.relsig = SIGUSR1; + VT.acqsig = SIGUSR1; + if (ioctl(fd, VT_SETMODE, &VT)) + FATAL0("kbdLinuxActivate: VT_SETMODE VT_PROCESS failed\n"); + signal(SIGUSR1, kbdLinuxVTSignalHandler); + } + return Success; +} + +static void kbdLinuxOpenConsole(DevicePtr pDev) +{ + GETPRIV; + const char *msg = MESSAGE; + + if (priv->fd >= 0) return; + priv->vtno = kbdLinuxGetFreeVTNumber(); + priv->fd = kbdLinuxOpenVT(priv->vtno); + priv->vtcurrent = kbdLinuxGetCurrentVTNumber(priv->fd); + LOG2("kbdLinuxOpenConsole: current VT %d; using free VT %d\n", + priv->vtcurrent, priv->vtno); + kbdLinuxActivate(priv->fd, priv->vtno, 1); + ioctl(priv->fd, KDSETMODE, KD_GRAPHICS); /* To turn off gpm */ + if (msg) write(priv->fd, msg, strlen(msg)); +} + +static void kbdLinuxCloseConsole(DevicePtr pDev) +{ + GETPRIV; + struct vt_mode VT; + const char *msg = FINALMESSAGE; + + if (priv->fd < 0) return; + + ioctl(priv->fd, KDSETMODE, KD_TEXT); + if (msg) write(priv->fd, msg, strlen(msg)); + if (ioctl(priv->fd, VT_GETMODE, &VT) != -1) { + VT.mode = VT_AUTO; + ioctl(priv->fd, VT_SETMODE, &VT); + } + + LOG1("kbdLinuxCloseConsole: switching to VT %d\n", priv->vtcurrent); + if (priv->vtcurrent >= 0) kbdLinuxActivate(priv->fd, priv->vtcurrent, 0); + + close(priv->fd); + priv->fd = -1; +} + +/** Initialize the \a pDev as a Linux keyboard. */ +void kbdLinuxInit(DevicePtr pDev) +{ + GETPRIV; + + if (priv->fd <= 0) kbdLinuxOpenConsole(pDev); + + ioctl(priv->fd, KDGKBMODE, &priv->kbdtrans); + if (tcgetattr(priv->fd, &priv->kbdtty) < 0) + FATAL1("kbdLinuxInit: tcgetattr failed (%s)\n", strerror(errno)); +} + +static int kbdLinuxPrefix0Mapping(unsigned char *scanCode) +{ + /* Table from xfree86/common/xf86Events.c */ + switch (*scanCode) { + case KEY_KP_7: *scanCode = KEY_Home; break; /* curs home */ + case KEY_KP_8: *scanCode = KEY_Up; break; /* curs up */ + case KEY_KP_9: *scanCode = KEY_PgUp; break; /* curs pgup */ + case KEY_KP_4: *scanCode = KEY_Left; break; /* curs left */ + case KEY_KP_5: *scanCode = KEY_Begin; break; /* curs begin */ + case KEY_KP_6: *scanCode = KEY_Right; break; /* curs right */ + case KEY_KP_1: *scanCode = KEY_End; break; /* curs end */ + case KEY_KP_2: *scanCode = KEY_Down; break; /* curs down */ + case KEY_KP_3: *scanCode = KEY_PgDown; break; /* curs pgdown */ + case KEY_KP_0: *scanCode = KEY_Insert; break; /* curs insert */ + case KEY_KP_Decimal: *scanCode = KEY_Delete; break; /* curs delete */ + case KEY_Enter: *scanCode = KEY_KP_Enter; break; /* keypad enter */ + case KEY_LCtrl: *scanCode = KEY_RCtrl; break; /* right ctrl */ + case KEY_KP_Multiply: *scanCode = KEY_Print; break; /* print */ + case KEY_Slash: *scanCode = KEY_KP_Divide; break; /* keyp divide */ + case KEY_Alt: *scanCode = KEY_AltLang; break; /* right alt */ + case KEY_ScrollLock: *scanCode = KEY_Break; break; /* curs break */ + case 0x5b: *scanCode = KEY_LMeta; break; + case 0x5c: *scanCode = KEY_RMeta; break; + case 0x5d: *scanCode = KEY_Menu; break; + case KEY_F3: *scanCode = KEY_F13; break; + case KEY_F4: *scanCode = KEY_F14; break; + case KEY_F5: *scanCode = KEY_F15; break; + case KEY_F6: *scanCode = KEY_F16; break; + case KEY_F7: *scanCode = KEY_F17; break; + case KEY_KP_Plus: *scanCode = KEY_KP_DEC; break; + /* + * Ignore virtual shifts (E0 2A, E0 AA, E0 36, E0 B6) + */ + case 0x2A: + case 0x36: + return 1; + default: + /* + * "Internet" keyboards are generating lots of new codes. + * Let them pass. There is little consistency between them, + * so don't bother with symbolic names at this level. + */ + scanCode += 0x78; + } + return 0; +} + +static int kbdLinuxPrefixMapping(myPrivate *priv, unsigned char *scanCode) +{ + int pressed = *scanCode & 0x80; + unsigned char code = *scanCode & 0x7f; + + /* If we don't have a prefix, check for one */ + if (!priv->prefix) { + switch (code) { + case KEY_Prefix0: + case KEY_Prefix1: + priv->prefix = code; + return 1; + } + return 0; /* No change */ + } + + /* We have a prefix from the last scanCode */ + switch (priv->prefix) { + case KEY_Prefix0: + priv->prefix = 0; + if (kbdLinuxPrefix0Mapping(&code)) return 1; /* Skip sequence */ + break; + case KEY_Prefix1: + priv->prefix = (code = KEY_LCtrl) ? KEY_LCtrl : 0; + return 1; /* Use new prefix */ + case KEY_LCtrl: + priv->prefix = 0; + if (code != KEY_NumLock) return 1; /* Skip sequence*/ + code = KEY_Pause; + break; + } + + *scanCode = code | (pressed ? 0x80 : 0x00); + return 0; /* Use old scanCode */ +} + +static void kbdLinuxConvert(DevicePtr pDev, + unsigned char scanCode, + ENQUEUEPROC enqueue, + CHECKPROC checkspecial, + BLOCK block) +{ + GETPRIV; + KeySymsPtr pKeySyms = &priv->pKeyboard->key->curKeySyms; + int type; + KeySym keySym = NoSymbol; + int keyCode; + int switching; + + /* Do special PC/AT prefix mapping -- may change scanCode! */ + if (kbdLinuxPrefixMapping(priv, &scanCode)) return; + + type = (scanCode & 0x80) ? KeyRelease : KeyPress; + keyCode = (scanCode & 0x7f) + MIN_KEYCODE; + + /* Handle repeats */ + + if (keyCode >= pKeySyms->minKeyCode && keyCode <= pKeySyms->maxKeyCode) { + keySym = pKeySyms->map[(keyCode - pKeySyms->minKeyCode) + * pKeySyms->mapWidth]; +#if 0 + switch (keySym) { + case XK_Num_Lock: + case XK_Scroll_Lock: + case XK_Shift_Lock: + case XK_Caps_Lock: + /* Ignore releases and all but first press */ + if (kbdLinuxModIgnore(priv, &xE, keySym)) return; + if (kbdLinuxKeyDown(priv, &xE)) xE.u.u.type = KeyRelease; + else xE.u.u.type = KeyPress; + break; + } +#endif + + /* If key is already down, ignore or autorepeat */ + if (type == KeyPress && kbdLinuxKeyDown(priv, keyCode)) { + KbdFeedbackClassRec *feed = priv->pKeyboard->kbdfeed; + + /* No auto-repeat? */ + if ((feed && !feed->ctrl.autoRepeat) + || priv->pKeyboard->key->modifierMap[keyCode] + || (feed + && !(feed->ctrl.autoRepeats[keyCode >> 3] + & (1 << (keyCode & 7))))) return; /* Ignore */ + + /* Do auto-repeat */ + enqueue(pDev, KeyRelease, keyCode, keySym, NULL, block); + type = KeyPress; + } + + /* If key is already up, ignore */ + if (type == KeyRelease && !kbdLinuxKeyDown(priv, keyCode)) return; + } + + switching = 0; + if (checkspecial && type == KeyPress) + switching = checkspecial(pDev, keySym); + if (!switching) { + if (enqueue) + enqueue(pDev, type, keyCode, keySym, NULL, block); + kbdLinuxKeyState(priv, type, keyCode); /* Update our state bitmap */ + } +} + +/** Read an event from the \a pDev device. If the event is a motion + * event, enqueue it with the \a motion function. Otherwise, check for + * special keys with the \a checkspecial function and enqueue the event + * with the \a enqueue function. The \a block type is passed to the + * functions so that they may block SIGIO handling as appropriate to the + * caller of this function. */ +void kbdLinuxRead(DevicePtr pDev, + MOTIONPROC motion, + ENQUEUEPROC enqueue, + CHECKPROC checkspecial, + BLOCK block) +{ + GETPRIV; + unsigned char buf[256]; /* RATS: Only used in length-limited call */ + unsigned char *pt; + int n; + + while ((n = read(priv->fd, buf, sizeof(buf))) > 0) + for (pt = buf; n; --n, ++pt) + kbdLinuxConvert(pDev, *pt, enqueue, checkspecial, block); +} + +/** Turn \a pDev on (i.e., take input from \a pDev). */ +int kbdLinuxOn(DevicePtr pDev) +{ + GETPRIV; + struct termios nTty; + + ioctl(priv->fd, KDSKBMODE, K_RAW); + + nTty = priv->kbdtty; + nTty.c_iflag = (IGNPAR | IGNBRK) & (~PARMRK) & (~ISTRIP); + nTty.c_oflag = 0; + nTty.c_cflag = CREAD | CS8; + nTty.c_lflag = 0; + nTty.c_cc[VTIME] = 0; + nTty.c_cc[VMIN] = 1; + cfsetispeed(&nTty, B9600); + cfsetospeed(&nTty, B9600); + if (tcsetattr(priv->fd, TCSANOW, &nTty) < 0) + FATAL1("kbdLinuxOn: tcsetattr failed (%s)\n", strerror(errno)); + return priv->fd; +} + +/** Turn \a pDev off (i.e., stop taking input from \a pDev). */ +void kbdLinuxOff(DevicePtr pDev) +{ + GETPRIV; + + ioctl(priv->fd, KDSKBMODE, priv->kbdtrans); + tcsetattr(priv->fd, TCSANOW, &priv->kbdtty); + kbdLinuxCloseConsole(pDev); +} + + +static void kbdLinuxReadKernelMapping(int fd, KeySymsPtr pKeySyms) +{ + KeySym *k; + int i; + int maxkey; + static unsigned char tbl[GLYPHS_PER_KEY] = { /* RATS: Use ok */ + 0, /* unshifted */ + 1, /* shifted */ + 0, /* modeswitch unshifted */ + 0 /* modeswitch shifted */ + }; + + /* + * Read the mapping from the kernel. + * Since we're still using the XFree86 scancode->AT keycode mapping + * routines, we need to convert the AT keycodes to Linux keycodes, + * then translate the Linux keysyms into X keysyms. + * + * First, figure out which tables to use for the modeswitch columns + * above, from the XF86Config fields. + */ + tbl[2] = 8; /* alt */ + tbl[3] = tbl[2] | 1; + +#if 00/*BP*/ + k = map+GLYPHS_PER_KEY; +#else + ErrorF("kbdLinuxReadKernelMapping() is broken/no-op'd\n"); + return; +#endif + maxkey = NUM_AT2LNX; + + for (i = 0; i < maxkey; ++i) { + struct kbentry kbe; + int j; + + kbe.kb_index = at2lnx[i]; + + for (j = 0; j < GLYPHS_PER_KEY; ++j, ++k) { + unsigned short kval; + + *k = NoSymbol; + + kbe.kb_table = tbl[j]; + if (kbe.kb_index == 0 || ioctl(fd, KDGKBENT, &kbe)) continue; + + kval = KVAL(kbe.kb_value); + switch (KTYP(kbe.kb_value)) { + case KT_LATIN: + case KT_LETTER: *k = linux_to_x[kval]; break; + case KT_FN: + if (kval <= 19) *k = XK_F1 + kval; + else switch (kbe.kb_value) { + case K_FIND: *k = XK_Home; /* or XK_Find */ break; + case K_INSERT: *k = XK_Insert; break; + case K_REMOVE: *k = XK_Delete; break; + case K_SELECT: *k = XK_End; /* or XK_Select */ break; + case K_PGUP: *k = XK_Prior; break; + case K_PGDN: *k = XK_Next; break; + case K_HELP: *k = XK_Help; break; + case K_DO: *k = XK_Execute; break; + case K_PAUSE: *k = XK_Pause; break; + case K_MACRO: *k = XK_Menu; break; + default: break; + } + break; + case KT_SPEC: + switch (kbe.kb_value) { + case K_ENTER: *k = XK_Return; break; + case K_BREAK: *k = XK_Break; break; + case K_CAPS: *k = XK_Caps_Lock; break; + case K_NUM: *k = XK_Num_Lock; break; + case K_HOLD: *k = XK_Scroll_Lock; break; + case K_COMPOSE: *k = XK_Multi_key; break; + default: break; + } + break; + case KT_PAD: + switch (kbe.kb_value) { + case K_PPLUS: *k = XK_KP_Add; break; + case K_PMINUS: *k = XK_KP_Subtract; break; + case K_PSTAR: *k = XK_KP_Multiply; break; + case K_PSLASH: *k = XK_KP_Divide; break; + case K_PENTER: *k = XK_KP_Enter; break; + case K_PCOMMA: *k = XK_KP_Separator; break; + case K_PDOT: *k = XK_KP_Decimal; break; + case K_PPLUSMINUS: *k = XK_KP_Subtract; break; + default: if (kval <= 9) *k = XK_KP_0 + kval; break; + } + break; + case KT_DEAD: + /* KT_DEAD keys are for accelerated diacritical creation. */ + switch (kbe.kb_value) { + case K_DGRAVE: *k = XK_dead_grave; break; + case K_DACUTE: *k = XK_dead_acute; break; + case K_DCIRCM: *k = XK_dead_circumflex; break; + case K_DTILDE: *k = XK_dead_tilde; break; + case K_DDIERE: *k = XK_dead_diaeresis; break; + } + break; + case KT_CUR: + switch (kbe.kb_value) { + case K_DOWN: *k = XK_Down; break; + case K_LEFT: *k = XK_Left; break; + case K_RIGHT: *k = XK_Right; break; + case K_UP: *k = XK_Up; break; + } + break; + case KT_SHIFT: + switch (kbe.kb_value) { + case K_ALTGR: *k = XK_Alt_R; break; + case K_ALT: + *k = (kbe.kb_index == 0x64 ? XK_Alt_R : XK_Alt_L); + break; + case K_CTRL: + *k = (kbe.kb_index == 0x61 ? XK_Control_R : XK_Control_L); + break; + case K_CTRLL: *k = XK_Control_L; break; + case K_CTRLR: *k = XK_Control_R; break; + case K_SHIFT: + *k = (kbe.kb_index == 0x36 ? XK_Shift_R : XK_Shift_L); + break; + case K_SHIFTL: *k = XK_Shift_L; break; + case K_SHIFTR: *k = XK_Shift_R; break; + default: break; + } + break; + case KT_ASCII: + /* KT_ASCII keys accumulate a 3 digit decimal number that + * gets emitted when the shift state changes. We can't + * emulate that. + */ + break; + case KT_LOCK: + if (kbe.kb_value == K_SHIFTLOCK) *k = XK_Shift_Lock; + break; + default: break; + } + } + + if (k[-1] == k[-2]) k[-1] = NoSymbol; + if (k[-2] == k[-3]) k[-2] = NoSymbol; + if (k[-3] == k[-4]) k[-3] = NoSymbol; + if (k[-4] == k[-2] && k[-3] == k[-1]) k[-2] = k[-1] = NoSymbol; + if (k[-1] == k[-4] && k[-2] == k[-3] + && k[-2] == NoSymbol) k[-1] = NoSymbol; + } +} + +static void kbdLinuxGetMap(DevicePtr pDev, KeySymsPtr pKeySyms, CARD8 *pModMap) +{ + GETPRIV; + KeySym *k, *mapCopy; + char type; + int i; + +#if 00/*BP*/ + mapCopy = xalloc(sizeof(map)); + memcpy(mapCopy, map, sizeof(map)); +#else + ErrorF("kbdLinuxGetMap() is broken/no-op'd\n"); + return; +#endif + + kbdLinuxReadKernelMapping(priv->fd, pKeySyms); + + /* compute the modifier map */ + for (i = 0; i < MAP_LENGTH; i++) + pModMap[i] = NoSymbol; /* make sure it is restored */ + + for (k = mapCopy, i = MIN_KEYCODE; + i < NUM_KEYCODES + MIN_KEYCODE; + i++, k += 4) { + switch(*k) { + case XK_Shift_L: + case XK_Shift_R: pModMap[i] = ShiftMask; break; + case XK_Control_L: + case XK_Control_R: pModMap[i] = ControlMask; break; + case XK_Caps_Lock: pModMap[i] = LockMask; break; + case XK_Alt_L: + case XK_Alt_R: pModMap[i] = AltMask; break; + case XK_Num_Lock: pModMap[i] = NumLockMask; break; + case XK_Scroll_Lock: pModMap[i] = ScrollLockMask; break; + case XK_Kana_Lock: + case XK_Kana_Shift: pModMap[i] = KanaMask; break; + case XK_Mode_switch: pModMap[i] = AltLangMask; break; + } + } + + priv->kbdType = (ioctl(priv->fd, KDGKBTYPE, &type) < 0) ? KB_101 : type; + + pKeySyms->map = mapCopy; /* Must be XFree'able */ + pKeySyms->mapWidth = GLYPHS_PER_KEY; + pKeySyms->minKeyCode = MIN_KEYCODE; + pKeySyms->maxKeyCode = MAX_KEYCODE; +} + +/** Fill the \a info structure with information needed to initialize \a + * pDev. */ +void kbdLinuxGetInfo(DevicePtr pDev, DMXLocalInitInfoPtr info) +{ + info->keyboard = 1; + info->keyClass = 1; + kbdLinuxGetMap(pDev, &info->keySyms, info->modMap); + info->focusClass = 1; + info->kbdFeedbackClass = 1; +} diff --git a/xorg-server/hw/dmx/input/lnx-keyboard.h b/xorg-server/hw/dmx/input/lnx-keyboard.h new file mode 100644 index 000000000..e36a50499 --- /dev/null +++ b/xorg-server/hw/dmx/input/lnx-keyboard.h @@ -0,0 +1,63 @@ +/* + * Copyright 2001 Red Hat Inc., Durham, North Carolina. + * + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation on the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NON-INFRINGEMENT. IN NO EVENT SHALL RED HAT AND/OR THEIR SUPPLIERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* + * Authors: + * Rickard E. (Rik) Faith <faith@redhat.com> + * + */ + +/** \file + * Interface to Linux keyboard driver. \see lnx-keyboard.c */ + +#ifndef _LNX_KEYBOARD_H_ +#define _LNX_KEYBOARD_H_ + +extern pointer kbdLinuxCreatePrivate(DeviceIntPtr pKeyboard); +extern void kbdLinuxDestroyPrivate(pointer private); + +extern void kbdLinuxInit(DevicePtr pDev); +extern void kbdLinuxGetInfo(DevicePtr pDev, DMXLocalInitInfoPtr info); +extern int kbdLinuxOn(DevicePtr pDev); +extern void kbdLinuxOff(DevicePtr pDev); + +extern void kbdLinuxVTPreSwitch(pointer p); +extern void kbdLinuxVTPostSwitch(pointer p); +extern int kbdLinuxVTSwitch(pointer p, int vt, + dmxVTSwitchReturnProcPtr switch_return, + pointer switch_return_data); + +extern void kbdLinuxRead(DevicePtr pDev, + dmxMotionProcPtr motion, + dmxEnqueueProcPtr enqueue, + dmxCheckSpecialProcPtr checkspecial, + DMXBlockType block); + +extern void kbdLinuxCtrl(DevicePtr pDev, KeybdCtrl *ctrl); +extern void kbdLinuxBell(DevicePtr pDev, int percent, + int volume, int pitch, int duration); +#endif diff --git a/xorg-server/hw/dmx/input/lnx-ms.c b/xorg-server/hw/dmx/input/lnx-ms.c new file mode 100644 index 000000000..b3692a071 --- /dev/null +++ b/xorg-server/hw/dmx/input/lnx-ms.c @@ -0,0 +1,322 @@ +/* Portions of this file were derived from the following files: + * + ********************************************************************** + * + * Xserver/hw/kdrive/linux/ms.c + * + * Copyright (c) 2001 by Juliusz Chroboczek + * Copyright (c) 1999 by Keith Packard + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +/* + * Copyright 2001-2003 Red Hat Inc., Durham, North Carolina. + * + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation on the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NON-INFRINGEMENT. IN NO EVENT SHALL RED HAT AND/OR THEIR SUPPLIERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* + * Authors: + * Rickard E. (Rik) Faith <faith@redhat.com> + * + */ + +/** \file + * + * This code implements a low-level device driver for a serial MS mouse. + * The code is derived from code by Juliusz Chroboczek and Keith Packard + * (see the source code for complete references). */ + +#ifdef HAVE_DMX_CONFIG_H +#include <dmx-config.h> +#endif + +#include "inputstr.h" +#include <X11/Xos.h> +#include <errno.h> +#include <termios.h> + +/*****************************************************************************/ +/* Define some macros to make it easier to move this file to another + * part of the Xserver tree. All calls to the dmx* layer are #defined + * here for the .c file. The .h file will also have to be edited. */ +#include "dmxinputinit.h" +#include "lnx-ms.h" + +#define GETPRIV myPrivate *priv \ + = ((DMXLocalInputInfoPtr)(pDev->devicePrivate))->private + +#define LOG0(f) dmxLog(dmxDebug,f) +#define LOG1(f,a) dmxLog(dmxDebug,f,a) +#define LOG2(f,a,b) dmxLog(dmxDebug,f,a,b) +#define LOG3(f,a,b,c) dmxLog(dmxDebug,f,a,b,c) +#define FATAL0(f) dmxLog(dmxFatal,f) +#define FATAL1(f,a) dmxLog(dmxFatal,f,a) +#define FATAL2(f,a,b) dmxLog(dmxFatal,f,a,b) +#define MOTIONPROC dmxMotionProcPtr +#define ENQUEUEPROC dmxEnqueueProcPtr +#define CHECKPROC dmxCheckSpecialProcPtr +#define BLOCK DMXBlockType + +/* End of interface definitions. */ +/*****************************************************************************/ + +/* Private area for MS mouse devices. */ +typedef struct _myPrivate { + DeviceIntPtr pMouse; + int fd; + struct termios tty; + enum { + button1 = 0x0001, + button2 = 0x0002, + button3 = 0x0004, + button4 = 0x0008, + button5 = 0x0010 + } buttons; +} myPrivate; + +static int msLinuxReadBytes(int fd, unsigned char *buf, int len, int min) +{ + int n, tot; + fd_set set; + struct timeval tv; + + tot = 0; + while (len) { + n = read(fd, buf, len); + if (n > 0) { + tot += n; + buf += n; + len -= n; + } + if (tot % min == 0) break; + FD_ZERO(&set); + FD_SET(fd, &set); + tv.tv_sec = 0; + tv.tv_usec = 100 * 1000; + n = select(fd + 1, &set, 0, 0, &tv); + if (n <= 0) break; + } + return tot; +} + +static void msLinuxButton(DevicePtr pDev, ENQUEUEPROC enqueue, int buttons, + BLOCK block) +{ + GETPRIV; + +#define PRESS(b) \ + do { \ + enqueue(pDev, ButtonPress, 0, 0, NULL, block); \ + } while (0) + +#define RELEASE(b) \ + do { \ + enqueue(pDev, ButtonRelease, 0, 0, NULL, block); \ + } while (0) + + if ((buttons & button1) && !(priv->buttons & button1)) PRESS(1); + if (!(buttons & button1) && (priv->buttons & button1)) RELEASE(1); + + if ((buttons & button2) && !(priv->buttons & button2)) PRESS(2); + if (!(buttons & button2) && (priv->buttons & button2)) RELEASE(2); + + if ((buttons & button3) && !(priv->buttons & button3)) PRESS(3); + if (!(buttons & button3) && (priv->buttons & button3)) RELEASE(3); + + if ((buttons & button4) && !(priv->buttons & button4)) PRESS(4); + if (!(buttons & button4) && (priv->buttons & button4)) RELEASE(4); + + if ((buttons & button5) && !(priv->buttons & button5)) PRESS(5); + if (!(buttons & button5) && (priv->buttons & button5)) RELEASE(5); + + priv->buttons = buttons; +} + +/** Read an event from the \a pDev device. If the event is a motion + * event, enqueue it with the \a motion function. Otherwise, check for + * special keys with the \a checkspecial function and enqueue the event + * with the \a enqueue function. The \a block type is passed to the + * functions so that they may block SIGIO handling as appropriate to the + * caller of this function. */ +void msLinuxRead(DevicePtr pDev, + MOTIONPROC motion, + ENQUEUEPROC enqueue, + CHECKPROC checkspecial, + BLOCK block) +{ + GETPRIV; + unsigned char buf[3 * 200]; /* RATS: Use ok */ + unsigned char *b; + int n; + int dx, dy, v[2]; + + while ((n = msLinuxReadBytes(priv->fd, buf, sizeof(buf), 3)) > 0) { + b = buf; + while (n >= 3) { + dx = (char)(((b[0] & 0x03) << 6) | (b[1] & 0x3f)); + dy = (char)(((b[0] & 0x0c) << 4) | (b[2] & 0x3f)); + v[0] = -dx; + v[1] = -dy; + + motion(pDev, v, 0, 2, 1, block); + msLinuxButton(pDev, enqueue, (((b[0] & 0x10) ? button3 : 0) + | ((b[0] & 0x20) ? button1 : 0)), + block); + n -= 3; + b += 3; + } + } +} + +/** Initialize \a pDev. */ +void msLinuxInit(DevicePtr pDev) +{ + GETPRIV; + const char *names[] = { "/dev/serialmouse", "/dev/mouse", NULL }; + int i; + + if (priv->fd >=0) return; + + for (i = 0; names[i]; i++) { + if ((priv->fd = open(names[i], O_RDWR | O_NONBLOCK, 0)) >= 0) break; + } + if (priv->fd < 0) + FATAL1("msLinuxInit: Cannot open mouse port (%s)\n", + strerror(errno)); + + if (!isatty(priv->fd)) + FATAL1("msLinuxInit: Mouse port %s is not a tty\n", names[i]); + + if (tcgetattr(priv->fd, &priv->tty) < 0) + FATAL1("msLinuxInit: tcgetattr failed (%s)\n", strerror(errno)); + + write(priv->fd, "*n", 2); /* 1200 baud */ + usleep(100000); +} + +/** Turn \a pDev on (i.e., take input from \a pDev). */ +int msLinuxOn(DevicePtr pDev) +{ + GETPRIV; + struct termios nTty; + + if (priv->fd < 0) msLinuxInit(pDev); + + nTty = priv->tty; + nTty.c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP | INLCR + | IGNCR | ICRNL | IXON | IXOFF); + nTty.c_oflag &= ~OPOST; + nTty.c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN); + nTty.c_cflag &= ~(CSIZE | PARENB); + nTty.c_cflag |= CS8 | CLOCAL | CSTOPB; + nTty.c_cc[VTIME] = 0; + nTty.c_cc[VMIN] = 1; + cfsetispeed (&nTty, B1200); + cfsetospeed (&nTty, B1200); + if (tcsetattr(priv->fd, TCSANOW, &nTty) < 0) + FATAL1("msLinuxInit: tcsetattr failed (%s)\n", strerror(errno)); + write(priv->fd, "*V", 2); /* 2 button 3 byte protocol */ + return priv->fd; +} + +/** Turn \a pDev off (i.e., stop taking input from \a pDev). */ +void msLinuxOff(DevicePtr pDev) +{ + GETPRIV; + + tcsetattr(priv->fd, TCSANOW, &priv->tty); + close(priv->fd); + priv->fd = -1; +} + +static void msLinuxGetMap(DevicePtr pDev, unsigned char *map, int *nButtons) +{ + int i; + + if (nButtons) *nButtons = 3; + if (map) for (i = 0; i <= *nButtons; i++) map[i] = i; +} + +/** Currently unused hook called prior to an VT switch. */ +void msLinuxVTPreSwitch(pointer p) +{ +} + +/** Currently unused hook called after returning from a VT switch. */ +void msLinuxVTPostSwitch(pointer p) +{ +} + +/** Create a private structure for use within this file. */ +pointer msLinuxCreatePrivate(DeviceIntPtr pMouse) +{ + myPrivate *priv = xalloc(sizeof(*priv)); + memset(priv, 0, sizeof(*priv)); + priv->fd = -1; + priv->pMouse = pMouse; + return priv; +} + +/** Destroy a private structure. */ +void msLinuxDestroyPrivate(pointer priv) +{ + if (priv) xfree(priv); +} + +/** Fill the \a info structure with information needed to initialize \a + * pDev. */ +void msLinuxGetInfo(DevicePtr pDev, DMXLocalInitInfoPtr info) +{ + info->buttonClass = 1; + msLinuxGetMap(pDev, info->map, &info->numButtons); + info->valuatorClass = 1; + info->numRelAxes = 2; + info->minval[0] = 0; + info->maxval[0] = 0; + info->res[0] = 1; + info->minres[0] = 0; + info->maxres[0] = 1; + info->ptrFeedbackClass = 1; +} diff --git a/xorg-server/hw/dmx/input/lnx-ms.h b/xorg-server/hw/dmx/input/lnx-ms.h new file mode 100644 index 000000000..9042fc293 --- /dev/null +++ b/xorg-server/hw/dmx/input/lnx-ms.h @@ -0,0 +1,55 @@ +/* + * Copyright 2001 Red Hat Inc., Durham, North Carolina. + * + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation on the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NON-INFRINGEMENT. IN NO EVENT SHALL RED HAT AND/OR THEIR SUPPLIERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* + * Authors: + * Rickard E. (Rik) Faith <faith@redhat.com> + * + */ + +/** \file + * Interface to Linux MS mouse driver. \see lnx-ms.c */ + +#ifndef _LNX_MS_H_ +#define _LNX_MS_H_ + +extern pointer msLinuxCreatePrivate(DeviceIntPtr pMouse); +extern void msLinuxDestroyPrivate(pointer priv); +extern void msLinuxRead(DevicePtr pDev, + dmxMotionProcPtr motion, + dmxEnqueueProcPtr enqueue, + dmxCheckSpecialProcPtr checkspecial, + DMXBlockType block); +extern void msLinuxInit(DevicePtr pDev); +extern void msLinuxGetInfo(DevicePtr pDev, DMXLocalInitInfoPtr info); +extern int msLinuxOn(DevicePtr pDev); +extern void msLinuxOff(DevicePtr pDev); +extern void msLinuxCtrl(DevicePtr pDev, PtrCtrl *ctrl); +extern void msLinuxVTPreSwitch(pointer p); +extern void msLinuxVTPostSwitch(pointer p); + +#endif diff --git a/xorg-server/hw/dmx/input/lnx-ps2.c b/xorg-server/hw/dmx/input/lnx-ps2.c new file mode 100644 index 000000000..8b906df5f --- /dev/null +++ b/xorg-server/hw/dmx/input/lnx-ps2.c @@ -0,0 +1,290 @@ +/* Portions of this file were derived from the following files: + * + ********************************************************************** + * + * Xserver/hw/kdrive/linux/ps2.c + * + * Copyright (c) 1999 by Keith Packard + * + * Permission to use, copy, modify, distribute, and sell this software and its + * documentation for any purpose is hereby granted without fee, provided that + * the above copyright notice appear in all copies and that both that + * copyright notice and this permission notice appear in supporting + * documentation, and that the name of Keith Packard not be used in + * advertising or publicity pertaining to distribution of the software without + * specific, written prior permission. Keith Packard makes no + * representations about the suitability of this software for any purpose. It + * is provided "as is" without express or implied warranty. + * + * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO + * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, + * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + * + */ + +/* + * Copyright 2001,2003 Red Hat Inc., Durham, North Carolina. + * + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation on the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NON-INFRINGEMENT. IN NO EVENT SHALL RED HAT AND/OR THEIR SUPPLIERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* + * Authors: + * Rickard E. (Rik) Faith <faith@redhat.com> + * + */ + +/** \file + * + * This code implements a low-level device driver for a serial MS mouse. + * The code is derived from code by Keith Packard (see the source code + * for complete references). */ + +#ifdef HAVE_DMX_CONFIG_H +#include <dmx-config.h> +#endif + +#include "inputstr.h" +#include <X11/Xos.h> +#include <errno.h> +#include <termios.h> + +/*****************************************************************************/ +/* Define some macros to make it easier to move this file to another + * part of the Xserver tree. All calls to the dmx* layer are #defined + * here for the .c file. The .h file will also have to be edited. */ +#include "dmxinputinit.h" +#include "lnx-ps2.h" + +#define GETPRIV myPrivate *priv \ + = ((DMXLocalInputInfoPtr)(pDev->devicePrivate))->private + +#define LOG0(f) dmxLog(dmxDebug,f) +#define LOG1(f,a) dmxLog(dmxDebug,f,a) +#define LOG2(f,a,b) dmxLog(dmxDebug,f,a,b) +#define LOG3(f,a,b,c) dmxLog(dmxDebug,f,a,b,c) +#define FATAL0(f) dmxLog(dmxFatal,f) +#define FATAL1(f,a) dmxLog(dmxFatal,f,a) +#define FATAL2(f,a,b) dmxLog(dmxFatal,f,a,b) +#define MOTIONPROC dmxMotionProcPtr +#define ENQUEUEPROC dmxEnqueueProcPtr +#define CHECKPROC dmxCheckSpecialProcPtr +#define BLOCK DMXBlockType + +/* End of interface definitions. */ +/*****************************************************************************/ + +/* Private area for PS/2 devices. */ +typedef struct _myPrivate { + DeviceIntPtr pMouse; + int fd; + enum { + button1 = 0x0001, + button2 = 0x0002, + button3 = 0x0004, + button4 = 0x0008, + button5 = 0x0010 + } buttons; +} myPrivate; + +static int ps2LinuxReadBytes(int fd, unsigned char *buf, int len, int min) +{ + int n, tot; + fd_set set; + struct timeval tv; + + tot = 0; + while (len) { + n = read(fd, buf, len); + if (n > 0) { + tot += n; + buf += n; + len -= n; + } + if (tot % min == 0) break; + FD_ZERO(&set); + FD_SET(fd, &set); + tv.tv_sec = 0; + tv.tv_usec = 100 * 1000; + n = select(fd + 1, &set, 0, 0, &tv); + if (n <= 0) break; + } + return tot; +} + +static void ps2LinuxButton(DevicePtr pDev, ENQUEUEPROC enqueue, + int buttons, BLOCK block) +{ + GETPRIV; + +#define PRESS(b) \ + do { \ + enqueue(pDev, ButtonPress, 0, 0, NULL, block); \ + } while (0) + +#define RELEASE(b) \ + do { \ + enqueue(pDev, ButtonRelease, 0, 0, NULL, block); \ + } while (0) + + if ((buttons & button1) && !(priv->buttons & button1)) PRESS(1); + if (!(buttons & button1) && (priv->buttons & button1)) RELEASE(1); + + if ((buttons & button2) && !(priv->buttons & button2)) PRESS(2); + if (!(buttons & button2) && (priv->buttons & button2)) RELEASE(2); + + if ((buttons & button3) && !(priv->buttons & button3)) PRESS(3); + if (!(buttons & button3) && (priv->buttons & button3)) RELEASE(3); + + if ((buttons & button4) && !(priv->buttons & button4)) PRESS(4); + if (!(buttons & button4) && (priv->buttons & button4)) RELEASE(4); + + if ((buttons & button5) && !(priv->buttons & button5)) PRESS(5); + if (!(buttons & button5) && (priv->buttons & button5)) RELEASE(5); + + priv->buttons = buttons; +} + +/** Read an event from the \a pDev device. If the event is a motion + * event, enqueue it with the \a motion function. Otherwise, check for + * special keys with the \a checkspecial function and enqueue the event + * with the \a enqueue function. The \a block type is passed to the + * functions so that they may block SIGIO handling as appropriate to the + * caller of this function. */ +void ps2LinuxRead(DevicePtr pDev, MOTIONPROC motion, + ENQUEUEPROC enqueue, CHECKPROC checkspecial, BLOCK block) +{ + GETPRIV; + unsigned char buf[3 * 200]; /* RATS: Use ok */ + unsigned char *b; + int n; + int dx, dy, v[2]; + + while ((n = ps2LinuxReadBytes(priv->fd, buf, sizeof(buf), 3)) > 0) { + b = buf; + while (n >= 3) { + dx = b[1] - ((b[0] & 0x10) ? 256 : 0); + dy = -b[2] + ((b[0] & 0x20) ? 256 : 0); + v[0] = -dx; + v[1] = -dy; + + motion(pDev, v, 0, 2, 1, block); + ps2LinuxButton(pDev, enqueue, (((b[0] & 4) ? button2 : 0) + | ((b[0] & 2) ? button3 : 0) + | ((b[0] & 1) ? button1 : 0)), + block); + n -= 3; + b += 3; + } + } +} + +/** Initialize \a pDev. */ +void ps2LinuxInit(DevicePtr pDev) +{ + GETPRIV; + const char *names[] = { "/dev/mouse", "/dev/psaux", NULL }; + int i; + + if (priv->fd >=0) return; + + for (i = 0; names[i]; i++) { + if ((priv->fd = open(names[i], O_RDWR | O_NONBLOCK, 0)) >= 0) break; + } + if (priv->fd < 0) + FATAL1("ps2LinuxInit: Cannot open mouse port (%s)\n", + strerror(errno)); +} + +/** Turn \a pDev on (i.e., take input from \a pDev). */ +int ps2LinuxOn(DevicePtr pDev) +{ + GETPRIV; + + if (priv->fd < 0) ps2LinuxInit(pDev); + return priv->fd; +} + +/** Turn \a pDev off (i.e., stop taking input from \a pDev). */ +void ps2LinuxOff(DevicePtr pDev) +{ + GETPRIV; + + close(priv->fd); + priv->fd = -1; +} + +static void ps2LinuxGetMap(DevicePtr pDev, unsigned char *map, int *nButtons) +{ + int i; + + if (nButtons) *nButtons = 3; + if (map) for (i = 0; i <= *nButtons; i++) map[i] = i; +} + +/** Currently unused hook called prior to an VT switch. */ +void ps2LinuxVTPreSwitch(pointer p) +{ +} + +/** Currently unused hook called after returning from a VT switch. */ +void ps2LinuxVTPostSwitch(pointer p) +{ +} + +/** Create a private structure for use within this file. */ +pointer ps2LinuxCreatePrivate(DeviceIntPtr pMouse) +{ + myPrivate *priv = xalloc(sizeof(*priv)); + memset(priv, 0, sizeof(*priv)); + priv->fd = -1; + priv->pMouse = pMouse; + return priv; +} + +/** Destroy a private structure. */ +void ps2LinuxDestroyPrivate(pointer priv) +{ + if (priv) xfree(priv); +} + +/** Fill the \a info structure with information needed to initialize \a + * pDev. */ +void ps2LinuxGetInfo(DevicePtr pDev, DMXLocalInitInfoPtr info) +{ + info->buttonClass = 1; + ps2LinuxGetMap(pDev, info->map, &info->numButtons); + info->valuatorClass = 1; + info->numRelAxes = 2; + info->minval[0] = 0; + info->maxval[0] = 0; + info->res[0] = 1; + info->minres[0] = 0; + info->maxres[0] = 1; + info->ptrFeedbackClass = 1; +} diff --git a/xorg-server/hw/dmx/input/lnx-ps2.h b/xorg-server/hw/dmx/input/lnx-ps2.h new file mode 100644 index 000000000..5772e03d0 --- /dev/null +++ b/xorg-server/hw/dmx/input/lnx-ps2.h @@ -0,0 +1,55 @@ +/* + * Copyright 2001 Red Hat Inc., Durham, North Carolina. + * + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation on the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NON-INFRINGEMENT. IN NO EVENT SHALL RED HAT AND/OR THEIR SUPPLIERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* + * Authors: + * Rickard E. (Rik) Faith <faith@redhat.com> + * + */ + +/** \file + * Interface to Linux PS/2 mouse driver. \see lnx-ps2.c */ + +#ifndef _LNX_PS2_H_ +#define _LNX_PS2_H_ + +extern pointer ps2LinuxCreatePrivate(DeviceIntPtr pMouse); +extern void ps2LinuxDestroyPrivate(pointer priv); +extern void ps2LinuxRead(DevicePtr pDev, + dmxMotionProcPtr motion, + dmxEnqueueProcPtr enqueue, + dmxCheckSpecialProcPtr checkspecial, + DMXBlockType block); +extern void ps2LinuxInit(DevicePtr pDev); +extern void ps2LinuxGetInfo(DevicePtr pDev, DMXLocalInitInfoPtr info); +extern int ps2LinuxOn(DevicePtr pDev); +extern void ps2LinuxOff(DevicePtr pDev); +extern void ps2LinuxCtrl(DevicePtr pDev, PtrCtrl *ctrl); +extern void ps2LinuxVTPreSwitch(pointer p); +extern void ps2LinuxVTPostSwitch(pointer p); + +#endif diff --git a/xorg-server/hw/dmx/input/usb-common.c b/xorg-server/hw/dmx/input/usb-common.c new file mode 100644 index 000000000..70695d0f1 --- /dev/null +++ b/xorg-server/hw/dmx/input/usb-common.c @@ -0,0 +1,382 @@ +/* + * Copyright 2002-2003 Red Hat Inc., Durham, North Carolina. + * + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation on the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NON-INFRINGEMENT. IN NO EVENT SHALL RED HAT AND/OR THEIR SUPPLIERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* + * Authors: + * Rickard E. (Rik) Faith <faith@redhat.com> + * + */ + +/** \file + * + * Routines that are common between #usb-keyboard.c, #usb-mouse.c, and + * #usb-other.c */ + +#ifdef HAVE_DMX_CONFIG_H +#include <dmx-config.h> +#endif + +#include "usb-private.h" + +#define USB_COMMON_DEBUG 1 + +/*****************************************************************************/ +/* Define some macros to make it easier to move this file to another + * part of the Xserver tree. All calls to the dmx* layer are #defined + * here for the .c file. The .h file will also have to be edited. */ +#include "usb-mouse.h" + +#define GETPRIV myPrivate *priv \ + = ((DMXLocalInputInfoPtr)(pDev->devicePrivate))->private + +#define GETNAME ((DMXLocalInputInfoPtr)(pDevice->public.devicePrivate)) \ + ->name + +#define LOG0(f) dmxLog(dmxDebug,f) +#define LOG1(f,a) dmxLog(dmxDebug,f,a) +#define LOG2(f,a,b) dmxLog(dmxDebug,f,a,b) +#define LOG3(f,a,b,c) dmxLog(dmxDebug,f,a,b,c) +#define LOG1INPUT(p,f,a) dmxLogInput(p->dmxInput,f,a) +#define LOG3INPUT(p,f,a,b,c) dmxLogInput(p->dmxInput,f,a,b,c) +#define LOG5INPUT(p,f,a,b,c,d,e) dmxLogInput(p->dmxInput,f,a,b,c,d,e) +#define FATAL0(f) dmxLog(dmxFatal,f) +#define FATAL1(f,a) dmxLog(dmxFatal,f,a) +#define FATAL2(f,a,b) dmxLog(dmxFatal,f,a,b) +#define MOTIONPROC dmxMotionProcPtr +#define ENQUEUEPROC dmxEnqueueProcPtr +#define CHECKPROC dmxCheckSpecialProcPtr +#define BLOCK DMXBlockType + +/* End of interface definitions. */ +/*****************************************************************************/ + + +/** Read an event from the \a pDev device. If the event is a motion + * event, enqueue it with the \a motion function. Otherwise, enqueue + * the event with the \a enqueue function. The \a block type is passed + * to the functions so that they may block SIGIO handling as appropriate + * to the caller of this function. + * + * Since USB devices return EV_KEY events for buttons and keys, \a + * minButton is used to decide if a Button or Key event should be + * queued.*/ +void usbRead(DevicePtr pDev, + MOTIONPROC motion, + ENQUEUEPROC enqueue, + int minButton, + BLOCK block) +{ + GETPRIV; + struct input_event raw; + int v[DMX_MAX_AXES]; + int axis; + +#define PRESS(b) \ + do { \ + enqueue(pDev, ButtonPress, 0, 0, NULL, block); \ + } while (0) + +#define RELEASE(b) \ + do { \ + enqueue(pDev, ButtonRelease, 0, 0, NULL, block); \ + } while (0) + + while (read(priv->fd, &raw, sizeof(raw)) > 0) { +#if USB_COMMON_DEBUG > 1 + LOG3("USB: type = %d, code = 0x%02x, value = %d\n", + raw.type, raw.code, raw.value); +#endif + switch (raw.type) { + case EV_KEY: + /* raw.value = 1 for first, 2 for repeat */ + if (raw.code > minButton) { + if (raw.value) PRESS((raw.code & 0x0f) + 1); + else RELEASE((raw.code & 0x0f) + 1); + } else { + enqueue(pDev, raw.value ? KeyPress : KeyRelease, + 0, 0, NULL, block); + } + break; + case EV_REL: + switch (raw.code) { + case REL_X: + v[0] = -raw.value; + v[1] = 0; + motion(pDev, v, 0, 2, DMX_RELATIVE, block); + break; + case REL_Y: + v[0] = 0; + v[1] = -raw.value; + motion(pDev, v, 0, 2, DMX_RELATIVE, block); + break; + case REL_WHEEL: + if ((int)raw.value > 0) { + PRESS(4); + RELEASE(4); + } else if ((int)raw.value < 0) { + PRESS(5); + RELEASE(5); + } + break; + default: + memset(v, 0, sizeof(v)); + axis = priv->relmap[raw.code]; + v[axis] = raw.value; + motion(pDev, v, axis, 1, DMX_RELATIVE, block); + } + break; + case EV_ABS: + memset(v, 0, sizeof(v)); + axis = priv->absmap[raw.code]; + v[axis] = raw.value; + motion(pDev, v, axis, 1, DMX_ABSOLUTE, block); + break; + } + } +} + +#define test_bit(bit) (priv->mask[(bit)/8] & (1 << ((bit)%8))) +#define test_bits(bit) (bits[(bit)/8] & (1 << ((bit)%8))) + +static void usbPrint(myPrivate *priv, + const char *filename, const char *devname, int fd) +{ + int j, k; + DeviceIntPtr pDevice = priv->pDevice; + unsigned char bits[KEY_MAX/8 + 1]; /* RATS: Use ok assuming that + * KEY_MAX is greater than + * REL_MAX, ABS_MAX, SND_MAX, and + * LED_MAX. */ + + LOG3INPUT(priv, "%s (%s) using %s\n", pDevice->name, GETNAME, filename); + LOG1INPUT(priv, " %s\n", devname); + for (j = 0; j < EV_MAX; j++) { + if (test_bit(j)) { + const char *type = "unknown"; + char extra[256]; /* FIXME: may cause buffer overflow */ + extra[0] = '\0'; + switch(j) { + case EV_KEY: type = "keys/buttons"; break; + case EV_REL: type = "relative"; + memset(bits, 0, sizeof(bits)); + ioctl(priv->fd, EVIOCGBIT(EV_REL, sizeof(bits)), bits); + for (k = 0; k < REL_MAX; k++) { + if (test_bits(k)) switch (k) { + case REL_X: strcat(extra, " X"); break; + case REL_Y: strcat(extra, " Y"); break; + case REL_Z: strcat(extra, " Z"); break; + case REL_HWHEEL: strcat(extra, " HWheel"); break; + case REL_DIAL: strcat(extra, " Dial"); break; + case REL_WHEEL: strcat(extra, " Wheel"); break; + case REL_MISC: strcat(extra, " Misc"); break; + } + } + break; + case EV_ABS: type = "absolute"; + memset(bits, 0, sizeof(bits)); + ioctl(priv->fd, EVIOCGBIT(EV_ABS, sizeof(bits)), bits); + for (k = 0; k < ABS_MAX; k++) { + if (test_bits(k)) switch (k) { + case ABS_X: strcat(extra," X"); break; + case ABS_Y: strcat(extra," Y"); break; + case ABS_Z: strcat(extra," Z"); break; + case ABS_RX: strcat(extra," RX"); break; + case ABS_RY: strcat(extra," RY"); break; + case ABS_RZ: strcat(extra," RZ"); break; + case ABS_THROTTLE: strcat(extra," Throttle");break; + case ABS_RUDDER: strcat(extra," Rudder"); break; + case ABS_WHEEL: strcat(extra," Wheel"); break; + case ABS_GAS: strcat(extra," Gas"); break; + case ABS_BRAKE: strcat(extra," Break"); break; + case ABS_HAT0X: strcat(extra," Hat0X"); break; + case ABS_HAT0Y: strcat(extra," Hat0Y"); break; + case ABS_HAT1X: strcat(extra," Hat1X"); break; + case ABS_HAT1Y: strcat(extra," Hat1Y"); break; + case ABS_HAT2X: strcat(extra," Hat2X"); break; + case ABS_HAT2Y: strcat(extra," Hat2Y"); break; + case ABS_HAT3X: strcat(extra," Hat3X"); break; + case ABS_HAT3Y: strcat(extra," Hat3Y"); break; + case ABS_PRESSURE: strcat(extra," Pressure");break; + case ABS_DISTANCE: strcat(extra," Distance");break; + case ABS_TILT_X: strcat(extra," TiltX"); break; + case ABS_TILT_Y: strcat(extra," TiltY"); break; + case ABS_MISC: strcat(extra," Misc"); break; + } + } + break; + case EV_MSC: type = "reserved"; break; + case EV_LED: type = "leds"; + memset(bits, 0, sizeof(bits)); + ioctl(priv->fd, EVIOCGBIT(EV_LED, sizeof(bits)), bits); + for (k = 0; k < LED_MAX; k++) { + if (test_bits(k)) switch (k) { + case LED_NUML: strcat(extra," NumLock"); break; + case LED_CAPSL: strcat(extra," CapsLock"); break; + case LED_SCROLLL: strcat(extra," ScrlLock"); break; + case LED_COMPOSE: strcat(extra," Compose"); break; + case LED_KANA: strcat(extra," Kana"); break; + case LED_SLEEP: strcat(extra," Sleep"); break; + case LED_SUSPEND: strcat(extra," Suspend"); break; + case LED_MUTE: strcat(extra," Mute"); break; + case LED_MISC: strcat(extra," Misc"); break; + } + } + break; + case EV_SND: type = "sound"; + memset(bits, 0, sizeof(bits)); + ioctl(priv->fd, EVIOCGBIT(EV_SND, sizeof(bits)), bits); + for (k = 0; k < SND_MAX; k++) { + if (test_bits(k)) switch (k) { + case SND_CLICK: strcat(extra," Click"); break; + case SND_BELL: strcat(extra," Bell"); break; + } + } + break; + case EV_REP: type = "repeat"; break; + case EV_FF: type = "feedback"; break; + } + LOG5INPUT(priv, " Feature 0x%02x = %s%s%s%s\n", j, type, + extra[0] ? " [" : "", + extra[0] ? extra+1 : "", + extra[0] ? "]" : ""); + } + } +} + +/** Initialized \a pDev as a \a usbMouse, \a usbKeyboard, or \a usbOther +device. */ +void usbInit(DevicePtr pDev, usbType type) +{ + GETPRIV; + char name[64]; /* RATS: Only used in XmuSnprintf */ + int i, j, k; + char buf[256] = { 0, }; /* RATS: Use ok */ + int version; + unsigned char bits[KEY_MAX/8 + 1]; /* RATS: Use ok assuming that + * KEY_MAX is greater than + * REL_MAX, ABS_MAX, SND_MAX, and + * LED_MAX. */ + + if (priv->fd >=0) return; + + for (i = 0; i < 32; i++) { + XmuSnprintf(name, sizeof(name), "/dev/input/event%d", i); + if ((priv->fd = open(name, O_RDWR | O_NONBLOCK, 0)) >= 0) { + ioctl(priv->fd, EVIOCGVERSION, &version); + ioctl(priv->fd, EVIOCGNAME(sizeof(buf)), buf); + memset(priv->mask, 0, sizeof(priv->mask)); + ioctl(priv->fd, EVIOCGBIT(0, sizeof(priv->mask)), priv->mask); + + for (j = 0; j < EV_MAX; j++) { + if (test_bit(j)) { + switch(j) { + case EV_REL: + memset(bits, 0, sizeof(bits)); + ioctl(priv->fd, EVIOCGBIT(EV_REL, sizeof(bits)), bits); + for (k = 0; k < REL_MAX; k++) { + if (test_bits(k)) { + if (k == REL_X) priv->relmap[k] = 0; + else if (k == REL_Y) priv->relmap[k] = 1; + else priv->relmap[k] = 2 + priv->numAbs; + ++priv->numRel; + } + } + break; + case EV_ABS: + memset(bits, 0, sizeof(bits)); + ioctl(priv->fd, EVIOCGBIT(EV_ABS, sizeof(bits)), bits); + for (k = 0; k < ABS_MAX; k++) { + if (test_bits(k)) { + priv->absmap[k] = priv->numAbs; + ++priv->numAbs; + } + } + break; + case EV_LED: + memset(bits, 0, sizeof(bits)); + ioctl(priv->fd, EVIOCGBIT(EV_LED, sizeof(bits)), bits); + for (k = 0; k < LED_MAX; k++) { + if (test_bits(k)) ++priv->numLeds; + } + break; + } + } + } + switch (type) { + case usbMouse: + if (test_bit(EV_REL) && test_bit(EV_KEY)) + goto found; + break; + case usbKeyboard: + if (test_bit(EV_KEY) && test_bit(EV_LED) && !test_bit(EV_ABS)) + goto found; + break; + case usbOther: + if (!(test_bit(EV_REL) && test_bit(EV_KEY)) + && !(test_bit(EV_KEY) && test_bit(EV_LED) + && !test_bit(EV_ABS))) + goto found; + break; + } + close(priv->fd); + priv->fd = -1; + } + } + if (priv->fd < 0) + FATAL1("usbInit: Cannot open /dev/input/event* port (%s)\n" + " If you have not done so, you may need to:\n" + " rmmod mousedev; rmmod keybdev\n" + " modprobe evdev\n", + strerror(errno)); + found: + usbPrint(priv, name, buf, priv->fd); +} + +/** Turn \a pDev off (i.e., stop taking input from \a pDev). */ +void usbOff(DevicePtr pDev) +{ + GETPRIV; + + if (priv->fd >= 0) close(priv->fd); + priv->fd = -1; +} + +/** Create a private structure for use within this file. */ +pointer usbCreatePrivate(DeviceIntPtr pDevice) +{ + myPrivate *priv = xalloc(sizeof(*priv)); + memset(priv, 0, sizeof(*priv)); + priv->fd = -1; + priv->pDevice = pDevice; + return priv; +} + +/** Destroy a private structure. */ +void usbDestroyPrivate(pointer priv) +{ + if (priv) xfree(priv); +} diff --git a/xorg-server/hw/dmx/input/usb-common.h b/xorg-server/hw/dmx/input/usb-common.h new file mode 100644 index 000000000..5ebfd1e78 --- /dev/null +++ b/xorg-server/hw/dmx/input/usb-common.h @@ -0,0 +1,55 @@ +/* + * Copyright 2002 Red Hat Inc., Durham, North Carolina. + * + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation on the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NON-INFRINGEMENT. IN NO EVENT SHALL RED HAT AND/OR THEIR SUPPLIERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* + * Authors: + * Rickard E. (Rik) Faith <faith@redhat.com> + * + */ + +/** \file + * Interface to common USB support. \see usb-common.c \see usb-mouse.c + * \see usb-keyboard.c \see usb-other.c */ + +#ifndef _USB_COMMON_H_ +#define _USB_COMMON_H_ +typedef enum { + usbMouse, + usbKeyboard, + usbOther +} usbType; + +extern pointer usbCreatePrivate(DeviceIntPtr pDevice); +extern void usbDestroyPrivate(pointer priv); +extern void usbRead(DevicePtr pDev, + dmxMotionProcPtr motion, + dmxEnqueueProcPtr enqueue, + int minButton, + DMXBlockType block); +extern void usbInit(DevicePtr pDev, usbType type); +extern void usbOff(DevicePtr pDev); +#endif diff --git a/xorg-server/hw/dmx/input/usb-keyboard.c b/xorg-server/hw/dmx/input/usb-keyboard.c new file mode 100644 index 000000000..efec2705b --- /dev/null +++ b/xorg-server/hw/dmx/input/usb-keyboard.c @@ -0,0 +1,441 @@ +/* Portions of this file were derived from the following files: + * + ********************************************************************** + * + * xfree86/common/xf86KbdLnx.c + * + * Linux version of keymapping setup. The kernel (since 0.99.14) has support + * for fully remapping the keyboard, but there are some differences between + * the Linux map and the SVR4 map (esp. in the extended keycodes). We also + * remove the restriction on what keycodes can be remapped. + * Orest Zborowski. + * + * Copyright 1990,91 by Thomas Roell, Dinkelscherben, Germany. + * + * Permission to use, copy, modify, distribute, and sell this software and its + * documentation for any purpose is hereby granted without fee, provided that + * the above copyright notice appear in all copies and that both that + * copyright notice and this permission notice appear in supporting + * documentation, and that the name of Thomas Roell not be used in + * advertising or publicity pertaining to distribution of the software without + * specific, written prior permission. Thomas Roell makes no representations + * about the suitability of this software for any purpose. It is provided + * "as is" without express or implied warranty. + * + * THOMAS ROELL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO + * EVENT SHALL THOMAS ROELL BE LIABLE FOR ANY SPECIAL, INDIRECT OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, + * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + * + */ + +/* + * Copyright 2001,2002 Red Hat Inc., Durham, North Carolina. + * + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation on the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NON-INFRINGEMENT. IN NO EVENT SHALL RED HAT AND/OR THEIR SUPPLIERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* + * Authors: + * Rickard E. (Rik) Faith <faith@redhat.com> + * + */ + +/** \file + * + * This code implements a low-level device driver for a USB keyboard + * under Linux. The keymap description is derived from code by Thomas + * Roell, Orest Zborowski. */ + +#ifdef HAVE_DMX_CONFIG_H +#include <dmx-config.h> +#endif + +#include "atKeynames.h" +#include "usb-private.h" + +#define USB_KEYBOARD_DEBUG 0 + +/*****************************************************************************/ +/* Define some macros to make it easier to move this file to another + * part of the Xserver tree. All calls to the dmx* layer are #defined + * here for the .c file. The .h file will also have to be edited. */ +#include "usb-keyboard.h" + +#define GETPRIV myPrivate *priv \ + = ((DMXLocalInputInfoPtr)(pDev->devicePrivate))->private + +#define LOG0(f) dmxLog(dmxDebug,f) +#define LOG1(f,a) dmxLog(dmxDebug,f,a) +#define LOG2(f,a,b) dmxLog(dmxDebug,f,a,b) +#define LOG3(f,a,b,c) dmxLog(dmxDebug,f,a,b,c) +#define FATAL0(f) dmxLog(dmxFatal,f) +#define FATAL1(f,a) dmxLog(dmxFatal,f,a) +#define FATAL2(f,a,b) dmxLog(dmxFatal,f,a,b) +#define MOTIONPROC dmxMotionProcPtr +#define ENQUEUEPROC dmxEnqueueProcPtr +#define CHECKPROC dmxCheckSpecialProcPtr +#define BLOCK DMXBlockType + +/* End of interface definitions. */ +/*****************************************************************************/ + +#define GLYPHS_PER_KEY 4 +#define NUM_KEYCODES 248 +#define MIN_KEYCODE 8 +#define MAX_KEYCODE (NUM_KEYCODES + MIN_KEYCODE - 1) + +static KeySym map[NUM_KEYCODES * GLYPHS_PER_KEY] = { +/* Table modified from xc/programs/Xserver/hw/xfree86/common/xf86Keymap.h */ + /* 0x00 */ NoSymbol, NoSymbol, NoSymbol, NoSymbol, + /* 0x01 */ XK_Escape, NoSymbol, NoSymbol, NoSymbol, + /* 0x02 */ XK_1, XK_exclam, NoSymbol, NoSymbol, + /* 0x03 */ XK_2, XK_at, NoSymbol, NoSymbol, + /* 0x04 */ XK_3, XK_numbersign, NoSymbol, NoSymbol, + /* 0x05 */ XK_4, XK_dollar, NoSymbol, NoSymbol, + /* 0x06 */ XK_5, XK_percent, NoSymbol, NoSymbol, + /* 0x07 */ XK_6, XK_asciicircum, NoSymbol, NoSymbol, + /* 0x08 */ XK_7, XK_ampersand, NoSymbol, NoSymbol, + /* 0x09 */ XK_8, XK_asterisk, NoSymbol, NoSymbol, + /* 0x0a */ XK_9, XK_parenleft, NoSymbol, NoSymbol, + /* 0x0b */ XK_0, XK_parenright, NoSymbol, NoSymbol, + /* 0x0c */ XK_minus, XK_underscore, NoSymbol, NoSymbol, + /* 0x0d */ XK_equal, XK_plus, NoSymbol, NoSymbol, + /* 0x0e */ XK_BackSpace, NoSymbol, NoSymbol, NoSymbol, + /* 0x0f */ XK_Tab, XK_ISO_Left_Tab,NoSymbol, NoSymbol, + /* 0x10 */ XK_Q, NoSymbol, NoSymbol, NoSymbol, + /* 0x11 */ XK_W, NoSymbol, NoSymbol, NoSymbol, + /* 0x12 */ XK_E, NoSymbol, NoSymbol, NoSymbol, + /* 0x13 */ XK_R, NoSymbol, NoSymbol, NoSymbol, + /* 0x14 */ XK_T, NoSymbol, NoSymbol, NoSymbol, + /* 0x15 */ XK_Y, NoSymbol, NoSymbol, NoSymbol, + /* 0x16 */ XK_U, NoSymbol, NoSymbol, NoSymbol, + /* 0x17 */ XK_I, NoSymbol, NoSymbol, NoSymbol, + /* 0x18 */ XK_O, NoSymbol, NoSymbol, NoSymbol, + /* 0x19 */ XK_P, NoSymbol, NoSymbol, NoSymbol, + /* 0x1a */ XK_bracketleft, XK_braceleft, NoSymbol, NoSymbol, + /* 0x1b */ XK_bracketright,XK_braceright, NoSymbol, NoSymbol, + /* 0x1c */ XK_Return, NoSymbol, NoSymbol, NoSymbol, + /* 0x1d */ XK_Control_L, NoSymbol, NoSymbol, NoSymbol, + /* 0x1e */ XK_A, NoSymbol, NoSymbol, NoSymbol, + /* 0x1f */ XK_S, NoSymbol, NoSymbol, NoSymbol, + /* 0x20 */ XK_D, NoSymbol, NoSymbol, NoSymbol, + /* 0x21 */ XK_F, NoSymbol, NoSymbol, NoSymbol, + /* 0x22 */ XK_G, NoSymbol, NoSymbol, NoSymbol, + /* 0x23 */ XK_H, NoSymbol, NoSymbol, NoSymbol, + /* 0x24 */ XK_J, NoSymbol, NoSymbol, NoSymbol, + /* 0x25 */ XK_K, NoSymbol, NoSymbol, NoSymbol, + /* 0x26 */ XK_L, NoSymbol, NoSymbol, NoSymbol, + /* 0x27 */ XK_semicolon, XK_colon, NoSymbol, NoSymbol, + /* 0x28 */ XK_quoteright, XK_quotedbl, NoSymbol, NoSymbol, + /* 0x29 */ XK_quoteleft, XK_asciitilde, NoSymbol, NoSymbol, + /* 0x2a */ XK_Shift_L, NoSymbol, NoSymbol, NoSymbol, + /* 0x2b */ XK_backslash, XK_bar, NoSymbol, NoSymbol, + /* 0x2c */ XK_Z, NoSymbol, NoSymbol, NoSymbol, + /* 0x2d */ XK_X, NoSymbol, NoSymbol, NoSymbol, + /* 0x2e */ XK_C, NoSymbol, NoSymbol, NoSymbol, + /* 0x2f */ XK_V, NoSymbol, NoSymbol, NoSymbol, + /* 0x30 */ XK_B, NoSymbol, NoSymbol, NoSymbol, + /* 0x31 */ XK_N, NoSymbol, NoSymbol, NoSymbol, + /* 0x32 */ XK_M, NoSymbol, NoSymbol, NoSymbol, + /* 0x33 */ XK_comma, XK_less, NoSymbol, NoSymbol, + /* 0x34 */ XK_period, XK_greater, NoSymbol, NoSymbol, + /* 0x35 */ XK_slash, XK_question, NoSymbol, NoSymbol, + /* 0x36 */ XK_Shift_R, NoSymbol, NoSymbol, NoSymbol, + /* 0x37 */ XK_KP_Multiply, NoSymbol, NoSymbol, NoSymbol, + /* 0x38 */ XK_Alt_L, XK_Meta_L, NoSymbol, NoSymbol, + /* 0x39 */ XK_space, NoSymbol, NoSymbol, NoSymbol, + /* 0x3a */ XK_Caps_Lock, NoSymbol, NoSymbol, NoSymbol, + /* 0x3b */ XK_F1, NoSymbol, NoSymbol, NoSymbol, + /* 0x3c */ XK_F2, NoSymbol, NoSymbol, NoSymbol, + /* 0x3d */ XK_F3, NoSymbol, NoSymbol, NoSymbol, + /* 0x3e */ XK_F4, NoSymbol, NoSymbol, NoSymbol, + /* 0x3f */ XK_F5, NoSymbol, NoSymbol, NoSymbol, + /* 0x40 */ XK_F6, NoSymbol, NoSymbol, NoSymbol, + /* 0x41 */ XK_F7, NoSymbol, NoSymbol, NoSymbol, + /* 0x42 */ XK_F8, NoSymbol, NoSymbol, NoSymbol, + /* 0x43 */ XK_F9, NoSymbol, NoSymbol, NoSymbol, + /* 0x44 */ XK_F10, NoSymbol, NoSymbol, NoSymbol, + /* 0x45 */ XK_Num_Lock, NoSymbol, NoSymbol, NoSymbol, + /* 0x46 */ XK_Scroll_Lock, NoSymbol, NoSymbol, NoSymbol, + /* 0x47 */ XK_KP_Home, XK_KP_7, NoSymbol, NoSymbol, + /* 0x48 */ XK_KP_Up, XK_KP_8, NoSymbol, NoSymbol, + /* 0x49 */ XK_KP_Prior, XK_KP_9, NoSymbol, NoSymbol, + /* 0x4a */ XK_KP_Subtract, NoSymbol, NoSymbol, NoSymbol, + /* 0x4b */ XK_KP_Left, XK_KP_4, NoSymbol, NoSymbol, + /* 0x4c */ XK_KP_Begin, XK_KP_5, NoSymbol, NoSymbol, + /* 0x4d */ XK_KP_Right, XK_KP_6, NoSymbol, NoSymbol, + /* 0x4e */ XK_KP_Add, NoSymbol, NoSymbol, NoSymbol, + /* 0x4f */ XK_KP_End, XK_KP_1, NoSymbol, NoSymbol, + /* 0x50 */ XK_KP_Down, XK_KP_2, NoSymbol, NoSymbol, + /* 0x51 */ XK_KP_Next, XK_KP_3, NoSymbol, NoSymbol, + /* 0x52 */ XK_KP_Insert, XK_KP_0, NoSymbol, NoSymbol, + /* 0x53 */ XK_KP_Delete, XK_KP_Decimal, NoSymbol, NoSymbol, + /* 0x54 */ XK_Sys_Req, NoSymbol, NoSymbol, NoSymbol, + /* 0x55 */ NoSymbol, NoSymbol, NoSymbol, NoSymbol, + /* 0x56 */ XK_less, XK_greater, NoSymbol, NoSymbol, + /* 0x57 */ XK_F11, NoSymbol, NoSymbol, NoSymbol, + /* 0x58 */ XK_F12, NoSymbol, NoSymbol, NoSymbol, + /* 0x59 */ NoSymbol, NoSymbol, NoSymbol, NoSymbol, + /* 0x5a */ NoSymbol, NoSymbol, NoSymbol, NoSymbol, + /* 0x5b */ NoSymbol, NoSymbol, NoSymbol, NoSymbol, + /* 0x5c */ NoSymbol, NoSymbol, NoSymbol, NoSymbol, + /* 0x5d */ XK_Begin, NoSymbol, NoSymbol, NoSymbol, + /* 0x5e */ NoSymbol, NoSymbol, NoSymbol, NoSymbol, + /* 0x5f */ NoSymbol, NoSymbol, NoSymbol, NoSymbol, + /* 0x60 */ XK_KP_Enter, NoSymbol, NoSymbol, NoSymbol, + /* 0x61 */ XK_Control_R, NoSymbol, NoSymbol, NoSymbol, + /* 0x62 */ XK_KP_Divide, NoSymbol, NoSymbol, NoSymbol, + /* 0x63 */ XK_Print, NoSymbol, NoSymbol, NoSymbol, + /* 0x64 */ XK_Alt_R, XK_Meta_R, NoSymbol, NoSymbol, + /* 0x65 */ XK_Break, NoSymbol, NoSymbol, NoSymbol, + /* 0x66 */ XK_Home, NoSymbol, NoSymbol, NoSymbol, + /* 0x67 */ XK_Up, NoSymbol, NoSymbol, NoSymbol, + /* 0x68 */ XK_Prior, NoSymbol, NoSymbol, NoSymbol, + /* 0x69 */ XK_Left, NoSymbol, NoSymbol, NoSymbol, + /* 0x6a */ XK_Right, NoSymbol, NoSymbol, NoSymbol, + /* 0x6b */ XK_End, NoSymbol, NoSymbol, NoSymbol, + /* 0x6c */ XK_Down, NoSymbol, NoSymbol, NoSymbol, + /* 0x6d */ XK_Next, NoSymbol, NoSymbol, NoSymbol, + /* 0x6e */ XK_Insert, NoSymbol, NoSymbol, NoSymbol, + /* 0x6f */ XK_Delete, NoSymbol, NoSymbol, NoSymbol, + /* 0x70 */ NoSymbol, NoSymbol, NoSymbol, NoSymbol, + /* 0x71 */ NoSymbol, NoSymbol, NoSymbol, NoSymbol, + /* 0x72 */ NoSymbol, NoSymbol, NoSymbol, NoSymbol, + /* 0x73 */ NoSymbol, NoSymbol, NoSymbol, NoSymbol, + /* 0x74 */ NoSymbol, NoSymbol, NoSymbol, NoSymbol, + /* 0x75 */ NoSymbol, NoSymbol, NoSymbol, NoSymbol, + /* 0x76 */ NoSymbol, NoSymbol, NoSymbol, NoSymbol, + /* 0x77 */ XK_Pause, NoSymbol, NoSymbol, NoSymbol, + /* 0x78 */ NoSymbol, NoSymbol, NoSymbol, NoSymbol, + /* 0x79 */ NoSymbol, NoSymbol, NoSymbol, NoSymbol, + /* 0x7a */ XK_Menu, NoSymbol, NoSymbol, NoSymbol, + /* 0x7b */ NoSymbol, NoSymbol, NoSymbol, NoSymbol, + /* 0x7c */ NoSymbol, NoSymbol, NoSymbol, NoSymbol, + /* 0x7d */ XK_Super_L, NoSymbol, NoSymbol, NoSymbol, + /* 0x7e */ XK_Super_R, NoSymbol, NoSymbol, NoSymbol, + /* 0x7f */ XK_Menu, NoSymbol, NoSymbol, NoSymbol, +}; + +static int kbdUSBKeyDown(myPrivate *priv, int keyCode) +{ + CARD8 byte = keyCode >> 5; + CARD32 bit = 1 << (keyCode & 0x1f); + + if (byte > NUM_STATE_ENTRIES) return 0; + return priv->kbdState[byte] & bit; +} + +static void kbdUSBKeyState(myPrivate *priv, int type, int keyCode) +{ + CARD8 byte = keyCode >> 5; + CARD32 bit = 1 << (keyCode & 0x1f); + + if (byte > NUM_STATE_ENTRIES) return; + if (type == KeyPress) priv->kbdState[byte] |= bit; + else priv->kbdState[byte] &= ~bit; +} + +/** Set the LEDs. */ +void kbdUSBCtrl(DevicePtr pDev, KeybdCtrl *ctrl) +{ + GETPRIV; + struct timeval tv; + struct input_event event; + int i, led; + + gettimeofday(&tv, NULL); + for (i = 0; i < 5; i++) { + event.time.tv_sec = tv.tv_sec; + event.time.tv_usec = tv.tv_usec; + event.type = EV_LED; + if (i == 0) led = 1; /* LED_CAPSL == 0x01 */ + else if (i == 1) led = 0; /* LED_NUML == 0x00 */ + else led = i; + event.code = led; + event.value = !!(ctrl->leds & (1 << led)); + write(priv->fd, &event, sizeof(event)); + } +} + +/** Initialize \a pDev using #usbInit. */ +void kbdUSBInit(DevicePtr pDev) +{ + usbInit(pDev, usbKeyboard); +} + +static void kbdUSBConvert(DevicePtr pDev, + unsigned int scanCode, + int value, + ENQUEUEPROC enqueue, + CHECKPROC checkspecial, + BLOCK block) +{ + GETPRIV; + KeySymsPtr pKeySyms = &priv->pDevice->key->curKeySyms; + int type; + int keyCode; + KeySym keySym = NoSymbol; + int switching; + + /* Set up xEvent information */ + type = value ? KeyPress : KeyRelease; + keyCode = (scanCode & 0xff) + MIN_KEYCODE; + + /* Handle repeats */ + + if (keyCode >= pKeySyms->minKeyCode && keyCode <= pKeySyms->maxKeyCode) { + keySym = pKeySyms->map[(keyCode - pKeySyms->minKeyCode) + * pKeySyms->mapWidth]; +#if 0 + switch (keySym) { + case XK_Num_Lock: + case XK_Scroll_Lock: + case XK_Shift_Lock: + case XK_Caps_Lock: + /* Ignore releases and all but first press */ + if (kbdLinuxModIgnore(priv, &xE, keySym)) return; + if (kbdLinuxKeyDown(priv, &xE)) xE.u.u.type = KeyRelease; + else xE.u.u.type = KeyPress; + break; + } +#endif + + /* If key is already down, ignore or autorepeat */ + if (type == KeyPress && kbdUSBKeyDown(priv, keyCode)) { + KbdFeedbackClassRec *feed = priv->pDevice->kbdfeed; + + /* No auto-repeat? */ + if ((feed && !feed->ctrl.autoRepeat) + || priv->pDevice->key->modifierMap[keyCode] + || (feed + && !(feed->ctrl.autoRepeats[keyCode >> 3] + & (1 << (keyCode & 7))))) return; /* Ignore */ + + /* Do auto-repeat */ + enqueue(pDev, KeyRelease, keyCode, keySym, NULL, block); + type = KeyPress; + } + + /* If key is already up, ignore */ + if (type == KeyRelease && !kbdUSBKeyDown(priv, keyCode)) return; + } + + switching = 0; + if (checkspecial && type == KeyPress) + switching = checkspecial(pDev, keySym); + if (!switching) { + if (enqueue) + enqueue(pDev, type, keyCode, keySym, NULL, block); + kbdUSBKeyState(priv, type, keyCode); /* Update our state bitmap */ + } +} + +/** Read an event from the \a pDev device. If the event is a motion + * event, enqueue it with the \a motion function. Otherwise, check for + * special keys with the \a checkspecial function and enqueue the event + * with the \a enqueue function. The \a block type is passed to the + * functions so that they may block SIGIO handling as appropriate to the + * caller of this function. */ +void kbdUSBRead(DevicePtr pDev, + MOTIONPROC motion, + ENQUEUEPROC enqueue, + CHECKPROC checkspecial, + BLOCK block) +{ + GETPRIV; + struct input_event raw; + + while (read(priv->fd, &raw, sizeof(raw)) > 0) { +#if USB_KEYBOARD_DEBUG + LOG3("KBD: type = %d, code = 0x%02x, value = %d\n", + raw.type, raw.code, raw.value); +#endif + kbdUSBConvert(pDev, raw.code, raw.value, enqueue, checkspecial, block); + } +} + +/** Turn \a pDev on (i.e., take input from \a pDev). */ +int kbdUSBOn(DevicePtr pDev) +{ + GETPRIV; + + if (priv->fd < 0) kbdUSBInit(pDev); + return priv->fd; +} + +static void kbdUSBGetMap(DevicePtr pDev, KeySymsPtr pKeySyms, CARD8 *pModMap) +{ + KeySym *k, *mapCopy; + int i; + + mapCopy = xalloc(sizeof(map)); + memcpy(mapCopy, map, sizeof(map)); + + /* compute the modifier map */ + for (i = 0; i < MAP_LENGTH; i++) + pModMap[i] = NoSymbol; /* make sure it is restored */ + + for (k = mapCopy, i = MIN_KEYCODE; + i < NUM_KEYCODES + MIN_KEYCODE; + i++, k += 4) { + switch(*k) { + case XK_Shift_L: + case XK_Shift_R: pModMap[i] = ShiftMask; break; + case XK_Control_L: + case XK_Control_R: pModMap[i] = ControlMask; break; + case XK_Caps_Lock: pModMap[i] = LockMask; break; + case XK_Alt_L: + case XK_Alt_R: pModMap[i] = AltMask; break; + case XK_Num_Lock: pModMap[i] = NumLockMask; break; + case XK_Scroll_Lock: pModMap[i] = ScrollLockMask; break; + case XK_Kana_Lock: + case XK_Kana_Shift: pModMap[i] = KanaMask; break; + case XK_Mode_switch: pModMap[i] = AltLangMask; break; + } + } + + pKeySyms->map = mapCopy; /* Must be XFree'able */ + pKeySyms->mapWidth = GLYPHS_PER_KEY; + pKeySyms->minKeyCode = MIN_KEYCODE; + pKeySyms->maxKeyCode = MAX_KEYCODE; +} + +/** Fill the \a info structure with information needed to initialize \a + * pDev. */ +void kbdUSBGetInfo(DevicePtr pDev, DMXLocalInitInfoPtr info) +{ + info->keyboard = 1; + info->keyClass = 1; + kbdUSBGetMap(pDev, &info->keySyms, info->modMap); + info->focusClass = 1; + info->kbdFeedbackClass = 1; +#ifdef XKB + info->names.keycodes = xstrdup("powerpcps2"); + info->force = 1; +#endif +} diff --git a/xorg-server/hw/dmx/input/usb-keyboard.h b/xorg-server/hw/dmx/input/usb-keyboard.h new file mode 100644 index 000000000..1f9614eef --- /dev/null +++ b/xorg-server/hw/dmx/input/usb-keyboard.h @@ -0,0 +1,48 @@ +/* + * Copyright 2002 Red Hat Inc., Durham, North Carolina. + * + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation on the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NON-INFRINGEMENT. IN NO EVENT SHALL RED HAT AND/OR THEIR SUPPLIERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* + * Authors: + * Rickard E. (Rik) Faith <faith@redhat.com> + * + */ + +/** \file + * Interface to USB keyboard driver. \see usb-keyboard.c \see usb-common.c */ + +#ifndef _USB_KEYBOARD_H_ +#define _USB_KEYBOARD_H_ +extern void kbdUSBInit(DevicePtr pDev); +extern void kbdUSBGetInfo(DevicePtr pDev, DMXLocalInitInfoPtr info); +extern int kbdUSBOn(DevicePtr pDev); +extern void kbdUSBRead(DevicePtr pDev, + dmxMotionProcPtr motion, + dmxEnqueueProcPtr enqueue, + dmxCheckSpecialProcPtr checkspecial, + DMXBlockType block); +extern void kbdUSBCtrl(DevicePtr pDev, KeybdCtrl *ctrl); +#endif diff --git a/xorg-server/hw/dmx/input/usb-mouse.c b/xorg-server/hw/dmx/input/usb-mouse.c new file mode 100644 index 000000000..efa9d00ec --- /dev/null +++ b/xorg-server/hw/dmx/input/usb-mouse.c @@ -0,0 +1,126 @@ +/* + * Copyright 2002 Red Hat Inc., Durham, North Carolina. + * + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation on the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NON-INFRINGEMENT. IN NO EVENT SHALL RED HAT AND/OR THEIR SUPPLIERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* + * Authors: + * Rickard E. (Rik) Faith <faith@redhat.com> + * + */ + +/** \file + * + * This code implements a low-level device driver for a USB mouse. */ + +#ifdef HAVE_DMX_CONFIG_H +#include <dmx-config.h> +#endif + +#include "usb-private.h" + +/*****************************************************************************/ +/* Define some macros to make it easier to move this file to another + * part of the Xserver tree. All calls to the dmx* layer are #defined + * here for the .c file. The .h file will also have to be edited. */ +#include "usb-mouse.h" + +#define GETPRIV myPrivate *priv \ + = ((DMXLocalInputInfoPtr)(pDev->devicePrivate))->private + +#define LOG0(f) dmxLog(dmxDebug,f) +#define LOG1(f,a) dmxLog(dmxDebug,f,a) +#define LOG2(f,a,b) dmxLog(dmxDebug,f,a,b) +#define LOG3(f,a,b,c) dmxLog(dmxDebug,f,a,b,c) +#define FATAL0(f) dmxLog(dmxFatal,f) +#define FATAL1(f,a) dmxLog(dmxFatal,f,a) +#define FATAL2(f,a,b) dmxLog(dmxFatal,f,a,b) +#define MOTIONPROC dmxMotionProcPtr +#define ENQUEUEPROC dmxEnqueueProcPtr +#define CHECKPROC dmxCheckSpecialProcPtr +#define BLOCK DMXBlockType + +/* End of interface definitions. */ +/*****************************************************************************/ + +/** Read the USB device using #usbRead. */ +void mouUSBRead(DevicePtr pDev, + MOTIONPROC motion, + ENQUEUEPROC enqueue, + CHECKPROC checkspecial, + BLOCK block) +{ + usbRead(pDev, motion, enqueue, BTN_MISC, block); +} + +/** Initialize \a pDev using #usbInit. */ +void mouUSBInit(DevicePtr pDev) +{ + usbInit(pDev, usbMouse); +} + +/** Turn \a pDev on (i.e., take input from \a pDev). */ +int mouUSBOn(DevicePtr pDev) +{ + GETPRIV; + + if (priv->fd < 0) mouUSBInit(pDev); + return priv->fd; +} + +static void mouUSBGetMap(DevicePtr pDev, unsigned char *map, int *nButtons) +{ + int i; + + if (nButtons) *nButtons = 5; + if (map) for (i = 0; i <= *nButtons; i++) map[i] = i; +} + +/** Fill the \a info structure with information needed to initialize \a + * pDev. */ +void mouUSBGetInfo(DevicePtr pDev, DMXLocalInitInfoPtr info) +{ + static KeySym keyboard_mapping = NoSymbol; + + info->buttonClass = 1; + mouUSBGetMap(pDev, info->map, &info->numButtons); + info->valuatorClass = 1; + info->numRelAxes = 2; + info->minval[0] = 0; + info->maxval[0] = 0; + info->res[0] = 1; + info->minres[0] = 0; + info->maxres[0] = 1; + info->ptrFeedbackClass = 1; + + /* Some USB mice devices return key + * events from their pair'd + * keyboard... */ + info->keyClass = 1; + info->keySyms.minKeyCode = 8; + info->keySyms.maxKeyCode = 8; + info->keySyms.mapWidth = 1; + info->keySyms.map = &keyboard_mapping; +} diff --git a/xorg-server/hw/dmx/input/usb-mouse.h b/xorg-server/hw/dmx/input/usb-mouse.h new file mode 100644 index 000000000..918bf6481 --- /dev/null +++ b/xorg-server/hw/dmx/input/usb-mouse.h @@ -0,0 +1,48 @@ +/* + * Copyright 2002 Red Hat Inc., Durham, North Carolina. + * + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation on the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NON-INFRINGEMENT. IN NO EVENT SHALL RED HAT AND/OR THEIR SUPPLIERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* + * Authors: + * Rickard E. (Rik) Faith <faith@redhat.com> + * + */ + +/** \file + * Interface to USB mouse driver. \see usb-mouse.c \see usb-common.c */ + +#ifndef _USB_MOU_H_ +#define _USB_MOU_H_ +extern void mouUSBRead(DevicePtr pDev, + dmxMotionProcPtr motion, + dmxEnqueueProcPtr enqueue, + dmxCheckSpecialProcPtr checkspecial, + DMXBlockType block); +extern void mouUSBInit(DevicePtr pDev); +extern void mouUSBGetInfo(DevicePtr pDev, DMXLocalInitInfoPtr info); +extern int mouUSBOn(DevicePtr pDev); +extern void mouUSBCtrl(DevicePtr pDev, PtrCtrl *ctrl); +#endif diff --git a/xorg-server/hw/dmx/input/usb-other.c b/xorg-server/hw/dmx/input/usb-other.c new file mode 100644 index 000000000..d1074b8e1 --- /dev/null +++ b/xorg-server/hw/dmx/input/usb-other.c @@ -0,0 +1,161 @@ +/* + * Copyright 2002 Red Hat Inc., Durham, North Carolina. + * + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation on the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NON-INFRINGEMENT. IN NO EVENT SHALL RED HAT AND/OR THEIR SUPPLIERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* + * Authors: + * Rickard E. (Rik) Faith <faith@redhat.com> + * + */ + +/** \file + * + * This code implements a low-level device driver for a non-keyboard, + * non-mouse USB device (e.g., a joystick or gamepad). */ + +#ifdef HAVE_DMX_CONFIG_H +#include <dmx-config.h> +#endif + +#include "usb-private.h" + +/*****************************************************************************/ +/* Define some macros to make it easier to move this file to another + * part of the Xserver tree. All calls to the dmx* layer are #defined + * here for the .c file. The .h file will also have to be edited. */ +#include "dmxinputinit.h" +#include "usb-other.h" + +#define GETPRIV myPrivate *priv \ + = ((DMXLocalInputInfoPtr)(pDev->devicePrivate))->private + +#define LOG0(f) dmxLog(dmxDebug,f) +#define LOG1(f,a) dmxLog(dmxDebug,f,a) +#define LOG2(f,a,b) dmxLog(dmxDebug,f,a,b) +#define LOG3(f,a,b,c) dmxLog(dmxDebug,f,a,b,c) +#define FATAL0(f) dmxLog(dmxFatal,f) +#define FATAL1(f,a) dmxLog(dmxFatal,f,a) +#define FATAL2(f,a,b) dmxLog(dmxFatal,f,a,b) +#define MOTIONPROC dmxMotionProcPtr +#define ENQUEUEPROC dmxEnqueueProcPtr +#define CHECKPROC dmxCheckSpecialProcPtr +#define BLOCK DMXBlockType + +/* End of interface definitions. */ +/*****************************************************************************/ + +/** Read the USB device using #usbRead. */ +void othUSBRead(DevicePtr pDev, + MOTIONPROC motion, + ENQUEUEPROC enqueue, + CHECKPROC checkspecial, + BLOCK block) +{ + usbRead(pDev, motion, enqueue, 0xffff, block); +} + +/** Initialize \a pDev using #usbInit. */ +void othUSBInit(DevicePtr pDev) +{ + usbInit(pDev, usbOther); +} + +/** Turn \a pDev on (i.e., take input from \a pDev). */ +int othUSBOn(DevicePtr pDev) +{ + GETPRIV; + + if (priv->fd < 0) othUSBInit(pDev); + return priv->fd; +} + +/** Fill the \a info structure with information needed to initialize \a + * pDev. */ +void othUSBGetInfo(DevicePtr pDev, DMXLocalInitInfoPtr info) +{ + GETPRIV; + int i, j; + static KeySym keyboard_mapping = NoSymbol; + int absolute[5]; + +#define test_bit(bit) (priv->mask[(bit)/8] & (1 << ((bit)%8))) + + /* Some USB mice devices return key + * events from their pair'd + * keyboard... */ + info->keyClass = 1; + info->keySyms.minKeyCode = 8; + info->keySyms.maxKeyCode = 8; + info->keySyms.mapWidth = 1; + info->keySyms.map = &keyboard_mapping; + + for (i = 0; i < EV_MAX; i++) { + if (test_bit(i)) { + switch (i) { + case EV_KEY: + /* See above */ + break; + case EV_REL: + info->valuatorClass = 1; + if (info->numRelAxes + info->numAbsAxes > DMX_MAX_AXES - 1) { + info->numRelAxes = DMX_MAX_AXES - info->numAbsAxes - 1; + dmxLog(dmxWarning, "Can only use %d relative axes\n", + info->numRelAxes); + } else + info->numRelAxes = priv->numRel; + info->minval[0] = 0; + info->maxval[0] = 0; + info->res[0] = 1; + info->minres[0] = 0; + info->maxres[0] = 1; + break; + case EV_ABS: + info->valuatorClass = 1; + if (info->numRelAxes + info->numAbsAxes > DMX_MAX_AXES - 1) { + info->numAbsAxes = DMX_MAX_AXES - info->numRelAxes - 1; + dmxLog(dmxWarning, "Can only use %d absolute axes\n", + info->numAbsAxes); + } else + info->numAbsAxes = priv->numAbs; + for (j = 0; j < info->numAbsAxes; j++) { + ioctl(priv->fd, EVIOCGABS(j), absolute); + info->minval[1+j] = absolute[1]; + info->maxval[1+j] = absolute[2]; + info->res[1+j] = absolute[3]; + info->minres[1+j] = absolute[3]; + info->maxres[1+j] = absolute[3]; + } + break; + case EV_LED: + info->ledFeedbackClass = 0; /* Not supported at this time */ + break; + case EV_SND: + info->belFeedbackClass = 0; /* Not supported at this time */ + break; + } + } + } +} diff --git a/xorg-server/hw/dmx/input/usb-other.h b/xorg-server/hw/dmx/input/usb-other.h new file mode 100644 index 000000000..b69e65933 --- /dev/null +++ b/xorg-server/hw/dmx/input/usb-other.h @@ -0,0 +1,48 @@ +/* + * Copyright 2002 Red Hat Inc., Durham, North Carolina. + * + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation on the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NON-INFRINGEMENT. IN NO EVENT SHALL RED HAT AND/OR THEIR SUPPLIERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* + * Authors: + * Rickard E. (Rik) Faith <faith@redhat.com> + * + */ + +/** \file + * Interface to USB generic driver. \see usb-other.c \see usb-common.c */ + +#ifndef _USB_OTHER_H_ +#define _USB_OTHER_H_ +extern void othUSBRead(DevicePtr pDev, + dmxMotionProcPtr motion, + dmxEnqueueProcPtr enqueue, + dmxCheckSpecialProcPtr checkspecial, + DMXBlockType block); +extern void othUSBInit(DevicePtr pDev); +extern void othUSBGetInfo(DevicePtr pDev, DMXLocalInitInfoPtr info); +extern int othUSBOn(DevicePtr pDev); +extern void othUSBCtrl(DevicePtr pDev, PtrCtrl *ctrl); +#endif diff --git a/xorg-server/hw/dmx/input/usb-private.h b/xorg-server/hw/dmx/input/usb-private.h new file mode 100644 index 000000000..c70668ce5 --- /dev/null +++ b/xorg-server/hw/dmx/input/usb-private.h @@ -0,0 +1,117 @@ +/* + * Copyright 2002 Red Hat Inc., Durham, North Carolina. + * + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation on the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NON-INFRINGEMENT. IN NO EVENT SHALL RED HAT AND/OR THEIR SUPPLIERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* + * Authors: + * Rickard E. (Rik) Faith <faith@redhat.com> + * + */ + +/** \file + * Private header file for USB support. This file provides + * Linux-specific include files and the definition of the private + * structure. \see usb-common.c \see usb-keyboard.c \see usb-mouse.c + * \see usb-other.c */ + +#ifndef _USB_PRIVATE_H_ +#define _USB_PRIVATE_H_ + +#include "dmxinputinit.h" +#include "inputstr.h" +#include <X11/Xos.h> +#include <errno.h> +#include <linux/input.h> +#include "usb-common.h" + + /* Support for force feedback was + * introduced in Linxu 2.4.10 */ +#ifndef EV_MSC +#define EV_MSC 0x04 +#endif +#ifndef EV_FF +#define EV_FF 0x15 +#endif +#ifndef LED_SLEEP +#define LED_SLEEP 0x05 +#endif +#ifndef LED_SUSPEND +#define LED_SUSPEND 0x06 +#endif +#ifndef LED_MUTE +#define LED_MUTE 0x07 +#endif +#ifndef LED_MISC +#define LED_MISC 0x08 +#endif +#ifndef BTN_DEAD +#define BTN_DEAD 0x12f +#endif +#ifndef BTN_THUMBL +#define BTN_THUMBL 0x13d +#endif +#ifndef BTN_THUMBR +#define BTN_THUMBR 0x13e +#endif +#ifndef MSC_SERIAL +#define MSC_SERIAL 0x00 +#endif +#ifndef MSC_MAX +#define MSC_MAX 0x07 +#endif + + /* Support for older kernels. */ +#ifndef ABS_WHEEL +#define ABS_WHEEL 0x08 +#endif +#ifndef ABS_GAS +#define ABS_GAS 0x09 +#endif +#ifndef ABS_BRAKE +#define ABS_BRAKE 0x0a +#endif + +#define NUM_STATE_ENTRIES (256/32) + +/* Private area for USB devices. */ +typedef struct _myPrivate { + DeviceIntPtr pDevice; /**< Device (mouse or other) */ + int fd; /**< File descriptor */ + unsigned char mask[EV_MAX/8 + 1]; /**< Mask */ + int numRel, numAbs, numLeds; /**< Counts */ + int relmap[DMX_MAX_AXES]; /**< Relative axis map */ + int absmap[DMX_MAX_AXES]; /**< Absolute axis map */ + + CARD32 kbdState[NUM_STATE_ENTRIES]; /**< Keyboard state */ + DeviceIntPtr pKeyboard; /** Keyboard device */ + + int pitch; /**< Bell pitch */ + unsigned long duration; /**< Bell duration */ + + /* FIXME: dmxInput is never initialized */ + DMXInputInfo *dmxInput; /**< For pretty-printing */ +} myPrivate; +#endif |