A single key on keyboard produces extra keypresses for each simultaneously pressed key
I have tried to make a proper patch for this bug. It is a problem in the kernel rather than with the keyboard, although it could be argued that the keyboard behave in a strange way. Anyway, the patch is submitted to the linux-input list for review but there are no comments on it yet.
This should fix the problem mentioned here with the QPAD MK-85, but the same problem exists with Corsair K70, Gigabyte Osmium and other similar keyboards. If you have a keyboard that has the bug it would be great it you can test the patch. If you test it let me know if it works and also what keyboard you have, it is also important what language version you are using, US and non-US keyboards will behave differently. Note that the backslash key on US keyboards will have other labels on other versions of the keyboard.
Here is the mail from linux-input with the patch:
http://article.gmane.org/gmane.linux.kernel.input/37583
Alright, I managed to put together a hack that solves the issue. I'll write it here in case someone stumbles with the same issue.
First off, if you're not interested in tweaking the kernel source, you might have another option: http://kbd-mangler.sourceforge.net/ - I did not test it, but the description looks rather promising. It allows you to tweak input before it's passed to the system.
My solution was to edit the file drivers/hid/hid-input.c. In the beginning of the file I added three new variable definitions;
static bool CODE43TRUE = 0; // If true, code43 has been pressed
static bool CODEXXTRUE = 0; // If true, any other key has been pressed
static int CODESKIP = 0; // Counter for skipping extra code43 events
Find the function
void hidinput_hid_event
At the bottom of this function is
input_event(input, usage->type, usage->code, value);
Input is the controller, type refers to event type (1 is keypress.. 2 is mouse motion?), code is the keycode and value is either 0 for depressed and 1 for pressed.
At any keypress the HID system loops 4 times through all keyboard keys. Why does it do it 4 times I do not know, but 4 corresponds with the amount of extra keypresses I got with my problematic key. On the first loop the pressed key has value 0, on second value 1, and on third and fourth again value 0.
The solution was to modify this function so that it would not allow the problematic key to be pressed again when other keys are pressed OR within 4 loops of the original keypress. This was achieved by the following code (Did I mention I haven't coded C for at least a decade? Sorry)
/* report the usage code as scancode if the key status has changed */
if (usage->type == EV_KEY && !!test_bit(usage->code, input->key) != value)
input_event(input, EV_MSC, MSC_SCAN, usage->hid);
// NEW CODE STARTS HERE
if (usage->type == 1 && value == 1) // Keypress ahead
{
if (usage->code == 43) { // Keypress is code 43
if (CODE43TRUE == 0) { // Key not yet pressed
CODE43TRUE = 1;
printk(KERN_INFO "CODE43 SET TRUE\n");
}
else { // Key already pressed, so force value 1
printk(KERN_INFO "CODE43 ALREADY TRUE SET VALUE 1\n");
value = 0;
}
}
else { // Some other key pressed, set XX true
CODEXXTRUE = 1;
printk(KERN_INFO "CODEXX SET TRUE\n");
}
printk(KERN_INFO "Keypress type:%u code:%u value%d\n", (unsigned int) usage->type, (unsigned int) usage->code, (int) value);
}
if (usage->type == 1 && value == 0) { // Non-pressed key ahead
if (usage->code == 43) { // If its a 43
printk(KERN_INFO "43 call..\n");
if (CODE43TRUE == 1) { // And 43 is fake pressed still
if (CODEXXTRUE == 1 || CODESKIP < 4) { // If other buttons are pressed OR we are less than 5 ticks into the press..
printk(KERN_INFO "FAKE PRESS 43. CODESKIP %d\n",CODESKIP);
value = 0;
CODESKIP ++;
}
else { // No other buttons pressed and over five ticks have passed
printk(KERN_INFO "43 RELEASED\n");
CODE43TRUE = 0;
CODESKIP = 0;
}
}
// Reset the CODEXXTRUE (next time we get info about 43, we have looped through all the other keys so we know if something is pressed)
CODEXXTRUE = 0;
}
}
// NEW CODE ENDS HERE
input_event(input, usage->type, usage->code, value);
If you're implementing this you might want to remove the printk statements once you've verified it's working as intended. They're just there to help debugging.