/* $XConsortium: XKBExtDev.c /main/3 1996/08/31 12:44:26 kaleb $ */
/************************************************************
Copyright (c) 1995 by Silicon Graphics Computer Systems, Inc.

Permission to use, copy, modify, and distribute this
software and its documentation for any purpose and without
fee is hereby granted, 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 Silicon Graphics not be 
used in advertising or publicity pertaining to distribution 
of the software without specific prior written permission.
Silicon Graphics makes no representation about the suitability 
of this software for any purpose. It is provided "as is"
without any express or implied warranty.

SILICON GRAPHICS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS 
SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY 
AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL SILICON
GRAPHICS 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.

********************************************************/

#include <stdio.h>
#define NEED_REPLIES
#define NEED_EVENTS
#define	NEED_MAP_READERS
#include "Xlibint.h"
#include <X11/extensions/XKBproto.h>
#include "XKBlibint.h"
#include <X11/extensions/XI.h>

/***====================================================================***/

extern	void
#if NeedFunctionPrototypes
XkbNoteDeviceChanges(	XkbDeviceChangesPtr		old,
			XkbExtensionDeviceNotifyEvent *	new,
			unsigned int			wanted)
#else
XkbNoteDeviceChanges(old,new,wanted)
    XkbDeviceChangesPtr			old;
    XkbExtensionDeviceNotifyEvent *	new;
    unsigned int			wanted;
#endif
{
    if ((!old)||(!new)||(!wanted)||((new->reason&wanted)==0))
	return;
    if ((wanted&new->reason)&XkbXI_ButtonActionsMask) {
	if (old->changed&XkbXI_ButtonActionsMask) {
	    int first,last,newLast;
	    if (new->first_btn<old->first_btn)
		 first= new->first_btn;
	    else first= old->first_btn;
	    last= old->first_btn+old->num_btns-1;
	    newLast= new->first_btn+new->num_btns-1;
	    if (newLast>last)
		last= newLast;
	    old->first_btn= first;
	    old->num_btns= (last-first)+1;
	}
	else {
	    old->changed|= XkbXI_ButtonActionsMask;
	    old->first_btn= new->first_btn;
	    old->num_btns= new->num_btns;
	}
    }
    if ((wanted&new->reason)&XkbXI_IndicatorsMask) {
	XkbDeviceLedChangesPtr this;
	if (old->changed&XkbXI_IndicatorsMask) {
	    XkbDeviceLedChangesPtr found;
	    found= NULL;
	    for (this= &old->leds;this&&(!found);this=this->next) {
		if ((this->led_class==new->led_class)&&
						(this->led_id==new->led_id)) {
		    found= this;
		}
	    }
	    if (!found) {
		found= _XkbTypedCalloc(1,XkbDeviceLedChangesRec);
		if (!found)
		    return;
		found->next= old->leds.next;
		found->led_class= new->led_class;
		found->led_id= new->led_id;
		old->leds.next= found;
	    }
	    if ((wanted&new->reason)&XkbXI_IndicatorNamesMask)
		found->defined= new->leds_defined;
	}
	else {
	    old->changed|= ((wanted&new->reason)&XkbXI_IndicatorsMask);
	    old->leds.led_class= new->led_class;
	    old->leds.led_id= new->led_id;
	    old->leds.defined= new->leds_defined;
	    if (old->leds.next) {
		XkbDeviceLedChangesPtr next;
		for (this=old->leds.next;this;this=next) {
		    next= this->next;
		    _XkbFree(this);
		}
		old->leds.next= NULL;
	    }
	}
    }
    return;
}

/***====================================================================***/

static Status
#if NeedFunctionPrototypes
_XkbReadDeviceLedInfo(	XkbReadBufferPtr	buf,
			unsigned 		present,
			XkbDeviceInfoPtr 	devi)
#else
_XkbReadDeviceLedInfo(buf,present,devi)
    XkbReadBufferPtr	buf;
    unsigned		present;
    XkbDeviceInfoPtr	devi;
#endif
{
register unsigned	i,bit;
XkbDeviceLedInfoPtr	devli;
xkbDeviceLedsWireDesc *	wireli;

    wireli= _XkbGetTypedRdBufPtr(buf,1,xkbDeviceLedsWireDesc);
    if (!wireli)
	return BadLength;
    devli= XkbAddDeviceLedInfo(devi,wireli->ledClass,wireli->ledID);
    if (!devli)
	return BadAlloc;
    devli->phys_indicators= 	wireli->physIndicators;

    if (present&XkbXI_IndicatorStateMask)
	devli->state= wireli->state;

    if (present&XkbXI_IndicatorNamesMask) {
	devli->names_present= 	wireli->namesPresent;
	if (devli->names_present) {
	    for (i=0,bit=1;i<XkbNumIndicators;i++,bit<<=1) {
		if (wireli->namesPresent&bit) {
		    if (!_XkbCopyFromReadBuffer(buf,(char *)&devli->names[i],4))
			return BadLength;
		}
	    }
	}
    }

    if (present&XkbXI_IndicatorMapsMask) {
	devli->maps_present= 	wireli->mapsPresent;
	if (devli->maps_present) {
	    XkbIndicatorMapPtr	 	im;
	    xkbIndicatorMapWireDesc *	wireim;
	    for (i=0,bit=1;i<XkbNumIndicators;i++,bit<<=1) {
		if (wireli->mapsPresent&bit) {
		    wireim= _XkbGetTypedRdBufPtr(buf,1,xkbIndicatorMapWireDesc);
		    if (!wireim)
			return BadAlloc;
		    im= &devli->maps[i];
		    im->flags= 		wireim->flags;
		    im->which_groups= 	wireim->whichGroups;
		    im->groups= 	wireim->groups;
		    im->which_mods= 	wireim->whichMods;
		    im->mods.mask= 	wireim->mods;
		    im->mods.real_mods= wireim->realMods;
		    im->mods.vmods= 	wireim->virtualMods;
		    im->ctrls= 		wireim->ctrls;
		}
	    }
	}
    }
    return Success;
}

static Status
#if NeedFunctionPrototypes
_XkbReadGetDeviceInfoReply(	Display *		dpy,
				xkbGetDeviceInfoReply *	rep,
				XkbDeviceInfoPtr	devi)
#else
_XkbReadGetDeviceInfoReply(dpy,rep,devi)
    Display *			dpy;
    xkbGetDeviceInfoReply *	rep;
    XkbDeviceInfoPtr		devi;
#endif
{
XkbReadBufferRec	buf;
XkbAction *		act;
int			tmp;

    if (!_XkbInitReadBuffer(dpy,&buf,(int)rep->length*4)) 
	return BadAlloc;

    if ((rep->totalBtns>0)&&(rep->totalBtns!=devi->num_btns)) {
	tmp= XkbResizeDeviceButtonActions(devi,rep->totalBtns);
	if (tmp!=Success)
	    return tmp;
    }
    if (rep->nBtnsWanted>0) {
	act= &devi->btn_acts[rep->firstBtnWanted];
	bzero((char *)act,(rep->nBtnsWanted*sizeof(XkbAction)));
    }
    if (devi->name!=NULL)
	_XkbFree(devi->name);
    if (!_XkbGetReadBufferCountedString(&buf,&devi->name))
	goto BAILOUT;
    if (rep->nBtnsRtrn>0) {
	int size;
	act= &devi->btn_acts[rep->firstBtnRtrn];
	size= rep->nBtnsRtrn*SIZEOF(xkbActionWireDesc);
	if (!_XkbCopyFromReadBuffer(&buf,(char *)act,size))
	    goto BAILOUT;
    }
    if (rep->nDeviceLedFBs>0) {
	register int 		i;
	for (i=0;i<rep->nDeviceLedFBs;i++) {
	    if ((tmp= _XkbReadDeviceLedInfo(&buf,rep->present,devi))!=Success)
		return tmp;
	}
    }
    tmp= _XkbFreeReadBuffer(&buf);
    if (tmp) 
	fprintf(stderr,"GetDeviceInfo! Bad length (%d extra bytes)\n",tmp);
    if (tmp || buf.error)
	return BadLength;
    return Success;
BAILOUT:
    _XkbFreeReadBuffer(&buf);
    return BadLength;
}

XkbDeviceInfoPtr
#if NeedFunctionPrototypes
XkbGetDeviceInfo(	Display *	dpy,
			unsigned 	which,
			unsigned 	deviceSpec,
			unsigned 	class,
			unsigned 	id)
#else
XkbGetDeviceInfo(dpy,which,deviceSpec,class,id)
    Display *	dpy;
    unsigned	which;
    unsigned	deviceSpec;
    unsigned	class;
    unsigned	id;
#endif
{
    register xkbGetDeviceInfoReq *	req;
    xkbGetDeviceInfoReply	 	rep;
    Status				status;
    XkbDeviceInfoPtr			devi;

    if ((dpy->flags & XlibDisplayNoXkb) ||
	(!dpy->xkb_info && !XkbUseExtension(dpy,NULL,NULL)))
	return NULL;
    LockDisplay(dpy);
    GetReq(kbGetDeviceInfo, req);
    req->reqType = dpy->xkb_info->codes->major_opcode;
    req->xkbReqType = X_kbGetDeviceInfo;
    req->deviceSpec = deviceSpec;
    req->wanted= which;
    req->allBtns= ((which&XkbXI_ButtonActionsMask)!=0);
    req->firstBtn= req->nBtns= 0;
    req->ledClass= class;
    req->ledID= id;
    if (!_XReply(dpy, (xReply *)&rep, 0, xFalse)) {
	UnlockDisplay(dpy);
	SyncHandle();
	return NULL;
    }
    devi= XkbAllocDeviceInfo(rep.deviceID,rep.totalBtns,rep.nDeviceLedFBs);
    if (devi) {
	devi->supported= rep.supported;
	devi->unsupported= rep.unsupported;
	devi->type= rep.devType;
	devi->has_own_state= rep.hasOwnState;
	devi->dflt_kbd_fb = rep.dfltKbdFB;
	devi->dflt_led_fb = rep.dfltLedFB;
	status= _XkbReadGetDeviceInfoReply(dpy,&rep,devi);
	if (status!=Success) {
	    XkbFreeDeviceInfo(devi,XkbXI_AllDeviceFeaturesMask,True);
	    devi= NULL;
	}
    }
    UnlockDisplay(dpy);
    SyncHandle();
    return devi;
}

Status
#if NeedFunctionPrototypes
XkbGetDeviceInfoChanges(	Display *		dpy,
				XkbDeviceInfoPtr 	devi,
				XkbDeviceChangesPtr	changes)
#else
XkbGetDeviceInfoChanges(dpy,devi,changes)
    Display *		dpy;
    XkbDeviceInfoPtr	devi;
    XkbDeviceChangesPtr	changes;
#endif
{
    register xkbGetDeviceInfoReq *	req;
    xkbGetDeviceInfoReply	 	rep;
    Status				status;

    if ((dpy->flags & XlibDisplayNoXkb) ||
	(!dpy->xkb_info && !XkbUseExtension(dpy,NULL,NULL)))
	return BadMatch;
    if ((changes->changed&XkbXI_AllDeviceFeaturesMask)==0)
	return Success;
    changes->changed&= ~XkbXI_AllDeviceFeaturesMask;
    status= Success;
    LockDisplay(dpy);
    while ((changes->changed)&&(status==Success)) {
	GetReq(kbGetDeviceInfo, req);
	req->reqType = dpy->xkb_info->codes->major_opcode;
	req->xkbReqType = X_kbGetDeviceInfo;
	req->deviceSpec = devi->device_spec;
	req->wanted= changes->changed;
	req->allBtns= False;
	if (changes->changed&XkbXI_ButtonActionsMask) {
	     req->firstBtn= changes->first_btn;
	     req->nBtns= 	changes->num_btns;
	     changes->changed&= ~XkbXI_ButtonActionsMask;
	}
	else req->firstBtn= req->nBtns= 0;
	if (changes->changed&XkbXI_IndicatorsMask) {
	    req->ledClass= changes->leds.led_class;
	    req->ledID= changes->leds.led_id;
	    if (changes->leds.next==NULL)
		changes->changed&= ~XkbXI_IndicatorsMask;
	    else {
		XkbDeviceLedChangesPtr next;
		next= changes->leds.next;
		changes->leds= *next;
		_XkbFree(next);
	    }
	}
	else {
	    req->ledClass= XkbDfltXIClass;
	    req->ledID= XkbDfltXIId;
	}
	if (!_XReply(dpy, (xReply *)&rep, 0, xFalse)) {
	    status= BadLength;
	    break;
	}
	devi->supported|= rep.supported;
	devi->unsupported|= rep.unsupported;
	devi->type= rep.devType;
	status= _XkbReadGetDeviceInfoReply(dpy,&rep,devi);
    }
    UnlockDisplay(dpy);
    SyncHandle();
    return status;
}

Status
#if NeedFunctionPrototypes
XkbGetDeviceButtonActions(	Display *		dpy,
				XkbDeviceInfoPtr	devi,
				Bool			all,
				unsigned int		first,
				unsigned int		num)
#else
XkbGetDeviceButtonActions(dpy,devi,all,first,num)
    Display *		dpy;
    XkbDeviceInfoPtr	devi;
    Bool		all;
    unsigned int	first;
    unsigned int	num;
#endif
{
    register xkbGetDeviceInfoReq *	req;
    xkbGetDeviceInfoReply	 	rep;
    Status				status;

    if ((dpy->flags & XlibDisplayNoXkb) || 
	(!dpy->xkb_info && !XkbUseExtension(dpy,NULL,NULL)))
	return BadMatch;
    if (!devi)
	return BadValue;
    LockDisplay(dpy);
    GetReq(kbGetDeviceInfo, req);
    req->reqType = dpy->xkb_info->codes->major_opcode;
    req->xkbReqType = X_kbGetDeviceInfo;
    req->deviceSpec = devi->device_spec;
    req->wanted= XkbXI_ButtonActionsMask;
    req->allBtns= all;
    req->firstBtn= first;
    req->nBtns= num;
    req->ledClass= XkbDfltXIClass;
    req->ledID= XkbDfltXIId;
    if (!_XReply(dpy, (xReply *)&rep, 0, xFalse)) {
	UnlockDisplay(dpy);
	SyncHandle();
	return BadLength;
    }
    devi->type= rep.devType;
    devi->supported= rep.supported;
    devi->unsupported= rep.unsupported;
    status= _XkbReadGetDeviceInfoReply(dpy,&rep,devi);
    UnlockDisplay(dpy);
    SyncHandle();
    return status;
}

Status
#if NeedFunctionPrototypes
XkbGetDeviceLedInfo(	Display *		dpy,
			XkbDeviceInfoPtr	devi,
			unsigned int		ledClass,
			unsigned int		ledId,
			unsigned int		which)
#else
XkbGetDeviceLedInfo(dpy,devi,ledClass,ledId,which)
    Display *		dpy;
    XkbDeviceInfoPtr	devi;
    unsigned int	ledClass;
    unsigned int	ledId;
    unsigned int	which;
#endif
{
    register xkbGetDeviceInfoReq *	req;
    xkbGetDeviceInfoReply	 	rep;
    Status				status;

    if ((dpy->flags & XlibDisplayNoXkb) || 
	(!dpy->xkb_info && !XkbUseExtension(dpy,NULL,NULL)))
	return BadMatch;
    if (((which&XkbXI_IndicatorsMask)==0)||(which&(~XkbXI_IndicatorsMask)))
	return BadMatch;
    if (!devi)
	return BadValue;
    LockDisplay(dpy);
    GetReq(kbGetDeviceInfo, req);
    req->reqType = dpy->xkb_info->codes->major_opcode;
    req->xkbReqType = X_kbGetDeviceInfo;
    req->deviceSpec = devi->device_spec;
    req->wanted= which;
    req->allBtns= False;
    req->firstBtn= req->nBtns= 0;
    req->ledClass= ledClass;
    req->ledID= ledId;
    if (!_XReply(dpy, (xReply *)&rep, 0, xFalse)) {
	UnlockDisplay(dpy);
	SyncHandle();
	return BadLength;
    } 
    devi->type= rep.devType;
    devi->supported= rep.supported;
    devi->unsupported= rep.unsupported;
    status= _XkbReadGetDeviceInfoReply(dpy,&rep,devi);
    UnlockDisplay(dpy);
    SyncHandle();
    return status;
}

/***====================================================================***/

typedef struct _LedInfoStuff {
	Bool			used;
	XkbDeviceLedInfoPtr	devli;
} LedInfoStuff;

typedef struct _SetLedStuff {
	unsigned		wanted;
	int			num_info;
	int			dflt_class;
	LedInfoStuff *		dflt_kbd_fb;
	LedInfoStuff *		dflt_led_fb;
	LedInfoStuff *		info;
} SetLedStuff;

static void
#if NeedFunctionPrototypes
_InitLedStuff(SetLedStuff *stuff,unsigned wanted,XkbDeviceInfoPtr devi)
#else
_InitLedStuff(stuff,wanted,devi)
    SetLedStuff	 *	stuff;
    unsigned		wanted;
    XkbDeviceInfoPtr	devi;
#endif
{
int				i;
register XkbDeviceLedInfoPtr	devli;

    bzero(stuff,sizeof(SetLedStuff));
    stuff->wanted= wanted;
    stuff->dflt_class=	XkbXINone;
    if ((devi->num_leds<1)||((wanted&XkbXI_IndicatorsMask)==0))
	return;
    stuff->info= _XkbTypedCalloc(devi->num_leds,LedInfoStuff);
    if (!stuff->info)
	return;
    stuff->num_info= devi->num_leds;
    for (devli=&devi->leds[0],i=0;i<devi->num_leds;i++,devli++) {
	stuff->info[i].devli= devli;
	if (devli->led_class==KbdFeedbackClass) {
	    stuff->dflt_class= KbdFeedbackClass;
	    if (stuff->dflt_kbd_fb==NULL)
		stuff->dflt_kbd_fb= &stuff->info[i];
	}
	else if (devli->led_class==LedFeedbackClass) {
	    if (stuff->dflt_class==XkbXINone)
		stuff->dflt_class= LedFeedbackClass;
	    if (stuff->dflt_led_fb==NULL)
		stuff->dflt_led_fb= &stuff->info[i];
	}
    }
    return;
}

static void
#if NeedFunctionPrototypes
_FreeLedStuff(SetLedStuff *stuff)
#else
_FreeLedStuff(stuff)
    SetLedStuff	*stuff;
#endif
{
    if ((stuff->num_info>0)&&(stuff->info!=NULL))
	_XkbFree(stuff->info);
    bzero(stuff,sizeof(SetLedStuff));
    return;
}

static int
#if NeedFunctionPrototypes
_XkbSizeLedInfo(unsigned changed,XkbDeviceLedInfoPtr devli)
#else
_XkbSizeLedInfo(changed,devli)
    unsigned		changed;
    XkbDeviceLedInfoPtr	devli;
#endif
{
register int i,size;
register unsigned bit,namesNeeded,mapsNeeded;

    size= SIZEOF(xkbDeviceLedsWireDesc);
    namesNeeded= mapsNeeded= 0;
    if (changed&XkbXI_IndicatorNamesMask)
	namesNeeded= devli->names_present;
    if (changed&XkbXI_IndicatorMapsMask)
	mapsNeeded= devli->maps_present;
    if ((namesNeeded)||(mapsNeeded)) {
	for (i=0,bit=1;i<XkbNumIndicators;i++,bit<<=1) {
	    if (namesNeeded&bit)
		size+= 4; /* atoms are 4 bytes on the wire */
	    if (mapsNeeded&bit)
		size+= SIZEOF(xkbIndicatorMapWireDesc);
	}
    }
    return size;
}

static Bool
#if NeedFunctionPrototypes
_SizeMatches(	SetLedStuff *		stuff,
		XkbDeviceLedChangesPtr 	changes,
		int *			sz_rtrn,
		int *			nleds_rtrn)
#else
_SizeMatches(stuff,changes,sz_rtrn,nleds_rtrn)
    SetLedStuff *		stuff;
    XkbDeviceLedChangesPtr	changes;
    int *			sz_rtrn;
    int *			nleds_rtrn;
#endif
{
int		i,nMatch,class,id;
LedInfoStuff *	linfo;
Bool		match;

    nMatch= 0;
    class= changes->led_class;
    id= changes->led_id;
    if (class==XkbDfltXIClass)
	class= stuff->dflt_class;
    for (i=0,linfo=&stuff->info[0];i<stuff->num_info;i++,linfo++) {
	XkbDeviceLedInfoPtr	devli;
	LedInfoStuff *		dflt;

	devli= linfo->devli;
	match= ((class==devli->led_class)||(class==XkbAllXIClasses));
	if (devli->led_class==KbdFeedbackClass)	dflt= stuff->dflt_kbd_fb;
	else					dflt= stuff->dflt_led_fb;
	match= match && (id==devli->led_id) || (id==XkbAllXIIds) ||
					((id==XkbDfltXIId)&&(linfo==dflt));
	if (match) {
	    if (!linfo->used) {
		*sz_rtrn+= _XkbSizeLedInfo(stuff->wanted,devli);
		*nleds_rtrn+= 1;
		linfo->used= True;
		if ((class!=XkbAllXIClasses)&&(id!=XkbAllXIIds))
		    return True;
	    }
	    nMatch++;
	    linfo->used= True;
	}
    }
    return (nMatch>0);
}

/***====================================================================***/


static Status
#if NeedFunctionPrototypes
_XkbSetDeviceInfoSize(	XkbDeviceInfoPtr	devi,
			XkbDeviceChangesPtr	changes,
			SetLedStuff *		stuff,
			int *			sz_rtrn,
			int *			num_leds_rtrn)
#else
_XkbSetDeviceInfoSize(devi,changes,stuff,sz_rtrn,num_leds_rtrn)
    XkbDeviceInfoPtr	devi;
    XkbDeviceChangesPtr	changes;
    SetLedStuff *	stuff;
    int *		sz_rtrn;
    int *		num_leds_rtrn;
#endif
{
    *sz_rtrn= 0;
    if ((changes->changed&XkbXI_ButtonActionsMask)&&(changes->num_btns>0)) {
	if (!XkbXI_LegalDevBtn(devi,(changes->first_btn+changes->num_btns-1)))
	    return BadMatch;
	*sz_rtrn+= changes->num_btns*SIZEOF(xkbActionWireDesc);
    }
    else {
	changes->changed&= ~XkbXI_ButtonActionsMask;
	changes->first_btn= changes->num_btns= 0;
    }
    if ((changes->changed&XkbXI_IndicatorsMask)&&
				XkbLegalXILedClass(changes->leds.led_class)) {
	XkbDeviceLedChangesPtr	leds;

	for (leds=&changes->leds;leds!=NULL;leds= leds->next) {
	    if (!_SizeMatches(stuff,leds,sz_rtrn,num_leds_rtrn))
		return BadMatch;
	}
    }
    else {
	changes->changed&= ~XkbXI_IndicatorsMask;
	*num_leds_rtrn= 0;
    }
    return Success;
}

static char *
#if NeedFunctionPrototypes
_XkbWriteLedInfo(char *wire,unsigned changed,XkbDeviceLedInfoPtr devli)
#else
_XkbWriteLedInfo(wire,changed,devli)
    char *			wire;
    unsigned			changed;
    XkbDeviceLedInfoPtr		devli;
#endif
{
register int 		i;
register unsigned 	bit,namesNeeded,mapsNeeded;
xkbDeviceLedsWireDesc *	lwire;

    namesNeeded= mapsNeeded= 0;
    if (changed&XkbXI_IndicatorNamesMask)
	namesNeeded= devli->names_present;
    if (changed&XkbXI_IndicatorMapsMask)
	mapsNeeded= devli->maps_present;

    lwire= (xkbDeviceLedsWireDesc *)wire;
    lwire->ledClass= devli->led_class;
    lwire->ledID= devli->led_id;
    lwire->namesPresent= namesNeeded;
    lwire->mapsPresent=  mapsNeeded;
    lwire->physIndicators= devli->phys_indicators;
    lwire->state= devli->state;
    wire= (char *)&lwire[1];
    if (namesNeeded) {
	CARD32 *awire;
	awire= (CARD32 *)wire;
	for (i=0,bit=1;i<XkbNumIndicators;i++,bit<<=1) {
	    if (namesNeeded&bit) {
		*awire= (CARD32)devli->names[i];
		awire++;
	    }
	}
	wire= (char *)awire;
    }
    if (mapsNeeded) {
	xkbIndicatorMapWireDesc *mwire;

	mwire= (xkbIndicatorMapWireDesc *)wire;
	for (i=0,bit=1;i<XkbNumIndicators;i++,bit<<=1) {
	    if (mapsNeeded&bit) {
		XkbIndicatorMapPtr	map;
		map= 			&devli->maps[i];
		mwire->flags= 		map->flags;
		mwire->whichGroups=	map->which_groups;
		mwire->groups=		map->groups;
		mwire->whichMods=	map->which_mods;
		mwire->mods=		map->mods.mask;
		mwire->realMods=	map->mods.real_mods;
		mwire->virtualMods=	map->mods.vmods;
		mwire->ctrls=		map->ctrls;
		mwire++;
	    }
	}
	wire= (char *)mwire;
    }
    return wire;
}


static int
#if NeedFunctionPrototypes
_XkbWriteSetDeviceInfo(	char *			wire,
			XkbDeviceChangesPtr	changes,
			SetLedStuff *		stuff,
			XkbDeviceInfoPtr	devi)
#else
_XkbWriteSetDeviceInfo(wire,changes,stuff,devi)
    char *			wire;
    XkbDeviceChangesPtr		changes;
    SetLedStuff *		stuff;
    XkbDeviceInfoPtr		devi;
#endif
{
char *start;

    start= wire;
    if (changes->changed&XkbXI_ButtonActionsMask) {
	int			size;
	size= changes->num_btns*SIZEOF(xkbActionWireDesc);
	memcpy(wire,(char *)&devi->btn_acts[changes->first_btn],size);
	wire+= size;
    }
    if (changes->changed&XkbXI_IndicatorsMask) {
	register int i;
	register LedInfoStuff *linfo;

	for (i=0,linfo=&stuff->info[0];i<stuff->num_info;i++,linfo++) {
	    if (linfo->used) {
		register char *new_wire;
		new_wire= _XkbWriteLedInfo(wire,stuff->wanted,linfo->devli);
		if (!new_wire)
		    return wire-start;
		wire= new_wire;
	    }
	}
    }
    return wire-start;
}

Bool
#if NeedFunctionPrototypes
XkbSetDeviceInfo(	Display *		dpy,
			unsigned 		which,
			XkbDeviceInfoPtr	devi)
#else
XkbSetDeviceInfo(dpy,which,devi)
    Display *		dpy;
    unsigned 		which;
    XkbDeviceInfoPtr	devi;
#endif
{
    register xkbSetDeviceInfoReq *req;
    Status		     	ok;
    int				size,nLeds;
    XkbInfoPtr 			xkbi;
    XkbDeviceChangesRec		changes;
    SetLedStuff			lstuff;

    if ((dpy->flags & XlibDisplayNoXkb) ||
	(!dpy->xkb_info && !XkbUseExtension(dpy,NULL,NULL)))
	return False;
    if ((!devi) || (which&(~XkbXI_AllDeviceFeaturesMask)) ||
	((which&XkbXI_ButtonActionsMask)&&(!XkbXI_DevHasBtnActs(devi)))||
	((which&XkbXI_IndicatorsMask)&&(!XkbXI_DevHasLeds(devi))))
	return False;

    bzero((char *)&changes,sizeof(XkbDeviceChangesRec));
    changes.changed= which;
    changes.first_btn=		0;
    changes.num_btns=		devi->num_btns;
    changes.leds.led_class=	XkbAllXIClasses;
    changes.leds.led_id=	XkbAllXIIds;
    changes.leds.defined=	0;
    size= nLeds= 		0;
    _InitLedStuff(&lstuff,changes.changed,devi);
    if (_XkbSetDeviceInfoSize(devi,&changes,&lstuff,&size,&nLeds)!=Success)
	return False;
    LockDisplay(dpy);
    xkbi = dpy->xkb_info;
    GetReq(kbSetDeviceInfo, req);
    req->length+=	size/4;
    req->reqType= 	xkbi->codes->major_opcode;
    req->xkbReqType= 	X_kbSetDeviceInfo;
    req->deviceSpec= 	devi->device_spec;
    req->firstBtn=	changes.first_btn;
    req->nBtns=		changes.num_btns;
    req->change=	changes.changed;
    req->nDeviceLedFBs=	nLeds;
    if (size>0) {
	char * 	wire;
	BufAlloc(char *,wire,size);
	ok= (wire!=NULL)&&
		(_XkbWriteSetDeviceInfo(wire,&changes,&lstuff,devi)==size);
    }
    UnlockDisplay(dpy);
    SyncHandle();
    _FreeLedStuff(&lstuff);
    /* 12/11/95 (ef) -- XXX!! should clear changes here */
    return ok;
}

Bool
#if NeedFunctionPrototypes
XkbChangeDeviceInfo(	Display *		dpy,
			XkbDeviceInfoPtr	devi,
			XkbDeviceChangesPtr	changes)
#else
XkbChangeDeviceInfo(dpy,devi,changes)
    Display *		dpy;
    XkbDeviceInfoPtr	devi;
    XkbDeviceChangesPtr	changes;
#endif
{
    register xkbSetDeviceInfoReq *req;
    Status		     	ok;
    int				size,nLeds;
    XkbInfoPtr 			xkbi;
    SetLedStuff			lstuff;

    if ((dpy->flags & XlibDisplayNoXkb) ||
	(!dpy->xkb_info && !XkbUseExtension(dpy,NULL,NULL)))
	return False;
    if ((!devi) || (changes->changed&(~XkbXI_AllDeviceFeaturesMask)) ||
	((changes->changed&XkbXI_ButtonActionsMask)&&
					(!XkbXI_DevHasBtnActs(devi)))||
	((changes->changed&XkbXI_IndicatorsMask)&&(!XkbXI_DevHasLeds(devi))))
	return False;

    size= nLeds= 0;
    _InitLedStuff(&lstuff,changes->changed,devi);
    if (_XkbSetDeviceInfoSize(devi,changes,&lstuff,&size,&nLeds)!=Success)
	return False;
    LockDisplay(dpy);
    xkbi = dpy->xkb_info;
    GetReq(kbSetDeviceInfo, req);
    req->length+=	size/4;
    req->reqType= 	xkbi->codes->major_opcode;
    req->xkbReqType= 	X_kbSetDeviceInfo;
    req->deviceSpec= 	devi->device_spec;
    req->firstBtn=	changes->first_btn;
    req->nBtns=		changes->num_btns;
    req->change=	changes->changed;
    req->nDeviceLedFBs=	nLeds;
    if (size>0) {
	char * 	wire;
	BufAlloc(char *,wire,size);
	ok= (wire!=NULL)&&
		(_XkbWriteSetDeviceInfo(wire,changes,&lstuff,devi)==size);
    }
    UnlockDisplay(dpy);
    SyncHandle();
    _FreeLedStuff(&lstuff);
    /* 12/11/95 (ef) -- XXX!! should clear changes here */
    return ok;
}

Bool 
#if NeedFunctionPrototypes
XkbSetDeviceLedInfo(	Display *		dpy,
			XkbDeviceInfoPtr	devi,
			unsigned 		ledClass,
			unsigned		ledID,
			unsigned		which)
#else
XkbSetDeviceLedInfo(dpy,devi,ledClass,ledID,which)
    Display *		dpy;
    XkbDeviceInfoPtr	devi;
    unsigned 		ledClass;
    unsigned		ledID;
    unsigned		which;
#endif
{
    return False;
}

Bool 
#if NeedFunctionPrototypes
XkbSetDeviceButtonActions(	Display *		dpy,
				XkbDeviceInfoPtr 	devi,
				unsigned int		first,
				unsigned int		nBtns)
#else
XkbSetDeviceButtonActions(dpy,devi,first,nBtns)
	Display *		dpy;
	XkbDeviceInfoPtr	devi;
	unsigned int		first;
	unsigned int		nBtns;
#endif
{
    register xkbSetDeviceInfoReq *req;
    Status		     	ok;
    int				size,nLeds;
    XkbInfoPtr 			xkbi;
    XkbDeviceChangesRec		changes;
    SetLedStuff			lstuff;

    if ((dpy->flags & XlibDisplayNoXkb) ||
	(!dpy->xkb_info && !XkbUseExtension(dpy,NULL,NULL)))
	return False;
    if ((!devi)||(!XkbXI_DevHasBtnActs(devi))||(first+nBtns>devi->num_btns))
	return False;
    if (nBtns==0)
	return True;

    bzero((char *)&changes,sizeof(XkbDeviceChangesRec));
    changes.changed= 		XkbXI_ButtonActionsMask;
    changes.first_btn=		first;
    changes.num_btns=		nBtns;
    changes.leds.led_class=	XkbXINone;
    changes.leds.led_id=	XkbXINone;
    changes.leds.defined=	0;
    size= nLeds= 		0;
    if (_XkbSetDeviceInfoSize(devi,&changes,NULL,&size,&nLeds)!=Success)
	return False;
    LockDisplay(dpy);
    xkbi = dpy->xkb_info;
    GetReq(kbSetDeviceInfo, req);
    req->length+=	size/4;
    req->reqType= 	xkbi->codes->major_opcode;
    req->xkbReqType= 	X_kbSetDeviceInfo;
    req->deviceSpec= 	devi->device_spec;
    req->firstBtn=	changes.first_btn;
    req->nBtns=		changes.num_btns;
    req->change=	changes.changed;
    req->nDeviceLedFBs=	nLeds;
    if (size>0) {
	char * 	wire;
	BufAlloc(char *,wire,size);
	ok= (wire!=NULL)&&
		(_XkbWriteSetDeviceInfo(wire,&changes,&lstuff,devi)==size);
    }
    UnlockDisplay(dpy);
    SyncHandle();
    return ok;
}
