Skip to content

Commit e05ff91

Browse files
kekrbySasha Levin
authored and
Sasha Levin
committed
HID: apple: fix key translations where multiple quirks attempt to translate the same key
[ Upstream commit 5476fcf ] The hid-apple driver does not support chaining translations or dependencies on other translations. This creates two problems: 1 - In Non-English keyboards of Macs, KEY_102ND and KEY_GRAVE are swapped and the APPLE_ISO_TILDE_QUIRK is used to work around this problem. The quirk is not set for the Macs where these bugs happen yet (see the 2nd patch for that), but this can be forced by setting the iso_layout parameter. Unfortunately, this only partially works. KEY_102ND gets translated to KEY_GRAVE, but KEY_GRAVE does not get translated to KEY_102ND, so both of them end up functioning as KEY_GRAVE. This is because the driver translates the keys as if Fn was pressed and the original is sent if it is not pressed, without any further translations happening on the key[torvalds#463]. KEY_GRAVE is present at macbookpro_no_esc_fn_keys[torvalds#195], so this is what happens: - KEY_GRAVE -> KEY_ESC (as if Fn is pressed) - KEY_GRAVE is returned (Fn isn't pressed, so translation is discarded) - KEY_GRAVE -> KEY_102ND (this part is not reached!) ... 2 - In case the touchbar does not work, the driver supports sending Escape when Fn+KEY_GRAVE is pressed. As mentioned previously, KEY_102ND is actually KEY_GRAVE and needs to be translated before this happens. Normally, these are the steps that should happen: - KEY_102ND -> KEY_GRAVE - KEY_GRAVE -> KEY_ESC (Fn is pressed) - KEY_ESC is returned Though this is what happens instead, as dependencies on other translations are not supported: - KEY_102ND -> KEY_ESC (Fn is pressed) - KEY_ESC is returned This patch fixes both bugs by ordering the translations correctly and by making the translations continue and not return immediately after translating a key so that chained translations work and translations can depend on other ones. This patch also simplifies the implementation of the swap_fn_leftctrl option a little bit, as it makes it simply use a normal translation instead adding extra code to translate a key to KEY_FN[torvalds#381]. This change wasn't put in another patch as the code that translates the Fn key needs to be changed because of the changes in the patch, and those changes would be discarded with the next patch anyway (the part that originally translates KEY_FN to KEY_LEFTCTRL needs to be made an else-if branch of the part that transltes KEY_LEFTCTRL to KEY_FN). Note: Line numbers (#XYZ) are for drivers/hid/hid-apple.c at commit 20afcc4 ("HID: apple: Add "GANSS" to the non-Apple list"). Note: These bugs are only present on Macs with a keyboard with no dedicated escape key and a non-English layout. Signed-off-by: Kerem Karabay <kekrby@gmail.com> Signed-off-by: Jiri Kosina <jkosina@suse.cz> Signed-off-by: Sasha Levin <sashal@kernel.org>
1 parent aa63178 commit e05ff91

File tree

1 file changed

+44
-58
lines changed

1 file changed

+44
-58
lines changed

drivers/hid/hid-apple.c

+44-58
Original file line numberDiff line numberDiff line change
@@ -314,6 +314,7 @@ static const struct apple_key_translation swapped_option_cmd_keys[] = {
314314

315315
static const struct apple_key_translation swapped_fn_leftctrl_keys[] = {
316316
{ KEY_FN, KEY_LEFTCTRL },
317+
{ KEY_LEFTCTRL, KEY_FN },
317318
{ }
318319
};
319320

@@ -375,24 +376,40 @@ static int hidinput_apple_event(struct hid_device *hid, struct input_dev *input,
375376
struct apple_sc *asc = hid_get_drvdata(hid);
376377
const struct apple_key_translation *trans, *table;
377378
bool do_translate;
378-
u16 code = 0;
379+
u16 code = usage->code;
379380
unsigned int real_fnmode;
380381

381-
u16 fn_keycode = (swap_fn_leftctrl) ? (KEY_LEFTCTRL) : (KEY_FN);
382-
383-
if (usage->code == fn_keycode) {
384-
asc->fn_on = !!value;
385-
input_event_with_scancode(input, usage->type, KEY_FN,
386-
usage->hid, value);
387-
return 1;
388-
}
389-
390382
if (fnmode == 3) {
391383
real_fnmode = (asc->quirks & APPLE_IS_NON_APPLE) ? 2 : 1;
392384
} else {
393385
real_fnmode = fnmode;
394386
}
395387

388+
if (swap_fn_leftctrl) {
389+
trans = apple_find_translation(swapped_fn_leftctrl_keys, code);
390+
391+
if (trans)
392+
code = trans->to;
393+
}
394+
395+
if (iso_layout > 0 || (iso_layout < 0 && (asc->quirks & APPLE_ISO_TILDE_QUIRK) &&
396+
hid->country == HID_COUNTRY_INTERNATIONAL_ISO)) {
397+
trans = apple_find_translation(apple_iso_keyboard, code);
398+
399+
if (trans)
400+
code = trans->to;
401+
}
402+
403+
if (swap_opt_cmd) {
404+
trans = apple_find_translation(swapped_option_cmd_keys, code);
405+
406+
if (trans)
407+
code = trans->to;
408+
}
409+
410+
if (code == KEY_FN)
411+
asc->fn_on = !!value;
412+
396413
if (real_fnmode) {
397414
if (hid->product == USB_DEVICE_ID_APPLE_ALU_WIRELESS_ANSI ||
398415
hid->product == USB_DEVICE_ID_APPLE_ALU_WIRELESS_ISO ||
@@ -430,15 +447,18 @@ static int hidinput_apple_event(struct hid_device *hid, struct input_dev *input,
430447
else
431448
table = apple_fn_keys;
432449

433-
trans = apple_find_translation (table, usage->code);
450+
trans = apple_find_translation(table, code);
434451

435452
if (trans) {
436-
if (test_bit(trans->from, input->key))
453+
bool from_is_set = test_bit(trans->from, input->key);
454+
bool to_is_set = test_bit(trans->to, input->key);
455+
456+
if (from_is_set)
437457
code = trans->from;
438-
else if (test_bit(trans->to, input->key))
458+
else if (to_is_set)
439459
code = trans->to;
440460

441-
if (!code) {
461+
if (!(from_is_set || to_is_set)) {
442462
if (trans->flags & APPLE_FLAG_FKEY) {
443463
switch (real_fnmode) {
444464
case 1:
@@ -455,62 +475,31 @@ static int hidinput_apple_event(struct hid_device *hid, struct input_dev *input,
455475
do_translate = asc->fn_on;
456476
}
457477

458-
code = do_translate ? trans->to : trans->from;
478+
if (do_translate)
479+
code = trans->to;
459480
}
460-
461-
input_event_with_scancode(input, usage->type, code,
462-
usage->hid, value);
463-
return 1;
464481
}
465482

466483
if (asc->quirks & APPLE_NUMLOCK_EMULATION &&
467-
(test_bit(usage->code, asc->pressed_numlock) ||
484+
(test_bit(code, asc->pressed_numlock) ||
468485
test_bit(LED_NUML, input->led))) {
469-
trans = apple_find_translation(powerbook_numlock_keys,
470-
usage->code);
486+
trans = apple_find_translation(powerbook_numlock_keys, code);
471487

472488
if (trans) {
473489
if (value)
474-
set_bit(usage->code,
475-
asc->pressed_numlock);
490+
set_bit(code, asc->pressed_numlock);
476491
else
477-
clear_bit(usage->code,
478-
asc->pressed_numlock);
492+
clear_bit(code, asc->pressed_numlock);
479493

480-
input_event_with_scancode(input, usage->type,
481-
trans->to, usage->hid, value);
494+
code = trans->to;
482495
}
483-
484-
return 1;
485496
}
486497
}
487498

488-
if (iso_layout > 0 || (iso_layout < 0 && (asc->quirks & APPLE_ISO_TILDE_QUIRK) &&
489-
hid->country == HID_COUNTRY_INTERNATIONAL_ISO)) {
490-
trans = apple_find_translation(apple_iso_keyboard, usage->code);
491-
if (trans) {
492-
input_event_with_scancode(input, usage->type,
493-
trans->to, usage->hid, value);
494-
return 1;
495-
}
496-
}
499+
if (usage->code != code) {
500+
input_event_with_scancode(input, usage->type, code, usage->hid, value);
497501

498-
if (swap_opt_cmd) {
499-
trans = apple_find_translation(swapped_option_cmd_keys, usage->code);
500-
if (trans) {
501-
input_event_with_scancode(input, usage->type,
502-
trans->to, usage->hid, value);
503-
return 1;
504-
}
505-
}
506-
507-
if (swap_fn_leftctrl) {
508-
trans = apple_find_translation(swapped_fn_leftctrl_keys, usage->code);
509-
if (trans) {
510-
input_event_with_scancode(input, usage->type,
511-
trans->to, usage->hid, value);
512-
return 1;
513-
}
502+
return 1;
514503
}
515504

516505
return 0;
@@ -640,9 +629,6 @@ static void apple_setup_input(struct input_dev *input)
640629
apple_setup_key_translation(input, apple2021_fn_keys);
641630
apple_setup_key_translation(input, macbookpro_no_esc_fn_keys);
642631
apple_setup_key_translation(input, macbookpro_dedicated_esc_fn_keys);
643-
644-
if (swap_fn_leftctrl)
645-
apple_setup_key_translation(input, swapped_fn_leftctrl_keys);
646632
}
647633

648634
static int apple_input_mapping(struct hid_device *hdev, struct hid_input *hi,

0 commit comments

Comments
 (0)