libxkbcommon icon indicating copy to clipboard operation
libxkbcommon copied to clipboard

How to clear modifier without RedirectKey?

Open sandangel opened this issue 5 years ago • 8 comments

Hi, I'm trying to remap Super+C to Ctrl+C using xkb, but I don't want to remap Super to Ctrl because I'm still using Super for other shortcuts. I have achieved this X using interpret F13 { RedirectKey(keys=c,modifiers=Control,clearmodifiers=Super) } and set symbols c to [c, C, F13]

I have tried set symbols c to [c, C, XF86Copy] on Mod4 xkb type but XF86Copy doesn't work with some applications because I still have modifier Super set when pressing Super+C

It would be great to have a way to clear modifier without using RedirectKey, or should I do something else.

sandangel avatar May 08 '20 18:05 sandangel

Implementing full support of RedirectKey is unlikely, see #18. While I re-assess some parts of this feature, you may to have a look at solutions like kmonad, keyd, Kanata and the likes.

wismill avatar Nov 07 '23 05:11 wismill

I use the neo layout and layer 4 (the navigation layer) uses modifiers to input arrow keys, return, backspace, delete and home/end. I use the following xkb_keymap file to clear modifiers, because some applications will not interpret arrow keys etc as such when input with modifiers:

xkb_keymap {
  xkb_keycodes  {
        //source https://unix.stackexchange.com/questions/188164/override-a-few-keycodes-with-xkb#188179
        include "evdev+aliases(qwerty)"
        //Custom changes for hp elitebook 8470p
        <LCTL> = 64; // LALT
        <LALT> = 37; // LCTL
        <RTSH> = 133; // LWIN
        <LALT> = 108; //RALT
        <LWIN> = 135; //COMP
        };
  xkb_types     {  include "complete"  };
  xkb_compat {
        include "complete+caps(caps_lock)+misc(assign_shift_left_action)+level5(level5_lock)"
        interpret osfLeft {
            action = RedirectKey(keycode=<LEFT>, clearmods=Mod3);
        };
        interpret osfRight {
            action = RedirectKey(keycode=<RGHT>, clearmods=Mod3);
        };
        interpret osfUp {
            action = RedirectKey(keycode=<UP>, clearmods=Mod3);
        };
        interpret osfDown {
            action = RedirectKey(keycode=<DOWN>, clearmods=Mod3);
        };
        interpret osfBeginLine {
            action = RedirectKey(keycode=<HOME>, clearmods=Mod3);
        };
        interpret osfEndLine {
            action = RedirectKey(keycode=<END>, clearmods=Mod3);
        };
        // interpret osfPageUp {
        //     action = RedirectKey(keycode=<PGUP>, clearmods=Mod3);
        // };
        // interpret osfPageDown {
        //     action = RedirectKey(keycode=<PGDN>, clearmods=Mod3);
        // };
        interpret osfDelete {
            action = RedirectKey(keycode=<DELE>, clearmods=Mod3);
        };
        interpret osfBackSpace {
            action = RedirectKey(keycode=<BKSP>, clearmods=Mod3);
        };
        interpret osfReturn {
            action = RedirectKey(keycode=<RTRN>, clearmods=Mod3); //doesn't work (no clue why)
        };
    };
  xkb_symbols   {
      include "pc+de(neo)+inet(evdev)+terminate(ctrl_alt_bksp)+group(lwin_toggle)"

      //Bypass modifiers to directly input movement keys
      key.type[Group1] = "EIGHT_LEVEL_ALPHABETIC_WITH_LEVEL5_LOCK";

      key <AD02> { [ v,                       V,                       underscore,              NoSymbol,                osfBackSpace,               osfBackSpace,               radical,                 NoSymbol                 ]
      };
      key <AD03> { [ l,                       L,                       bracketleft,             Greek_lambda,            osfUp,                      osfUp,                      Greek_LAMBDA,            NoSymbol                 ]
      };
      key <AD04> { [ c,                       C,                       bracketright,            Greek_chi,               osfDelete,                  osfDelete,                  U2102,                   NoSymbol                 ]
      };


      key <AC01> { [ u,                       U,                       backslash,               lessthanequal,                osfBeginLine,                    osfBeginLine,                    includedin,              NoSymbol                 ]
      };
      key <AC02> { [ i,                       I,                       slash,                   Greek_iota,              osfLeft,                    osfLeft,                    integral,                NoSymbol                 ]
      };
      key <AC03> { [ a,                       A,                       braceleft,               Greek_alpha,             osfDown,                    osfDown,                    U2200,                   NoSymbol                 ]
      };
      key <AC04> { [ e,                       E,                       braceright,              Greek_epsilon,           osfRight,                   osfRight,                   U2203,                   NoSymbol                 ]
      };
      key <AC05> { [ o,                       O,                       asterisk,                Greek_omicron,           osfEndLine,                     osfEndLine,                     elementof,               NoSymbol                 ]
      };

      //custom greaterthanequal
      key <AB01> { [ udiaeresis,              Udiaeresis,              numbersign,              greaterthanequal,                Escape,                  Escape,                  union,                   NoSymbol                 ]
      };

      key <AB04> { symbols[Group1]=[ p,                       P,                       asciitilde,              Greek_pi,                Return,                  Return,                  Greek_PI,                NoSymbol                 ],
                   actions[Group1]=[NoAction(),NoAction(),NoAction(),NoAction(),RedirectKey(keycode=<RTRN>, clearmods=Mod3),RedirectKey(keycode=<RTRN>, clearmods=Mod3),NoAction(),NoAction()]};


  };
  xkb_geometry  { include "pc(pc104)" };
};

cxandru avatar Nov 07 '23 09:11 cxandru

I am using Vim-like arrow keys as detailed in the Arch Wiki. This also only needs the support for clearing modifiers.

hadabascus avatar Mar 07 '24 16:03 hadabascus

My usecase for clearMods: I'm trying to make <CTRL>+<LEFT> jump to the beginning of the line on my laptop that doesn't have reachable Home button: so I want <CTRL>+<LEFT> act as <Home>, but not act as <CTRL>+<Home> (which jumps to the beginning of the page by default).

On X this could be done with:

    override key <LEFT> {
        type = "PC_CONTROL_LEVEL2",
        repeat = Yes,
        symbols[Group1] = [ Left, NoSymbol ],
        actions[Group1] = [ NoAction(), RedirectKey(key=<HOME>, clearMods=Control) ]
    };

On Wayland I have not yet found a viable option (without clearMods).

notnout avatar May 29 '24 18:05 notnout

I also need clearmods because I've mapped my cursor keys to the home row and Chrome and other apps like Gnome file manager seem to look at keycodes and not keysyms. For Chrome, I can make it use X11 as a workaround (using ozone setting).

ronny-rentner avatar Jun 26 '24 09:06 ronny-rentner

@ronny-rentner have you reported the issue to the respective projects? Their keyboard handling looks wrong.

Meanwhile, you may want to have a look at solutions such as KMonad, keyd, Kanata and the likes.

wismill avatar Jun 26 '24 15:06 wismill

@wismill Last time I checked, only very few apps handled keyboard correctly. Creating issues in hundreds of projects is a waste of time, they will not be fixed. This really needs to be fixed here.

hadabascus avatar Jun 26 '24 16:06 hadabascus

So I checked if we could implement at least the clearMods feature: unfortunately it is not possible.

XOrg implement RedirectKey by sending key event with modified keycode and modifiers, then restoring the state, but we cannot: we do not send key events, we only update a global state, which affect all keys.

So this is a feature that should be implemented at compositor level.

@whot @bluetech we could, however, add new minimal API:

  • XKB_STATE_REDICTECT_KEY to xkb_state_component and add it to the return value of xkb_state_update_key. This new “component” is not stored, it merely indicates there is a key redirection to (optionally) handle.
  • xkb_state_key_get_redirect(state, key, keycode_out, mods…) to get the new keycode and mods changes.

Then the compositor may detect there is a key redirection looking for XKB_STATE_REDICTECT_KEY and handle it with the new API, or ignore it completely. Handling it requires some work:

  • storing old mod state
  • computing new mod state
  • sending mod & key event
  • restoring state
  • sending current mod state.

Is it likely that compositors will implement this? We would need to consult at least KDE & Gnome.

wismill avatar Jul 12 '24 04:07 wismill