#ifdef HAVE_DIX_CONFIG_H
#include "dix-config.h"
#endif
#include "exevents.h"
#include "exglobals.h"
#include "misc.h"
#include "input.h"
#include "inputstr.h"
#include "xace.h"
#include "xkbsrv.h"
#include "xkbstr.h"
#include "inpututils.h"
static int
check_butmap_change(DeviceIntPtr dev, CARD8 *map, int len, CARD32 *errval_out,
ClientPtr client)
{
int i, ret;
if (!dev || !dev->button)
{
client->errorValue = (dev) ? dev->id : 0;
return BadDevice;
}
ret = XaceHook(XACE_DEVICE_ACCESS, client, dev, DixManageAccess);
if (ret != Success)
{
client->errorValue = dev->id;
return ret;
}
for (i = 0; i < len; i++) {
if (dev->button->map[i + 1] != map[i] && dev->button->down[i + 1])
return MappingBusy;
}
return Success;
}
static void
do_butmap_change(DeviceIntPtr dev, CARD8 *map, int len, ClientPtr client)
{
int i;
xEvent core_mn;
deviceMappingNotify xi_mn;
memcpy(&(dev->button->map[1]), map, len);
core_mn.u.u.type = MappingNotify;
core_mn.u.mappingNotify.request = MappingPointer;
for (i = 1; i < currentMaxClients; i++) {
if (!clients[i] || clients[i]->clientState != ClientStateRunning)
continue;
if (!XIShouldNotify(clients[i], dev))
continue;
WriteEventsToClient(clients[i], 1, &core_mn);
}
xi_mn.type = DeviceMappingNotify;
xi_mn.request = MappingPointer;
xi_mn.deviceid = dev->id;
xi_mn.time = GetTimeInMillis();
SendEventToAllWindows(dev, DeviceMappingNotifyMask, (xEvent *) &xi_mn, 1);
}
int
ApplyPointerMapping(DeviceIntPtr dev, CARD8 *map, int len, ClientPtr client)
{
int ret;
ret = check_butmap_change(dev, map, len, &client->errorValue, client);
if (ret != Success)
return ret;
do_butmap_change(dev, map, len, client);
return Success;
}
static int
check_modmap_change(ClientPtr client, DeviceIntPtr dev, KeyCode *modmap)
{
int ret, i;
XkbDescPtr xkb;
ret = XaceHook(XACE_DEVICE_ACCESS, client, dev, DixManageAccess);
if (ret != Success)
return ret;
if (!dev->key)
return BadMatch;
xkb = dev->key->xkbInfo->desc;
for (i = 0; i < MAP_LENGTH; i++) {
if (!modmap[i])
continue;
if (i < xkb->min_key_code || i > xkb->max_key_code) {
client->errorValue = i;
return -1;
}
if (!LegalModifier(i, dev)) {
client->errorValue = i;
return MappingFailed;
}
if (key_is_down(dev, i, KEY_POSTED | KEY_PROCESSED)) {
client->errorValue = i;
return MappingBusy;
}
}
for (i = xkb->min_key_code; i < xkb->max_key_code; i++) {
if (!xkb->map->modmap[i])
continue;
if (key_is_down(dev, i, KEY_POSTED | KEY_PROCESSED)) {
client->errorValue = i;
return MappingBusy;
}
}
return Success;
}
static int
check_modmap_change_slave(ClientPtr client, DeviceIntPtr master,
DeviceIntPtr slave, CARD8 *modmap)
{
XkbDescPtr master_xkb, slave_xkb;
int i, j;
if (!slave->key || !master->key)
return 0;
master_xkb = master->key->xkbInfo->desc;
slave_xkb = slave->key->xkbInfo->desc;
if (slave_xkb->min_key_code != master_xkb->min_key_code ||
slave_xkb->max_key_code != master_xkb->max_key_code)
return 0;
for (i = 0; i < MAP_LENGTH; i++) {
if (!modmap[i])
continue;
for (j = 0;
j < XkbKeyNumSyms(slave_xkb, i) &&
j < XkbKeyNumSyms(master_xkb, i);
j++)
if (XkbKeySymsPtr(slave_xkb, i)[j] != XkbKeySymsPtr(master_xkb, i)[j])
return 0;
}
if (check_modmap_change(client, slave, modmap) != Success)
return 0;
return 1;
}
static void
do_modmap_change(ClientPtr client, DeviceIntPtr dev, CARD8 *modmap)
{
XkbApplyMappingChange(dev, NULL, 0, 0, modmap, serverClient);
}
static int build_modmap_from_modkeymap(CARD8 *modmap, KeyCode *modkeymap,
int max_keys_per_mod)
{
int i, len = max_keys_per_mod * 8;
memset(modmap, 0, MAP_LENGTH);
for (i = 0; i < len; i++) {
if (!modkeymap[i])
continue;
if (modkeymap[i] >= MAP_LENGTH)
return BadValue;
if (modmap[modkeymap[i]])
return BadValue;
modmap[modkeymap[i]] = 1 << (i / max_keys_per_mod);
}
return Success;
}
int
change_modmap(ClientPtr client, DeviceIntPtr dev, KeyCode *modkeymap,
int max_keys_per_mod)
{
int ret;
CARD8 modmap[MAP_LENGTH];
DeviceIntPtr tmp;
ret = build_modmap_from_modkeymap(modmap, modkeymap, max_keys_per_mod);
if (ret != Success)
return ret;
ret = check_modmap_change(client, dev, modmap);
if (ret != Success)
return ret;
do_modmap_change(client, dev, modmap);
if (IsMaster(dev)) {
for (tmp = inputInfo.devices; tmp; tmp = tmp->next) {
if (!IsMaster(tmp) && tmp->u.master == dev)
if (check_modmap_change_slave(client, dev, tmp, modmap))
do_modmap_change(client, tmp, modmap);
}
}
else if (dev->u.master && dev->u.master->u.lastSlave == dev) {
if (check_modmap_change(client, dev->u.master, modmap))
do_modmap_change(client, dev->u.master, modmap);
}
return Success;
}
int generate_modkeymap(ClientPtr client, DeviceIntPtr dev,
KeyCode **modkeymap_out, int *max_keys_per_mod_out)
{
CARD8 keys_per_mod[8];
int max_keys_per_mod;
KeyCode *modkeymap = NULL;
int i, j, ret;
ret = XaceHook(XACE_DEVICE_ACCESS, client, dev, DixGetAttrAccess);
if (ret != Success)
return ret;
if (!dev->key)
return BadMatch;
max_keys_per_mod = 0;
for (i = 0; i < 8; i++)
keys_per_mod[i] = 0;
for (i = 8; i < MAP_LENGTH; i++) {
for (j = 0; j < 8; j++) {
if (dev->key->xkbInfo->desc->map->modmap[i] & (1 << j)) {
if (++keys_per_mod[j] > max_keys_per_mod)
max_keys_per_mod = keys_per_mod[j];
}
}
}
if (max_keys_per_mod != 0) {
modkeymap = calloc(max_keys_per_mod * 8, sizeof(KeyCode));
if (!modkeymap)
return BadAlloc;
for (i = 0; i < 8; i++)
keys_per_mod[i] = 0;
for (i = 8; i < MAP_LENGTH; i++) {
for (j = 0; j < 8; j++) {
if (dev->key->xkbInfo->desc->map->modmap[i] & (1 << j)) {
modkeymap[(j * max_keys_per_mod) + keys_per_mod[j]] = i;
keys_per_mod[j]++;
}
}
}
}
*max_keys_per_mod_out = max_keys_per_mod;
*modkeymap_out = modkeymap;
return Success;
}
InputAttributes*
DuplicateInputAttributes(InputAttributes *attrs)
{
InputAttributes *new_attr;
int ntags = 0;
char **tags, **new_tags;
if (!attrs)
return NULL;
if (!(new_attr = calloc(1, sizeof(InputAttributes))))
goto unwind;
if (attrs->product && !(new_attr->product = strdup(attrs->product)))
goto unwind;
if (attrs->vendor && !(new_attr->vendor = strdup(attrs->vendor)))
goto unwind;
if (attrs->device && !(new_attr->device = strdup(attrs->device)))
goto unwind;
if (attrs->pnp_id && !(new_attr->pnp_id = strdup(attrs->pnp_id)))
goto unwind;
if (attrs->usb_id && !(new_attr->usb_id = strdup(attrs->usb_id)))
goto unwind;
new_attr->flags = attrs->flags;
if ((tags = attrs->tags))
{
while(*tags++)
ntags++;
new_attr->tags = calloc(ntags + 1, sizeof(char*));
if (!new_attr->tags)
goto unwind;
tags = attrs->tags;
new_tags = new_attr->tags;
while(*tags)
{
*new_tags = strdup(*tags);
if (!*new_tags)
goto unwind;
tags++;
new_tags++;
}
}
return new_attr;
unwind:
FreeInputAttributes(new_attr);
return NULL;
}
void
FreeInputAttributes(InputAttributes *attrs)
{
char **tags;
if (!attrs)
return;
free(attrs->product);
free(attrs->vendor);
free(attrs->device);
free(attrs->pnp_id);
free(attrs->usb_id);
if ((tags = attrs->tags))
while(*tags)
free(*tags++);
free(attrs->tags);
free(attrs);
}
ValuatorMask*
valuator_mask_new(int num_valuators)
{
ValuatorMask *mask = calloc(1, sizeof(ValuatorMask));
mask->last_bit = -1;
return mask;
}
void
valuator_mask_free(ValuatorMask **mask)
{
free(*mask);
*mask = NULL;
}
void
valuator_mask_set_range(ValuatorMask *mask, int first_valuator, int num_valuators,
const int* valuators)
{
int i;
valuator_mask_zero(mask);
for (i = first_valuator; i < min(first_valuator + num_valuators, MAX_VALUATORS); i++)
valuator_mask_set(mask, i, valuators[i - first_valuator]);
}
void
valuator_mask_zero(ValuatorMask *mask)
{
memset(mask, 0, sizeof(*mask));
mask->last_bit = -1;
}
int
valuator_mask_size(const ValuatorMask *mask)
{
return mask->last_bit + 1;
}
int
valuator_mask_num_valuators(const ValuatorMask *mask)
{
return CountBits(mask->mask, min(mask->last_bit + 1, MAX_VALUATORS));
}
int
valuator_mask_isset(const ValuatorMask *mask, int valuator)
{
return mask->last_bit >= valuator && BitIsOn(mask->mask, valuator);
}
void
valuator_mask_set(ValuatorMask *mask, int valuator, int data)
{
mask->last_bit = max(valuator, mask->last_bit);
SetBit(mask->mask, valuator);
mask->valuators[valuator] = data;
}
int
valuator_mask_get(const ValuatorMask *mask, int valuator)
{
return mask->valuators[valuator];
}
void
valuator_mask_unset(ValuatorMask *mask, int valuator)
{
if (mask->last_bit >= valuator) {
int i, lastbit = -1;
ClearBit(mask->mask, valuator);
mask->valuators[valuator] = 0;
for (i = 0; i <= mask->last_bit; i++)
if (valuator_mask_isset(mask, i))
lastbit = max(lastbit, i);
mask->last_bit = lastbit;
}
}
void
valuator_mask_copy(ValuatorMask *dest, const ValuatorMask *src)
{
if (src)
memcpy(dest, src, sizeof(*dest));
else
valuator_mask_zero(dest);
}
int
CountBits(const uint8_t *mask, int len)
{
int i;
int ret = 0;
for (i = 0; i < len; i++)
if (BitIsOn(mask, i))
ret++;
return ret;
}