Perché non funzionano
Secondo l'articolo di ArchWiki che hai citato:
-
Il server X riceve i codici chiave dal dispositivo di input e li converte nellostato e keysym .
-
stato è la maschera di bit dei modificatori X (Ctrl/Shift/etc).
-
keysym è (secondo
/usr/include/X11/keysymdef.h
) il numero interothatidentificare i caratteri o le funzioni associate a ciascun tasto (ad esempio, tramite l'incisione visibile) di un layout di tastiera.
Ogni carattere stampabile ha il proprio keysym, come
plus
,a
,A
, oCyrillic_a
, ma anche altre chiavi generano i propri keysym, comeShift_L
,Left
oF1
.
-
-
L'applicazione negli eventi di stampa/rilascio chiave ottiene tutte queste informazioni.
Alcune applicazioni tengono traccia dei keysym come
Control_L
da soli, altri semplicemente cercano i bit modificatori nello stato .
Quindi cosa succede quando premi AltGr +j :
-
Premi AltGr . L'applicazione ottiene l'evento KeyPressed con keycode108 (
<RALT>
) e keysym 0xfe03 (ISO_Level3_Shift
), lo stato è 0. -
Premi j (che esegue il mapping a "h" in dvorak senza modificatori). L'applicazione riceve l'evento KeyPressed con codice tasto 44 (
<AC07>
), keysym 0xff51(Left
) e stato 0x80 (il modificatore Mod5 è attivo). -
Rilasci j . L'applicazione riceve l'evento KeyRelease per la chiave
<AC07>
/Left
con gli stessi parametri. -
Poi rilascia AltGr — Evento KeyRelease per AltGr. (A proposito, lo stato qui è ancora 0x80, ma non importa.)
Questo può essere visto se esegui xev
utilità.
Quindi, tutto ciò significa che, sebbene l'applicazione ottenga lo stesso codice keysym(Left
) come dalla normale chiave <LEFT>
, ottiene anche il codice keysym e lo stato del modificatore da AltGr. Molto probabilmente, quei programmi che non funzionano, guardano i modificatori e non vogliono funzionare quando alcuni sono attivi.
Come farli funzionare
Apparentemente, non possiamo cambiare ogni programma per non cercare i modificatori. Quindi l'unica opzione per sfuggire a questa situazione è non generare keysyms e bit di stato dei modificatori.
1. Gruppo separato
L'unico metodo che mi viene in mente è:definire i tasti di movimento del cursore in un gruppo separato e passare, con una pressione di tasto separata, a quel gruppo prima di premere i tasti j , k , l , io (h
,t
, n
, c
) (la chiusura del gruppo è il metodo preferito per un cambio di gruppo una tantum, a quanto ho capito).
Ad esempio:
xkb_keymap {
xkb_keycodes { include "evdev+aliases(qwerty)" };
xkb_types { include "complete" };
xkb_compatibility {
include "complete"
interpret ISO_Group_Latch { action = LatchGroup(group=2); };
};
xkb_symbols {
include "pc+us(dvorak)+inet(evdev)"
key <RALT> { [ ISO_Group_Latch ] };
key <AC07> {
type[Group2] = "ONE_LEVEL",
symbols[Group2] = [ Left ]
};
key <AC08> {
type[Group2] = "ONE_LEVEL",
symbols[Group2] = [ Down ]
};
key <AC09> {
type[Group2] = "ONE_LEVEL",
symbols[Group2] = [ Right ]
};
key <AD08> {
type[Group2] = "ONE_LEVEL",
symbols[Group2] = [ Up ]
};
};
xkb_geometry { include "pc(pc104)" };
};
Ora, se prima premi AltGr e poi (separatamente) uno dei tasti di movimento, questo dovrebbe funzionare.
Tuttavia, questo non è molto utile, sarebbe più appropriato LockGroup
invece di bloccare e premere AltGr prima e dopo il cambio di gruppo. Ancora meglio forse a SetGroup
— quindi AltGr selezionerebbe quel gruppo solo mentre viene premuto, ma questo rivela alle applicazioni il keysym(ISO_Group_Shift
di AltGr /ISO_Group_Latch
/qualunque cosa sia definita) (ma il modificatore state rimane pulito).
Ma... c'è anche la possibilità che l'applicazione legga anche i keycode (i codici delle chiavi reali). Quindi noterà i tasti cursore "falsi".
2. Sovrapposizione
La soluzione più "di basso livello" sarebbe l'sovrapposizione (come descrive lo stesso articolo).
Sovrapponi significa semplicemente che un tasto (della tastiera reale) restituisce il codice tasto di un altro tasto. Il server X cambia il codice chiave di una chiave e calcola lo stato del modificatore e il keysym per quel nuovo codice chiave, quindi l'applicazione non dovrebbe notare il cambiamento.
Ma le sovrapposizioni sono molto limitate:
- Ci sono solo 2 bit di controllo dell'overlay nel server X (ovvero possono esserci al massimo 2 overlay).
- Ogni chiave può avere solo 1 codice chiave alternativo.
Per quanto riguarda il resto, l'implementazione è abbastanza simile al metodo con un gruppo separato:
xkb_keymap {
xkb_keycodes { include "evdev+aliases(qwerty)" };
xkb_types { include "complete" };
xkb_compatibility {
include "complete"
interpret Overlay1_Enable {
action = SetControls(controls=overlay1);
};
};
xkb_symbols {
include "pc+us(dvorak)+inet(evdev)"
key <RALT> {
type[Group1] = "ONE_LEVEL",
symbols[Group1] = [ Overlay1_Enable ]
};
key <AC07> { overlay1 = <LEFT> };
key <AC08> { overlay1 = <DOWN> };
key <AC09> { overlay1 = <RGHT> };
key <AD08> { overlay1 = <UP> };
};
xkb_geometry { include "pc(pc104)" };
};
SetControls
significa modificare il bit di controllo mentre il tasto è premuto e ripristinarlo al rilascio del tasto. Dovrebbe esserci una funzione simile LatchControls
, maxkbcomp
mi dà
Error: Unknown action LatchControls
sulla compilazione della mappa dei tasti.
(A proposito, uso anche dvorak e ho anche rimappato alcuni simboli di tasti di movimento ad alti livelli di tasti alfabetici. E ho anche riscontrato alcune funzionalità interrotte (selezione nelle note di Xfce e cambio desktop con Ctrl-Alt-Sinistra/Destra). Grazie alla tua domanda e questa risposta, ora so cos'è un overlay :).)
Come farli funzionare - Soluzione 3
Utilizzo di livelli aggiuntivi e Action RedirectKey
La seguente soluzione utilizza il tasto Alt sinistro per fornire i tasti cursore su jkli, Home/Fine/PaginaSu/PaginaGiù su uopö e Canc su Backspace.
Il tasto Alt sinistro rimane utilizzabile per altri scopi per tutti gli altri tasti (come per il menu dell'applicazione). L'Alt sinistro (Mod1) viene rimosso dallo stato del modificatore quando viene utilizzato il blocco del cursore in modo che le applicazioni non possano vederlo.
xkb_keymap {
xkb_keycodes {
include "evdev+aliases(qwertz)"
};
xkb_types {
include "complete"
};
xkb_compat {
include "complete"
interpret osfLeft {
action = RedirectKey(keycode=<LEFT>, clearmodifiers=Mod1);
};
interpret osfRight {
action = RedirectKey(keycode=<RGHT>, clearmodifiers=Mod1);
};
interpret osfUp {
action = RedirectKey(keycode=<UP>, clearmodifiers=Mod1);
};
interpret osfDown {
action = RedirectKey(keycode=<DOWN>, clearmodifiers=Mod1);
};
interpret osfBeginLine {
action = RedirectKey(keycode=<HOME>, clearmodifiers=Mod1);
};
interpret osfEndLine {
action = RedirectKey(keycode=<END>, clearmodifiers=Mod1);
};
interpret osfPageUp {
action = RedirectKey(keycode=<PGUP>, clearmodifiers=Mod1);
};
interpret osfPageDown {
action = RedirectKey(keycode=<PGDN>, clearmodifiers=Mod1);
};
interpret osfDelete {
action = RedirectKey(keycode=<DELE>, clearmodifiers=Mod1);
};
};
xkb_symbols {
include "pc+de(nodeadkeys)"
include "inet(evdev)"
include "compose(rwin)"
key <LALT> {
type[Group1] = "ONE_LEVEL",
symbols[Group1] = [ ISO_Level5_Shift ]
};
modifier_map Mod1 { <LALT> };
key <AC07> {
type[Group1] = "EIGHT_LEVEL_SEMIALPHABETIC",
symbols[Group1] = [ j, J, dead_belowdot, dead_abovedot, osfLeft, osfLeft, osfLeft, osfLeft ]
};
key <AC08> {
type[Group1] = "EIGHT_LEVEL_SEMIALPHABETIC",
symbols[Group1] = [ k, K, kra, ampersand, osfDown, osfDown, osfDown, osfDown ]
};
key <AC09> {
type[Group1] = "EIGHT_LEVEL_ALPHABETIC",
symbols[Group1] = [ l, L, lstroke, Lstroke, osfRight, osfRight, osfRight, osfRight ]
};
key <AC10> {
type[Group1] = "EIGHT_LEVEL_SEMIALPHABETIC",
symbols[Group1] = [ odiaeresis, Odiaeresis, doubleacute, doubleacute, osfPageDown, osfPageDown, osfPageDown, osfPageDown ]
};
key <AD07> {
type[Group1] = "EIGHT_LEVEL_SEMIALPHABETIC",
symbols[Group1] = [ u, U, downarrow, uparrow, osfBeginLine, osfBeginLine, osfBeginLine, osfBeginLine ]
};
key <AD08> {
type[Group1] = "EIGHT_LEVEL_SEMIALPHABETIC",
symbols[Group1] = [ i, I, rightarrow, idotless, osfUp, osfUp, osfUp, osfUp ]
};
key <AD09> {
type[Group1] = "EIGHT_LEVEL_ALPHABETIC",
symbols[Group1] = [ o, O, oslash, Oslash, osfEndLine, osfEndLine, osfEndLine, osfEndLine ]
};
key <AD10> {
type[Group1] = "EIGHT_LEVEL_ALPHABETIC",
symbols[Group1] = [ p, P, thorn, THORN, osfPageUp, osfPageUp, osfPageUp, osfPageUp ]
};
key <BKSP> {
type[Group1] = "EIGHT_LEVEL_ALPHABETIC",
symbols[Group1] = [ BackSpace, BackSpace, BackSpace, BackSpace, osfDelete, osfDelete, osfDelete, osfDelete ]
};
};
xkb_geometry {
include "pc(pc105)"
};
};
Ho lo stesso problema. È così doloroso.
Quindi il titolo è "Come fare in modo che tutte le applicazioni rispettino il mio layout xkb modificato?". Bene, penso che l'unico modo sia riparare tutti i programmi che lo fanno in modo errato. Facciamolo!
Bene, dopo aver segnalato quel bug in NetBeans (Aggiornamento:ho provato l'ultima versione e ora funziona! ), ho pensato che avrei continuato a segnalare questo bug per ogni applicazione. L'applicazione successiva nell'elenco è stata Speedcrunch .
Tuttavia, dopo aver cercato segnalazioni di bug simili, ho riscontrato questo problema. Qualcun altro ha lo stesso problema, fantastico!
Dopo aver letto i commenti capirai che questo bug dovrebbe essere presente in tutte le app QT. Ecco una segnalazione di bug QT. Non risolto, ma sembra che il problema sia stato risolto in Qt5 .
Tuttavia, se guardi i commenti, c'è una soluzione alternativa! Ecco come funziona. Se stavi facendo questo:
key <SPCE> { [ ISO_Level3_Shift ] };
Quindi puoi cambiarlo in questo:
key <SPCE> {
type[Group1]="ONE_LEVEL",
symbols[Group1] = [ ISO_Level3_Shift ]
};
E risolverà effettivamente il problema per alcune delle applicazioni! Ad esempio, Speedcrunch ora funziona per me! Evviva!
Riepilogo
In questo momento qualsiasi applicazione dovrebbe funzionare correttamente. In caso contrario, devi utilizzare type[Group1]="ONE_LEVEL"
. Se lo hai già, devi aggiornare il tuo software. Se continua a non funzionare, è specifico dell'app e devi inviare una segnalazione di bug.
AGGIORNAMENTO (23-09-2017)
Ad oggi tutte le applicazioni rispettano il layout della mia tastiera. Tutti tranne uno.
Seriamente, la gestione della tastiera in Chromium è spazzatura . Ci sono diversi problemi con esso:
- La selezione dello spostamento non funziona con i tasti freccia personalizzati (ma i tasti freccia stessi funzionano bene)
- Se hai più layout e su uno dei layout qualche tasto è speciale (ad es. Frecce, Backspace, ecc.), allora su un altro layout questo tasto sarà fissato a quello che hai sul tuo primo layout. Ad esempio, se hai due layout:
foo
,bar
e alcuni tasti fanno Backspace infoo
, quindi continuerà a funzionare come Backspace inbar
anche se lì viene ridefinito.
Per anni ho ignorato questi problemi semplicemente non usando il cromo. Tuttavia, al giorno d'oggi le cose tendono a utilizzare Electron, che purtroppo è costruito su Chromium.
Il modo giusto per risolvere questo problema sarebbe inviare una segnalazione di bug in Chromium e sperare per il meglio. Non so quanto tempo impiegheranno a risolvere un problema che riguarda solo un paio di utenti... ma sembra essere l'unica via d'uscita. Il problema con questo è che il cromo in realtà funziona bene con neo(de)
disposizione. Il layout Neo ha i tasti freccia al livello 5, ma non riesco a farlo funzionare nel mio layout personalizzato.
Segnalazioni di bug ancora aperte:
- Pluma – https://github.com/mate-desktop/pluma/issues/17