inpututils.c revision 6747b715
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; 2896747b715Smrg KeyCode *modkeymap; 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 3136747b715Smrg modkeymap = calloc(max_keys_per_mod * 8, sizeof(KeyCode)); 3146747b715Smrg if (!modkeymap) 3156747b715Smrg return BadAlloc; 3166747b715Smrg 3176747b715Smrg for (i = 0; i < 8; i++) 3186747b715Smrg keys_per_mod[i] = 0; 3196747b715Smrg 3206747b715Smrg for (i = 8; i < MAP_LENGTH; i++) { 3216747b715Smrg for (j = 0; j < 8; j++) { 3226747b715Smrg if (dev->key->xkbInfo->desc->map->modmap[i] & (1 << j)) { 3236747b715Smrg modkeymap[(j * max_keys_per_mod) + keys_per_mod[j]] = i; 3246747b715Smrg keys_per_mod[j]++; 3256747b715Smrg } 3266747b715Smrg } 3276747b715Smrg } 3286747b715Smrg 3296747b715Smrg *max_keys_per_mod_out = max_keys_per_mod; 3306747b715Smrg *modkeymap_out = modkeymap; 3316747b715Smrg 3326747b715Smrg return Success; 3336747b715Smrg} 3346747b715Smrg 3356747b715Smrg/** 3366747b715Smrg * Duplicate the InputAttributes in the most obvious way. 3376747b715Smrg * No special memory handling is used to give drivers the maximum 3386747b715Smrg * flexibility with the data. Drivers should be able to call realloc on the 3396747b715Smrg * product string if needed and perform similar operations. 3406747b715Smrg */ 3416747b715SmrgInputAttributes* 3426747b715SmrgDuplicateInputAttributes(InputAttributes *attrs) 3436747b715Smrg{ 3446747b715Smrg InputAttributes *new_attr; 3456747b715Smrg int ntags = 0; 3466747b715Smrg char **tags, **new_tags; 3476747b715Smrg 3486747b715Smrg if (!attrs) 3496747b715Smrg return NULL; 3506747b715Smrg 3516747b715Smrg if (!(new_attr = calloc(1, sizeof(InputAttributes)))) 3526747b715Smrg goto unwind; 3536747b715Smrg 3546747b715Smrg if (attrs->product && !(new_attr->product = strdup(attrs->product))) 3556747b715Smrg goto unwind; 3566747b715Smrg if (attrs->vendor && !(new_attr->vendor = strdup(attrs->vendor))) 3576747b715Smrg goto unwind; 3586747b715Smrg if (attrs->device && !(new_attr->device = strdup(attrs->device))) 3596747b715Smrg goto unwind; 3606747b715Smrg if (attrs->pnp_id && !(new_attr->pnp_id = strdup(attrs->pnp_id))) 3616747b715Smrg goto unwind; 3626747b715Smrg if (attrs->usb_id && !(new_attr->usb_id = strdup(attrs->usb_id))) 3636747b715Smrg goto unwind; 3646747b715Smrg 3656747b715Smrg new_attr->flags = attrs->flags; 3666747b715Smrg 3676747b715Smrg if ((tags = attrs->tags)) 3686747b715Smrg { 3696747b715Smrg while(*tags++) 3706747b715Smrg ntags++; 3716747b715Smrg 3726747b715Smrg new_attr->tags = calloc(ntags + 1, sizeof(char*)); 3736747b715Smrg if (!new_attr->tags) 3746747b715Smrg goto unwind; 3756747b715Smrg 3766747b715Smrg tags = attrs->tags; 3776747b715Smrg new_tags = new_attr->tags; 3786747b715Smrg 3796747b715Smrg while(*tags) 3806747b715Smrg { 3816747b715Smrg *new_tags = strdup(*tags); 3826747b715Smrg if (!*new_tags) 3836747b715Smrg goto unwind; 3846747b715Smrg 3856747b715Smrg tags++; 3866747b715Smrg new_tags++; 3876747b715Smrg } 3886747b715Smrg } 3896747b715Smrg 3906747b715Smrg return new_attr; 3916747b715Smrg 3926747b715Smrgunwind: 3936747b715Smrg FreeInputAttributes(new_attr); 3946747b715Smrg return NULL; 3956747b715Smrg} 3966747b715Smrg 3976747b715Smrgvoid 3986747b715SmrgFreeInputAttributes(InputAttributes *attrs) 3996747b715Smrg{ 4006747b715Smrg char **tags; 4016747b715Smrg 4026747b715Smrg if (!attrs) 4036747b715Smrg return; 4046747b715Smrg 4056747b715Smrg free(attrs->product); 4066747b715Smrg free(attrs->vendor); 4076747b715Smrg free(attrs->device); 4086747b715Smrg free(attrs->pnp_id); 4096747b715Smrg free(attrs->usb_id); 4106747b715Smrg 4116747b715Smrg if ((tags = attrs->tags)) 4126747b715Smrg while(*tags) 4136747b715Smrg free(*tags++); 4146747b715Smrg 4156747b715Smrg free(attrs->tags); 4166747b715Smrg free(attrs); 4176747b715Smrg} 4186747b715Smrg 419