1307 lines
		
	
	
		
			45 KiB
		
	
	
	
		
			C
		
	
	
	
			
		
		
	
	
			1307 lines
		
	
	
		
			45 KiB
		
	
	
	
		
			C
		
	
	
	
| /*
 | |
|  * 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 "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"
 | |
| #include "xkbsrv.h"
 | |
| 
 | |
| #include <X11/extensions/XI.h>
 | |
| #include <X11/extensions/XIproto.h>
 | |
| #include "exevents.h"
 | |
| #include "extinit.h"
 | |
| 
 | |
| 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);
 | |
|         if (dmxLocal->pDevice->kbdfeed) {
 | |
|             XkbEventCauseRec cause;
 | |
|             XkbSetCauseUnknown(&cause);
 | |
|             /* Generate XKB events, as necessary */
 | |
|             XkbUpdateIndicators(dmxLocal->pDevice, XkbAllIndicatorsMask, False,
 | |
|                                 NULL, &cause);
 | |
|         }
 | |
|     }
 | |
| }
 | |
| 
 | |
| 
 | |
| /** 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);
 | |
|     }
 | |
| }
 | |
| 
 | |
| static void dmxKeyboardFreeNames(XkbComponentNamesPtr names)
 | |
| {
 | |
|     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);
 | |
| }
 | |
| 
 | |
| 
 | |
| static int dmxKeyboardOn(DeviceIntPtr pDevice, DMXLocalInitInfo *info)
 | |
| {
 | |
|     GETDMXINPUTFROMPDEVICE;
 | |
|     XkbRMLVOSet rmlvo;
 | |
| 
 | |
|     rmlvo.rules = dmxConfigGetXkbRules();
 | |
|     rmlvo.model = dmxConfigGetXkbModel();
 | |
|     rmlvo.layout = dmxConfigGetXkbLayout();
 | |
|     rmlvo.variant = dmxConfigGetXkbVariant();
 | |
|     rmlvo.options = dmxConfigGetXkbOptions();
 | |
| 
 | |
|     XkbSetRulesDflts(&rmlvo);
 | |
|     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() : "");
 | |
|     }
 | |
|     InitKeyboardDeviceStruct(pDevice, &rmlvo,
 | |
|                                 dmxKeyboardBellProc,
 | |
|                                 dmxKeyboardKbdCtrlProc);
 | |
| 
 | |
|     if (info->freenames) dmxKeyboardFreeNames(&info->names);
 | |
| 
 | |
|     return Success;
 | |
| }
 | |
| 
 | |
|     
 | |
| static int dmxDeviceOnOff(DeviceIntPtr pDevice, int what)
 | |
| {
 | |
|     GETDMXINPUTFROMPDEVICE;
 | |
|     int              fd;
 | |
|     DMXLocalInitInfo info;
 | |
|     int              i;
 | |
|     Atom             btn_labels[MAX_BUTTONS] = {0}; /* FIXME */
 | |
|     Atom             axis_labels[MAX_VALUATORS] = {0}; /* FIXME */
 | |
| 
 | |
|     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) {
 | |
|             XkbRMLVOSet rmlvo;
 | |
| 
 | |
|             rmlvo.rules = dmxConfigGetXkbRules();
 | |
|             rmlvo.model = dmxConfigGetXkbModel();
 | |
|             rmlvo.layout = dmxConfigGetXkbLayout();
 | |
|             rmlvo.variant = dmxConfigGetXkbVariant();
 | |
|             rmlvo.options = dmxConfigGetXkbOptions();
 | |
| 
 | |
|             InitKeyboardDeviceStruct(pDevice,
 | |
|                                      &rmlvo,
 | |
|                                      dmxBell, dmxKbdCtrl);
 | |
|         }
 | |
|         if (info.buttonClass) {
 | |
|             InitButtonClassDeviceStruct(pDevice, info.numButtons,
 | |
|                                         btn_labels, info.map);
 | |
|         }
 | |
|         if (info.valuatorClass) {
 | |
|             if (info.numRelAxes && dmxLocal->sendsCore) {
 | |
|                 InitValuatorClassDeviceStruct(pDevice, info.numRelAxes,
 | |
|                                               axis_labels,
 | |
|                                               GetMaximumEventsNum(),
 | |
|                                               Relative);
 | |
|                 for (i = 0; i < info.numRelAxes; i++)
 | |
|                     InitValuatorAxisStruct(pDevice, i, axis_labels[i],
 | |
|                                            info.minval[i], info.maxval[i],
 | |
|                                            info.res[i],
 | |
|                                            info.minres[i], info.maxres[i],
 | |
|                                            Relative);
 | |
|             } else if (info.numRelAxes) {
 | |
|                 InitValuatorClassDeviceStruct(pDevice, info.numRelAxes,
 | |
|                                               axis_labels,
 | |
|                                               dmxPointerGetMotionBufferSize(),
 | |
|                                               Relative);
 | |
|                 for (i = 0; i < info.numRelAxes; i++)
 | |
|                     InitValuatorAxisStruct(pDevice, i, axis_labels[i],
 | |
|                                            info.minval[i],
 | |
|                                            info.maxval[i], info.res[i],
 | |
|                                            info.minres[i], info.maxres[i],
 | |
|                                            Relative);
 | |
|             } else if (info.numAbsAxes) {
 | |
|                 InitValuatorClassDeviceStruct(pDevice, info.numAbsAxes,
 | |
|                                               axis_labels,
 | |
|                                               dmxPointerGetMotionBufferSize(),
 | |
|                                               Absolute);
 | |
|                 for (i = 0; i < info.numAbsAxes; i++)
 | |
|                     InitValuatorAxisStruct(pDevice, i,
 | |
|                                            axis_labels[i],
 | |
|                                            info.minval[i], info.maxval[i],
 | |
|                                            info.res[i], info.minres[i],
 | |
|                                            info.maxres[i], Absolute);
 | |
|             }
 | |
|         }
 | |
|         if (info.focusClass)       InitFocusClassDeviceStruct(pDevice);
 | |
|         if (info.proximityClass)   InitProximityClassDeviceStruct(pDevice);
 | |
|         if (info.ptrFeedbackClass)
 | |
|             InitPtrFeedbackClassDeviceStruct(pDevice, dmxChangePointerControl);
 | |
|         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;
 | |
|     }
 | |
|     if (info.xkb) XkbFreeKeyboard(info.xkb, 0, True);
 | |
|     return Success;
 | |
| }
 | |
| 
 | |
| static void dmxProcessInputEvents(DMXInputInfo *dmxInput)
 | |
| {
 | |
|     int i;
 | |
| 
 | |
|     mieqProcessInputEvents();
 | |
| #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 != screenInfo.screens[0]->root)
 | |
|         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 = malloc(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;
 | |
|     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";
 | |
|         }
 | |
|         if (dmxLocal->type == DMX_LOCAL_MOUSE && !dmxLocalCorePointer) {
 | |
|             dmxLocal->isCore     = 1;
 | |
|             dmxLocalCorePointer  = dmxLocal;
 | |
|             name                 = "pointer";
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     if (!name) {
 | |
|         name            = "extension";
 | |
|     }
 | |
| 
 | |
|     if (!name)
 | |
|         dmxLog(dmxFatal, "Cannot add device %s\n", dmxLocal->name);
 | |
| 
 | |
|     pDevice                       = AddInputDevice(serverClient, 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;
 | |
| 
 | |
|     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 = malloc(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 = realloc(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, _Xconst char *name, _Xconst char *reason)
 | |
| {
 | |
|     return 0;
 | |
| }
 | |
| 
 | |
| static void dmxInputScanForExtensions(DMXInputInfo *dmxInput, int doXI)
 | |
| {
 | |
|     XExtensionVersion    *ext;
 | |
|     XDeviceInfo          *devices;
 | |
|     Display              *display;
 | |
|     int                  num;
 | |
|     int                  i, j;
 | |
|     XextErrorHandler     handler;
 | |
| 
 | |
|     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;
 | |
|             case IsXExtensionPointer:  use = "XExtensionPointer"; break;
 | |
|             case IsXExtensionKeyboard: use = "XExtensionKeyboard"; 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
 | |
|                                             ? strdup(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;
 | |
| #if 0
 | |
|             case IsXExtensionDevice:
 | |
|             case IsXExtensionKeyboard:
 | |
|             case IsXExtensionPointer:
 | |
|                 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
 | |
|                                                 ? strdup(devices[i].name)
 | |
|                                                 : NULL);
 | |
|                     }
 | |
|                 }
 | |
|                 break;
 | |
| #endif
 | |
|             }
 | |
|         }
 | |
|         XFreeDeviceList(devices);
 | |
|     }
 | |
|     XCloseDisplay(display);
 | |
| }
 | |
| 
 | |
| /** Re-initialize all the devices described in \a dmxInput.  Called from
 | |
|     #dmxAdjustCursorBoundaries 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
 | |
|     #dmxAdjustCursorBoundaries 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];
 | |
|         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;
 | |
|         }
 | |
|     }
 | |
|     
 | |
|     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);
 | |
|     free(local->history);
 | |
|     free(local->valuators);
 | |
|     free(local->deviceName);
 | |
|     local->private    = NULL;
 | |
|     local->history    = NULL;
 | |
|     local->deviceName = NULL;
 | |
|     free(local);
 | |
| }
 | |
| 
 | |
| /** Free all of the memory associated with \a dmxInput */
 | |
| void dmxInputFree(DMXInputInfo *dmxInput)
 | |
| {
 | |
|     int i;
 | |
|     
 | |
|     if (!dmxInput) return;
 | |
| 
 | |
|     free(dmxInput->keycodes);
 | |
|     free(dmxInput->symbols);
 | |
|     free(dmxInput->geometry);
 | |
| 
 | |
|     for (i = 0; i < dmxInput->numDevs; i++) {
 | |
|         dmxInputFreeLocal(dmxInput->devs[i]);
 | |
|         dmxInput->devs[i] = NULL;
 | |
|     }
 | |
|     free(dmxInput->devs);
 | |
|     dmxInput->devs    = NULL;
 | |
|     dmxInput->numDevs = 0;
 | |
|     if (dmxInput->freename) free(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, TRUE);
 | |
|     }
 | |
|     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, TRUE);
 | |
|     }
 | |
|     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);
 | |
| }
 |