• David Herrmann's avatar
    HID: input: fix confusion on conflicting mappings · a097d579
    David Herrmann authored
    commit 6ce901eb upstream.
    
    On an PC-101/103/104 keyboard (American layout) the 'Enter' key and its
    neighbours look like this:
    
               +---+ +---+ +-------+
               | 1 | | 2 | |   5   |
               +---+ +---+ +-------+
                 +---+ +-----------+
                 | 3 | |     4     |
                 +---+ +-----------+
    
    On a PC-102/105 keyboard (European layout) it looks like this:
    
               +---+ +---+ +-------+
               | 1 | | 2 | |       |
               +---+ +---+ +-+  4  |
                 +---+ +---+ |     |
                 | 3 | | 5 | |     |
                 +---+ +---+ +-----+
    
    (Note that the number of keys is the same, but key '5' is moved down and
     the shape of key '4' is changed. Keys '1' to '3' are exactly the same.)
    
    The keys 1-4 report the same scan-code in HID in both layouts, even though
    the keysym they produce is usually different depending on the XKB-keymap
    used by user-space.
    However, key '5' (US 'backslash'/'pipe') reports 0x31 for the upper layout
    and 0x32 for the lower layout, as defined by the HID spec. This is highly
    confusing as the linux-input API uses a single keycode for both.
    
    So far, this was never a problem as there never has been a keyboard with
    both of those keys present at the same time. It would have to look
    something like this:
    
               +---+ +---+ +-------+
               | 1 | | 2 | |  x31  |
               +---+ +---+ +-------+
                 +---+ +---+ +-----+
                 | 3 | |x32| |  4  |
                 +---+ +---+ +-----+
    
    HID can represent such a keyboard, but the linux-input API cannot.
    Furthermore, any user-space mapping would be confused by this and,
    luckily, no-one ever produced such hardware.
    
    Now, the HID input layer fixed this mess by mapping both 0x31 and 0x32 to
    the same keycode (KEY_BACKSLASH==0x2b). As only one of both physical keys
    is present on a hardware, this works just fine.
    
    Lets introduce hardware-vendors into this:
    ------------------------------------------
    
    Unfortunately, it seems way to expensive to produce a different device for
    American and European layouts. Therefore, hardware-vendors put both keys,
    (0x31 and 0x32) on the same keyboard, but only one of them is hooked up
    to the physical button, the other one is 'dead'.
    This means, they can use the same hardware, with a different button-layout
    and automatically produce the correct HID events for American *and*
    European layouts. This is unproblematic for normal keyboards, as the
    'dead' key will never report any KEY-DOWN events. But RollOver keyboards
    send the whole matrix on each key-event, allowing n-key roll-over mode.
    This means, we get a 0x31 and 0x32 event on each key-press. One of them
    will always be 0, the other reports the real state. As we map both to the
    same keycode, we will get spurious key-events, even though the real
    key-state never changed.
    
    The easiest way would be to blacklist 'dead' keys and never handle those.
    We could simply read the 'country' tag of USB devices and blacklist either
    key according to the layout. But... hardware vendors... want the same
    device for all countries and thus many of them set 'country' to 0 for all
    devices. Meh..
    
    So we have to deal with this properly. As we cannot know which of the keys
    is 'dead', we either need a heuristic and track those keys, or we simply
    make use of our value-tracking for HID fields. We simply ignore HID events
    for absolute data if the data didn't change. As HID tracks events on the
    HID level, we haven't done the keycode translation, yet. Therefore, the
    'dead' key is tracked independently of the real key, therefore, any events
    on it will be ignored.
    
    This patch simply discards any HID events for absolute data if it didn't
    change compared to the last report. We need to ignore relative and
    buffered-byte reports for obvious reasons. But those cannot be affected by
    this bug, so we're fine.
    
    Preferably, we'd do this filtering on the HID-core level. But this might
    break a lot of custom drivers, if they do not follow the HID specs.
    Therefore, we do this late in hid-input just before we inject it into the
    input layer (which does the exact same filtering, but on the keycode
    level).
    
    If this turns out to break some devices, we might have to limit filtering
    to EV_KEY events. But lets try to do the Right Thing first, and properly
    filter any absolute data that didn't change.
    
    This patch is tagged for 'stable' as it fixes a lot of n-key RollOver
    hardware. We might wanna wait with backporting for a while, before we know
    it doesn't break anything else, though.
    Reported-by: default avatarAdam Goode <adam@spicenitz.org>
    Reported-by: default avatarFredrik Hallenberg <megahallon@gmail.com>
    Tested-by: default avatarFredrik Hallenberg <megahallon@gmail.com>
    Signed-off-by: default avatarDavid Herrmann <dh.herrmann@gmail.com>
    Signed-off-by: default avatarJiri Kosina <jkosina@suse.cz>
    Signed-off-by: default avatarLuis Henriques <luis.henriques@canonical.com>
    a097d579
hid-input.c 44.6 KB