From c42968a6d4921742b4700b1c6a3f08bbd0ba7c57 Mon Sep 17 00:00:00 2001 From: Pierre Le Marre Date: Tue, 14 Oct 2025 18:58:07 +0200 Subject: [PATCH 1/3] xkb: Fix key type update Before this commit the key type of the old keymap was checked for all keys, when only *updated* keys should use the new key configuration. This sometimes resulted in failed updates when the key types list is shrunk. TODO: implement missing fallback to automatic types for removed key types Signed-off-by: Pierre Le Marre --- xkb/xkb.c | 32 +++++++++++++++++++++++++++++++- 1 file changed, 31 insertions(+), 1 deletion(-) diff --git a/xkb/xkb.c b/xkb/xkb.c index 2433b7d73..43e218f20 100644 --- a/xkb/xkb.c +++ b/xkb/xkb.c @@ -2150,9 +2150,20 @@ SetKeySyms(ClientPtr client, changes->map.num_key_syms = (last - first + 1); s = 0; - for (i = xkb->min_key_code; i <= xkb->max_key_code; i++) { + oldMap = &xkb->map->key_sym_map[xkb->min_key_code]; + for (i = xkb->min_key_code; i <= xkb->max_key_code; i++, oldMap++) { if (XkbKeyNumGroups(xkb, i) > s) s = XkbKeyNumGroups(xkb, i); + if (i >= first && i <= last) { + /* Skip keys that were explicitly updated */ + continue; + } + for (unsigned char g = 0; g < XkbNumGroups(oldMap->group_info); g++) { + if (oldMap->kt_index[g] < xkb->map->num_types) + continue; + /* Deleted type: use an automatic type */ + // TODO: implement fallback to automatic types + } } if (s != xkb->ctrls->num_groups) { xkbControlsNotify cn; @@ -2483,6 +2494,7 @@ _XkbSetMapChecks(ClientPtr client, DeviceIntPtr dev, xkbSetMapReq * req, CARD16 symsPerKey[XkbMaxLegalKeyCode + 1] = { 0 }; XkbSymMapPtr map; int i; + int max_changed_key; if (!dev->key) return 0; @@ -2520,16 +2532,34 @@ _XkbSetMapChecks(ClientPtr client, DeviceIntPtr dev, xkbSetMapReq * req, return BadValue; } + max_changed_key = req->firstKeySym + req->nKeySyms; + map = &xkb->map->key_sym_map[xkb->min_key_code]; for (i = xkb->min_key_code; i < xkb->max_key_code; i++, map++) { register int g, ng, w; + if ((req->present & XkbKeySymsMask) && + i >= req->firstKeySym && i < max_changed_key) { + /* Skip updated keys, since we do not know their type yet */ + continue; + } + ng = XkbNumGroups(map->group_info); for (w = g = 0; g < ng; g++) { if (map->kt_index[g] >= (unsigned) nTypes) { + // TODO: implement fallback to automatic types + // if (map->kt_index[g] >= (unsigned) nTypes && + // (!(req->present & XkbKeyTypesMask) || + // !(req->flags & XkbSetMapResizeTypes))) { + /* Key type was deleted without updating the key, which + * is permitted only with a proper key types list update + * and a fallback to one of the automatic types. */ client->errorValue = _XkbErrCode4(0x13, i, g, map->kt_index[g]); return BadValue; } + /* NOTE: a key type may still have been moved or deleted if it is in + * the updated range. In that case we rely on the width check for + * symbols. */ if (mapWidths[map->kt_index[g]] > w) w = mapWidths[map->kt_index[g]]; } From 62e748fea6e273da4df5acdb8b03d626e839cbf7 Mon Sep 17 00:00:00 2001 From: Pierre Le Marre Date: Tue, 14 Oct 2025 18:59:22 +0200 Subject: [PATCH 2/3] xkb: Remove useless check Signed-off-by: Pierre Le Marre --- xkb/xkb.c | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/xkb/xkb.c b/xkb/xkb.c index 43e218f20..2c94d8226 100644 --- a/xkb/xkb.c +++ b/xkb/xkb.c @@ -1727,7 +1727,6 @@ CheckKeySyms(ClientPtr client, CARD16 *symsPerKey, xkbSymMapWireDesc ** wireRtrn, int *errorRtrn, Bool doswap) { register unsigned i; - XkbSymMapPtr map; xkbSymMapWireDesc *wire = *wireRtrn; if (!(XkbKeySymsMask & req->present)) @@ -1779,21 +1778,6 @@ CheckKeySyms(ClientPtr client, wire = (xkbSymMapWireDesc *) &pSyms[wire->nSyms]; } - map = &xkb->map->key_sym_map[i]; - for (; i <= (unsigned) xkb->max_key_code; i++, map++) { - register int g, nG, w; - - nG = XkbKeyNumGroups(xkb, i); - for (w = g = 0; g < nG; g++) { - if (map->kt_index[g] >= (unsigned) nTypes) { - *errorRtrn = _XkbErrCode4(0x18, i, g, map->kt_index[g]); - return 0; - } - if (mapWidths[map->kt_index[g]] > w) - w = mapWidths[map->kt_index[g]]; - } - symsPerKey[i] = w * nG; - } *wireRtrn = wire; return 1; } From 4c76f75bfc99c36e65cf924aec4b02ce550c8fce Mon Sep 17 00:00:00 2001 From: Pierre Le Marre Date: Tue, 14 Oct 2025 23:17:32 +0200 Subject: [PATCH 3/3] xkb: Fix key type level names Signed-off-by: Pierre Le Marre --- xkb/xkb.c | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/xkb/xkb.c b/xkb/xkb.c index 2c94d8226..77253c564 100644 --- a/xkb/xkb.c +++ b/xkb/xkb.c @@ -4350,13 +4350,14 @@ _XkbSetNames(ClientPtr client, DeviceIntPtr dev, xkbSetNamesReq * stuff) tmp = (CARD32 *) (((char *) tmp) + XkbPaddedSize(stuff->nKTLevels)); type = &xkb->map->types[stuff->firstKTLevel]; for (i = 0; i < stuff->nKTLevels; i++, type++) { - if (width[i] > 0) { - if (type->level_names) { - register unsigned n; - - for (n = 0; n < width[i]; n++) { - type->level_names[n] = tmp[n]; - } + if (type->level_names) { + register unsigned n; + for (n = 0; n < width[i]; n++) { + type->level_names[n] = tmp[n]; + } + /* Reset other level names */ + for (n = width[i]; n < type->num_levels; n++) { + type->level_names[n] = None; } tmp += width[i]; }