inpututils.c revision 8223e2f2
16747b715Smrg/*
26747b715Smrg * Copyright © 2008 Daniel Stone
36747b715Smrg *
46747b715Smrg * Permission is hereby granted, free of charge, to any person obtaining a
56747b715Smrg * copy of this software and associated documentation files (the "Software"),
66747b715Smrg * to deal in the Software without restriction, including without limitation
76747b715Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense,
86747b715Smrg * and/or sell copies of the Software, and to permit persons to whom the
96747b715Smrg * Software is furnished to do so, subject to the following conditions:
106747b715Smrg *
116747b715Smrg * The above copyright notice and this permission notice (including the next
126747b715Smrg * paragraph) shall be included in all copies or substantial portions of the
136747b715Smrg * Software.
146747b715Smrg *
156747b715Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
166747b715Smrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
176747b715Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
186747b715Smrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
196747b715Smrg * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
206747b715Smrg * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
216747b715Smrg * DEALINGS IN THE SOFTWARE.
226747b715Smrg *
236747b715Smrg * Author: Daniel Stone <daniel@fooishbar.org>
246747b715Smrg */
256747b715Smrg
266747b715Smrg#ifdef HAVE_DIX_CONFIG_H
276747b715Smrg#include "dix-config.h"
286747b715Smrg#endif
296747b715Smrg
306747b715Smrg#include "exevents.h"
316747b715Smrg#include "exglobals.h"
326747b715Smrg#include "misc.h"
336747b715Smrg#include "input.h"
346747b715Smrg#include "inputstr.h"
356747b715Smrg#include "xace.h"
366747b715Smrg#include "xkbsrv.h"
376747b715Smrg#include "xkbstr.h"
386747b715Smrg
396747b715Smrg/* Check if a button map change is okay with the device.
406747b715Smrg * Returns -1 for BadValue, as it collides with MappingBusy. */
416747b715Smrgstatic int
426747b715Smrgcheck_butmap_change(DeviceIntPtr dev, CARD8 *map, int len, CARD32 *errval_out,
436747b715Smrg                    ClientPtr client)
446747b715Smrg{
456747b715Smrg    int i, ret;
466747b715Smrg
476747b715Smrg    if (!dev || !dev->button)
486747b715Smrg    {
496747b715Smrg        client->errorValue = (dev) ? dev->id : 0;
506747b715Smrg        return BadDevice;
516747b715Smrg    }
526747b715Smrg
536747b715Smrg    ret = XaceHook(XACE_DEVICE_ACCESS, client, dev, DixManageAccess);
546747b715Smrg    if (ret != Success)
556747b715Smrg    {
566747b715Smrg        client->errorValue = dev->id;
576747b715Smrg        return ret;
586747b715Smrg    }
596747b715Smrg
606747b715Smrg    for (i = 0; i < len; i++) {
616747b715Smrg        if (dev->button->map[i + 1] != map[i] && dev->button->down[i + 1])
626747b715Smrg            return MappingBusy;
636747b715Smrg    }
646747b715Smrg
656747b715Smrg    return Success;
666747b715Smrg}
676747b715Smrg
686747b715Smrgstatic void
696747b715Smrgdo_butmap_change(DeviceIntPtr dev, CARD8 *map, int len, ClientPtr client)
706747b715Smrg{
716747b715Smrg    int i;
726747b715Smrg    xEvent core_mn;
736747b715Smrg    deviceMappingNotify xi_mn;
746747b715Smrg
756747b715Smrg    /* The map in ButtonClassRec refers to button numbers, whereas the
766747b715Smrg     * protocol is zero-indexed.  Sigh. */
776747b715Smrg    memcpy(&(dev->button->map[1]), map, len);
786747b715Smrg
796747b715Smrg    core_mn.u.u.type = MappingNotify;
806747b715Smrg    core_mn.u.mappingNotify.request = MappingPointer;
816747b715Smrg
826747b715Smrg    /* 0 is the server client. */
836747b715Smrg    for (i = 1; i < currentMaxClients; i++) {
846747b715Smrg        /* Don't send irrelevant events to naïve clients. */
856747b715Smrg        if (!clients[i] || clients[i]->clientState != ClientStateRunning)
866747b715Smrg            continue;
876747b715Smrg
886747b715Smrg        if (!XIShouldNotify(clients[i], dev))
896747b715Smrg            continue;
906747b715Smrg
916747b715Smrg        WriteEventsToClient(clients[i], 1, &core_mn);
926747b715Smrg    }
936747b715Smrg
946747b715Smrg    xi_mn.type = DeviceMappingNotify;
956747b715Smrg    xi_mn.request = MappingPointer;
966747b715Smrg    xi_mn.deviceid = dev->id;
976747b715Smrg    xi_mn.time = GetTimeInMillis();
986747b715Smrg
996747b715Smrg    SendEventToAllWindows(dev, DeviceMappingNotifyMask, (xEvent *) &xi_mn, 1);
1006747b715Smrg}
1016747b715Smrg
1026747b715Smrg/*
1036747b715Smrg * Does what it says on the box, both for core and Xi.
1046747b715Smrg *
1056747b715Smrg * Faithfully reports any errors encountered while trying to apply the map
1066747b715Smrg * to the requested device, faithfully ignores any errors encountered while
1076747b715Smrg * trying to apply the map to its master/slaves.
1086747b715Smrg */
1096747b715Smrgint
1106747b715SmrgApplyPointerMapping(DeviceIntPtr dev, CARD8 *map, int len, ClientPtr client)
1116747b715Smrg{
1126747b715Smrg    int ret;
1136747b715Smrg
1146747b715Smrg    /* If we can't perform the change on the requested device, bail out. */
1156747b715Smrg    ret = check_butmap_change(dev, map, len, &client->errorValue, client);
1166747b715Smrg    if (ret != Success)
1176747b715Smrg        return ret;
1186747b715Smrg    do_butmap_change(dev, map, len, client);
1196747b715Smrg
1206747b715Smrg    return Success;
1216747b715Smrg}
1226747b715Smrg
1236747b715Smrg/* Check if a modifier map change is okay with the device.
1246747b715Smrg * Returns -1 for BadValue, as it collides with MappingBusy; this particular
1256747b715Smrg * caveat can be removed with LegalModifier, as we have no other reason to
1266747b715Smrg * set MappingFailed.  Sigh. */
1276747b715Smrgstatic int
1286747b715Smrgcheck_modmap_change(ClientPtr client, DeviceIntPtr dev, KeyCode *modmap)
1296747b715Smrg{
1306747b715Smrg    int ret, i;
1316747b715Smrg    XkbDescPtr xkb;
1326747b715Smrg
1336747b715Smrg    ret = XaceHook(XACE_DEVICE_ACCESS, client, dev, DixManageAccess);
1346747b715Smrg    if (ret != Success)
1356747b715Smrg        return ret;
1366747b715Smrg
1376747b715Smrg    if (!dev->key)
1386747b715Smrg        return BadMatch;
1396747b715Smrg    xkb = dev->key->xkbInfo->desc;
1406747b715Smrg
1416747b715Smrg    for (i = 0; i < MAP_LENGTH; i++) {
1426747b715Smrg        if (!modmap[i])
1436747b715Smrg            continue;
1446747b715Smrg
1456747b715Smrg        /* Check that all the new modifiers fall within the advertised
1466747b715Smrg         * keycode range. */
1476747b715Smrg        if (i < xkb->min_key_code || i > xkb->max_key_code) {
1486747b715Smrg            client->errorValue = i;
1496747b715Smrg            return -1;
1506747b715Smrg        }
1516747b715Smrg
1526747b715Smrg        /* Make sure the mapping is okay with the DDX. */
1536747b715Smrg        if (!LegalModifier(i, dev)) {
1546747b715Smrg            client->errorValue = i;
1556747b715Smrg            return MappingFailed;
1566747b715Smrg        }
1576747b715Smrg
1586747b715Smrg        /* None of the new modifiers may be down while we change the
1596747b715Smrg         * map. */
1606747b715Smrg        if (key_is_down(dev, i, KEY_POSTED | KEY_PROCESSED)) {
1616747b715Smrg            client->errorValue = i;
1626747b715Smrg            return MappingBusy;
1636747b715Smrg        }
1646747b715Smrg    }
1656747b715Smrg
1666747b715Smrg    /* None of the old modifiers may be down while we change the map,
1676747b715Smrg     * either. */
1686747b715Smrg    for (i = xkb->min_key_code; i < xkb->max_key_code; i++) {
1696747b715Smrg        if (!xkb->map->modmap[i])
1706747b715Smrg            continue;
1716747b715Smrg        if (key_is_down(dev, i, KEY_POSTED | KEY_PROCESSED)) {
1726747b715Smrg            client->errorValue = i;
1736747b715Smrg            return MappingBusy;
1746747b715Smrg        }
1756747b715Smrg    }
1766747b715Smrg
1776747b715Smrg    return Success;
1786747b715Smrg}
1796747b715Smrg
1806747b715Smrgstatic int
1816747b715Smrgcheck_modmap_change_slave(ClientPtr client, DeviceIntPtr master,
1826747b715Smrg                          DeviceIntPtr slave, CARD8 *modmap)
1836747b715Smrg{
1846747b715Smrg    XkbDescPtr master_xkb, slave_xkb;
1856747b715Smrg    int i, j;
1866747b715Smrg
1876747b715Smrg    if (!slave->key || !master->key)
1886747b715Smrg        return 0;
1896747b715Smrg
1906747b715Smrg    master_xkb = master->key->xkbInfo->desc;
1916747b715Smrg    slave_xkb = slave->key->xkbInfo->desc;
1926747b715Smrg
1936747b715Smrg    /* Ignore devices with a clearly different keymap. */
1946747b715Smrg    if (slave_xkb->min_key_code != master_xkb->min_key_code ||
1956747b715Smrg        slave_xkb->max_key_code != master_xkb->max_key_code)
1966747b715Smrg        return 0;
1976747b715Smrg
1986747b715Smrg    for (i = 0; i < MAP_LENGTH; i++) {
1996747b715Smrg        if (!modmap[i])
2006747b715Smrg            continue;
2016747b715Smrg
2026747b715Smrg        /* If we have different symbols for any modifier on an
2036747b715Smrg         * extended keyboard, ignore the whole remap request. */
2046747b715Smrg        for (j = 0;
2056747b715Smrg             j < XkbKeyNumSyms(slave_xkb, i) &&
2066747b715Smrg              j < XkbKeyNumSyms(master_xkb, i);
2076747b715Smrg             j++)
2086747b715Smrg            if (XkbKeySymsPtr(slave_xkb, i)[j] != XkbKeySymsPtr(master_xkb, i)[j])
2096747b715Smrg                return 0;
2106747b715Smrg    }
2116747b715Smrg
2126747b715Smrg    if (check_modmap_change(client, slave, modmap) != Success)
2136747b715Smrg        return 0;
2146747b715Smrg
2156747b715Smrg    return 1;
2166747b715Smrg}
2176747b715Smrg
2186747b715Smrg/* Actually change the modifier map, and send notifications.  Cannot fail. */
2196747b715Smrgstatic void
2206747b715Smrgdo_modmap_change(ClientPtr client, DeviceIntPtr dev, CARD8 *modmap)
2216747b715Smrg{
2226747b715Smrg    XkbApplyMappingChange(dev, NULL, 0, 0, modmap, serverClient);
2236747b715Smrg}
2246747b715Smrg
2256747b715Smrg/* Rebuild modmap (key -> mod) from map (mod -> key). */
2266747b715Smrgstatic int build_modmap_from_modkeymap(CARD8 *modmap, KeyCode *modkeymap,
2276747b715Smrg                                       int max_keys_per_mod)
2286747b715Smrg{
2296747b715Smrg    int i, len = max_keys_per_mod * 8;
2306747b715Smrg
2316747b715Smrg    memset(modmap, 0, MAP_LENGTH);
2326747b715Smrg
2336747b715Smrg    for (i = 0; i < len; i++) {
2346747b715Smrg        if (!modkeymap[i])
2356747b715Smrg            continue;
2366747b715Smrg
2376747b715Smrg        if (modkeymap[i] >= MAP_LENGTH)
2386747b715Smrg            return BadValue;
2396747b715Smrg
2406747b715Smrg        if (modmap[modkeymap[i]])
2416747b715Smrg            return BadValue;
2426747b715Smrg
2436747b715Smrg        modmap[modkeymap[i]] = 1 << (i / max_keys_per_mod);
2446747b715Smrg    }
2456747b715Smrg
2466747b715Smrg    return Success;
2476747b715Smrg}
2486747b715Smrg
2496747b715Smrgint
2506747b715Smrgchange_modmap(ClientPtr client, DeviceIntPtr dev, KeyCode *modkeymap,
2516747b715Smrg              int max_keys_per_mod)
2526747b715Smrg{
2536747b715Smrg    int ret;
2546747b715Smrg    CARD8 modmap[MAP_LENGTH];
2556747b715Smrg    DeviceIntPtr tmp;
2566747b715Smrg
2576747b715Smrg    ret = build_modmap_from_modkeymap(modmap, modkeymap, max_keys_per_mod);
2586747b715Smrg    if (ret != Success)
2596747b715Smrg        return ret;
2606747b715Smrg
2616747b715Smrg    /* If we can't perform the change on the requested device, bail out. */
2626747b715Smrg    ret = check_modmap_change(client, dev, modmap);
2636747b715Smrg    if (ret != Success)
2646747b715Smrg        return ret;
2656747b715Smrg    do_modmap_change(client, dev, modmap);
2666747b715Smrg
2676747b715Smrg    /* Change any attached masters/slaves. */
2686747b715Smrg    if (IsMaster(dev)) {
2696747b715Smrg        for (tmp = inputInfo.devices; tmp; tmp = tmp->next) {
2706747b715Smrg            if (!IsMaster(tmp) && tmp->u.master == dev)
2716747b715Smrg                if (check_modmap_change_slave(client, dev, tmp, modmap))
2726747b715Smrg                    do_modmap_change(client, tmp, modmap);
2736747b715Smrg        }
2746747b715Smrg    }
2756747b715Smrg    else if (dev->u.master && dev->u.master->u.lastSlave == dev) {
2766747b715Smrg        /* If this fails, expect the results to be weird. */
2776747b715Smrg        if (check_modmap_change(client, dev->u.master, modmap))
2786747b715Smrg            do_modmap_change(client, dev->u.master, modmap);
2796747b715Smrg    }
2806747b715Smrg
2816747b715Smrg    return Success;
2826747b715Smrg}
2836747b715Smrg
2846747b715Smrgint generate_modkeymap(ClientPtr client, DeviceIntPtr dev,
2856747b715Smrg                       KeyCode **modkeymap_out, int *max_keys_per_mod_out)
2866747b715Smrg{
2876747b715Smrg    CARD8 keys_per_mod[8];
2886747b715Smrg    int max_keys_per_mod;
2898223e2f2Smrg    KeyCode *modkeymap = NULL;
2906747b715Smrg    int i, j, ret;
2916747b715Smrg
2926747b715Smrg    ret = XaceHook(XACE_DEVICE_ACCESS, client, dev, DixGetAttrAccess);
2936747b715Smrg    if (ret != Success)
2946747b715Smrg        return ret;
2956747b715Smrg
2966747b715Smrg    if (!dev->key)
2976747b715Smrg        return BadMatch;
2986747b715Smrg
2996747b715Smrg    /* Count the number of keys per modifier to determine how wide we
3006747b715Smrg     * should make the map. */
3016747b715Smrg    max_keys_per_mod = 0;
3026747b715Smrg    for (i = 0; i < 8; i++)
3036747b715Smrg        keys_per_mod[i] = 0;
3046747b715Smrg    for (i = 8; i < MAP_LENGTH; i++) {
3056747b715Smrg        for (j = 0; j < 8; j++) {
3066747b715Smrg            if (dev->key->xkbInfo->desc->map->modmap[i] & (1 << j)) {
3076747b715Smrg                if (++keys_per_mod[j] > max_keys_per_mod)
3086747b715Smrg                    max_keys_per_mod = keys_per_mod[j];
3096747b715Smrg            }
3106747b715Smrg        }
3116747b715Smrg    }
3126747b715Smrg
3138223e2f2Smrg    if (max_keys_per_mod != 0) {
3148223e2f2Smrg        modkeymap = calloc(max_keys_per_mod * 8, sizeof(KeyCode));
3158223e2f2Smrg        if (!modkeymap)
3168223e2f2Smrg            return BadAlloc;
3176747b715Smrg
3188223e2f2Smrg        for (i = 0; i < 8; i++)
3198223e2f2Smrg            keys_per_mod[i] = 0;
3206747b715Smrg
3218223e2f2Smrg        for (i = 8; i < MAP_LENGTH; i++) {
3228223e2f2Smrg            for (j = 0; j < 8; j++) {
3238223e2f2Smrg                if (dev->key->xkbInfo->desc->map->modmap[i] & (1 << j)) {
3248223e2f2Smrg                    modkeymap[(j * max_keys_per_mod) + keys_per_mod[j]] = i;
3258223e2f2Smrg                    keys_per_mod[j]++;
3268223e2f2Smrg                }
3276747b715Smrg            }
3286747b715Smrg        }
3296747b715Smrg    }
3306747b715Smrg
3316747b715Smrg    *max_keys_per_mod_out = max_keys_per_mod;
3326747b715Smrg    *modkeymap_out = modkeymap;
3336747b715Smrg
3346747b715Smrg    return Success;
3356747b715Smrg}
3366747b715Smrg
3376747b715Smrg/**
3386747b715Smrg * Duplicate the InputAttributes in the most obvious way.
3396747b715Smrg * No special memory handling is used to give drivers the maximum
3406747b715Smrg * flexibility with the data. Drivers should be able to call realloc on the
3416747b715Smrg * product string if needed and perform similar operations.
3426747b715Smrg */
3436747b715SmrgInputAttributes*
3446747b715SmrgDuplicateInputAttributes(InputAttributes *attrs)
3456747b715Smrg{
3466747b715Smrg    InputAttributes *new_attr;
3476747b715Smrg    int ntags = 0;
3486747b715Smrg    char **tags, **new_tags;
3496747b715Smrg
3506747b715Smrg    if (!attrs)
3516747b715Smrg        return NULL;
3526747b715Smrg
3536747b715Smrg    if (!(new_attr = calloc(1, sizeof(InputAttributes))))
3546747b715Smrg        goto unwind;
3556747b715Smrg
3566747b715Smrg    if (attrs->product && !(new_attr->product = strdup(attrs->product)))
3576747b715Smrg        goto unwind;
3586747b715Smrg    if (attrs->vendor && !(new_attr->vendor = strdup(attrs->vendor)))
3596747b715Smrg        goto unwind;
3606747b715Smrg    if (attrs->device && !(new_attr->device = strdup(attrs->device)))
3616747b715Smrg        goto unwind;
3626747b715Smrg    if (attrs->pnp_id && !(new_attr->pnp_id = strdup(attrs->pnp_id)))
3636747b715Smrg        goto unwind;
3646747b715Smrg    if (attrs->usb_id && !(new_attr->usb_id = strdup(attrs->usb_id)))
3656747b715Smrg        goto unwind;
3666747b715Smrg
3676747b715Smrg    new_attr->flags = attrs->flags;
3686747b715Smrg
3696747b715Smrg    if ((tags = attrs->tags))
3706747b715Smrg    {
3716747b715Smrg        while(*tags++)
3726747b715Smrg            ntags++;
3736747b715Smrg
3746747b715Smrg        new_attr->tags = calloc(ntags + 1, sizeof(char*));
3756747b715Smrg        if (!new_attr->tags)
3766747b715Smrg            goto unwind;
3776747b715Smrg
3786747b715Smrg        tags = attrs->tags;
3796747b715Smrg        new_tags = new_attr->tags;
3806747b715Smrg
3816747b715Smrg        while(*tags)
3826747b715Smrg        {
3836747b715Smrg            *new_tags = strdup(*tags);
3846747b715Smrg            if (!*new_tags)
3856747b715Smrg                goto unwind;
3866747b715Smrg
3876747b715Smrg            tags++;
3886747b715Smrg            new_tags++;
3896747b715Smrg        }
3906747b715Smrg    }
3916747b715Smrg
3926747b715Smrg    return new_attr;
3936747b715Smrg
3946747b715Smrgunwind:
3956747b715Smrg    FreeInputAttributes(new_attr);
3966747b715Smrg    return NULL;
3976747b715Smrg}
3986747b715Smrg
3996747b715Smrgvoid
4006747b715SmrgFreeInputAttributes(InputAttributes *attrs)
4016747b715Smrg{
4026747b715Smrg    char **tags;
4036747b715Smrg
4046747b715Smrg    if (!attrs)
4056747b715Smrg        return;
4066747b715Smrg
4076747b715Smrg    free(attrs->product);
4086747b715Smrg    free(attrs->vendor);
4096747b715Smrg    free(attrs->device);
4106747b715Smrg    free(attrs->pnp_id);
4116747b715Smrg    free(attrs->usb_id);
4126747b715Smrg
4136747b715Smrg    if ((tags = attrs->tags))
4146747b715Smrg        while(*tags)
4156747b715Smrg            free(*tags++);
4166747b715Smrg
4176747b715Smrg    free(attrs->tags);
4186747b715Smrg    free(attrs);
4196747b715Smrg}
4206747b715Smrg
421