在X会话中无需根访问权限即可更改键盘指示灯的状态


10

我正试图强制启动大写锁定。xset不适用于我,因此我正在尝试使用setleds

在图形控制台中,此命令返回:

> LANG=C setleds -L +caps
KDGKBLED: Inappropriate ioctl for device
Error reading current flags setting. Maybe you are not on the console?

在虚拟终端中,它可以工作,但是效果是该虚拟终端本地的。据我了解,跑步

> setleds -L +caps < /dev/tty1

从虚拟终端(我的X服务器坐在tty1上)应该可以正常工作。但是,这需要root访问。

有没有一种方法可以将命令发送到X服务器下面的控制台,是从所说的xserver还是从另一个VT(没有root)发送的命令?

编辑:根据Mark Plotnik的建议,并根据此处找到的代码,我编写并编译了以下内容:

#include <X11/Xlib.h>
#include <X11/XKBlib.h>

#define SCROLLLOCK 1
#define CAPSLOCK 2
#define NUMLOCK 16

void setLeds(int leds) {
   Display *dpy = XOpenDisplay(0);
   XKeyboardControl values;
   values.led_mode = leds & SCROLLLOCK ? LedModeOn : LedModeOff;
   values.led = 3;
   XChangeKeyboardControl(dpy, KBLedMode, &values);
   XkbLockModifiers(dpy, XkbUseCoreKbd, CAPSLOCK | NUMLOCK,
                    leds & (CAPSLOCK | NUMLOCK) );
   XFlush(dpy);
   XCloseDisplay(dpy);
}

int main() {
   setLeds(CAPSLOCK);
   return 0;
}

从Gilles所写的内容来看xset,我没想到它会起作用,但是从某种意义上说,它确实起作用了:它设置了led,但同时也设置了大写锁定状态。我不完全理解上面的所有代码,因此我可能犯了一个愚蠢的错误。显然,该行XChangeKeyboardControl...不会更改程序的行为,XkbLockModifiers而是设置led和capslock状态的原因。


您可以xdotool key Caps_Lock从授权的X客户端执行类似操作,尽管这实际上会打开大写锁定。
Mark Plotnick

@MarkPlotnick重点确实是不要打开CapsLock。有没有办法关闭CapsLock,而无需触摸LED?
T. Verron

我查看了xterm源代码,它使用了对XChangeKeyboardControl()的调用来设置或取消设置LED,而不会影响大写锁定等的状态。因此,如果可以编译C代码,那是一种方法。
Mark Plotnick

@MarkPlotnick是否xterm会影响led?听起来是个好主意,我将使用结果来编辑问题。
T. Verron

我必须xterm通过发送转义序列ESC [3 q来点亮ScrollLock LED ctlseqs.txt,根据源附带的文件,但是无法使Num或CapsLock LED亮起并带有参数1和2。也许我需要做答案中提到的XKB配置。xterm电话XChangeKeyboardControlxtermShowLEDxtermClearLEDs,但不调用XkbLockModifiers所有的任何地方。
Mark Plotnick

Answers:


7

原则上,您应该能够使用古老的xset命令来做到这一点。

xset led named 'Caps Lock'

xset led 4设置LED编号4(如果系统无法按名称识别LED)。

但是,这似乎无法可靠地工作。在我的机器上,我只能以这种方式设置“滚动锁定”,而我并不是唯一的一个。这似乎是XKB配置的问题

以下用户级别的变通办法应该起作用(大部分情况下):

  1. 提取您当前的xkb配置:

    xkbcomp $DISPLAY myconf.xkb
    
  2. 编辑文件myconf.xkb,在相关块中替换!allowExplicitallowExplicit

    indicator "Caps Lock" {
        allowExplicit;
        whichModState= locked;
        modifiers= Lock;
    };
    indicator "Num Lock" {
        allowExplicit;
        whichModState= locked;
        modifiers= NumLock;
    };
    
  3. 加载新文件

    xkbcomp myconf.xkb $DISPLAY
    

现在,打开和关闭LED灯xset应该可以工作了。根据错误报告,您应该在应该打开LED时将其关闭(例如,如果启用了CapsLock)。


谢谢!我xset之前曾尝试过,但实际上不起作用。我没有看到此错误报告。无论如何,“状态:已解决的Wontfix”并不真正令人鼓舞... allowExplicit解决方法可能对我有用(我不需要关闭led),但是更改它仍然需要root。
T. Verron

@ T.Verron您不需要是root用户即可更改XKB配置。您可以随时打电话xkbcomp。我对XKB不够熟悉,无法确切地告诉您需要更改的内容(使用XKB设置特定方面而不是完整的预定义映射有些麻烦),但是unix.stackexchange.com/questions/166844/mapping -key-bindings /…应该有一些指针。
吉勒斯(Gilles)'所以

哦,好点。好吧,作为第一次尝试,我尝试了:xkbcomp $DISPLAY output.xkb,然后在部分中替换!allowExplicit为,然后使用重新加载文件。有很多警告,之后xset不会更好。我将阅读有关xkb的更多信息。allowExplicitindicator "Caps Lock"xkbcomp output.xkb
T. Verron

1
这种为我工作。导入修改后的文件后,我收到一些错误消息,并且可以点亮LED,但其他东西弄乱了,而且重启后仍然无法正常工作。因此,我继续进行编辑/usr/share/X11/xkb/compat/ledcaps和... / lednum,这使其永久化。
jtgd18年

0

使用 sed

$ sudo sed -i 's|\!allowExplicit|allowExplicit|g' /usr/share/X11/xkb/compat/ledcaps

注销并再次登录后,Caps Lock现在可以root使用以下命令在没有任何特权的情况下控制LED :

$ xset led named 'Caps Lock'
$ xset -led named 'Caps Lock'

但这需要root。
T. Verron

@ T.Verron仅一次使用更改配置文件,sudo然后再也不会更改。要了解为什么这对于某些用户可能如此重要,请参阅此vim应用程序
Serge Stroobandt

作为3年前问这个问题的人,我绝对理解为什么它对某些用户来说很重要(在我的情况下,这是要解决的问题是,在重新激活大写锁以进行控制之后,激活大写锁时苹果键盘会出现愚蠢的延迟)。但是那时候,我特别需要一个根本没有root用户访问权限的解决方案,因为它是用于工作计算机的。可接受的答案涉及更多步骤,但无需sudo即可使用。
T. Verron '18

@ T.Verron我明白。共享系统是另一种不起作用的情况。尽管如此,我还是喜欢最后一个评论者在接受的答案上的直截了当,并sed从中得出一个整体。
Serge Stroobandt '18年

0

@Gilles的无根方法与@Serge_Stroobandt的完全自动化思想的结合。

要控制Caps LockNum LockShift Lock LED:

#!/bin/bash
# Enables to control keyboard LEDs that are not available for control by default
xkbcomp $DISPLAY /tmp/my_conf.xkb
cat /tmp/my_conf.xkb | awk -e '
    BEGIN {
        change = 0
    }

    {
        if (change == 1) {
            if ($1 == "!allowExplicit;") {
                gsub("!", "", $0)
            }
            change = 0
        }
        print $0

    }

    /indicator "Caps Lock"/ {
        change = 1
    }
    /indicator "Num Lock"/ {
        change = 1
    }
    /indicator "Shift Lock"/ {
        change = 1
    }
    ' > /tmp/my_conf_modified.xkb
xkbcomp /tmp/my_conf_modified.xkb $DISPLAY

要打开和关闭LED:

# Turns the LED on
xset led named 'Caps Lock'

# wait 1s
sleep 1

# Resets the LED to the actual state,
# so it might still be on, if Caps Lock is activated.
xset -led named 'Caps Lock'
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.