web-dev-qa-db-ja.com

特定の信号を外部USBキーボードに送信しますか?または、fdopen()を修正するにはどうすればよいですか?

背景:コマンドラインからコマンドを実行すると、コマンドで外部キーボードのCapsLockライトが点灯するようにしようとしています。理想的には、スクリプト化できるので、アラートなどに使用できます(キーボードを分解しました)。

私はそれが動作するはずのように見えるこのコマンドを手に入れました:

fd=fdopen("/dev/console"); ioctl(fd, 0x4B32, 0x04);

このコマンドをOSXまたは配置しているUbuntuサーバーのいずれかで実行しようとすると、次のようになります。

me@server1:~$ fd=fdopen("/dev/console"); ioctl(fd, 0x4B32, 0x04);
-bash: syntax error near unexpected token `('
me@server1:~$ fd=fdopen(/dev/console);
-bash: syntax error near unexpected token `('

したがって、問題は最初の部分にあるように見えます。ソフトウェア/ユーティリティのセットをインストールする必要がありますか?外部キーボードのCapsLockライトを手動で制御するにはどうすればよいですか?

6
Undo

あなたの問題は、Cコードをシェルプロンプトに入力しようとすることです。これは明らかな理由で機能しません。それを正しいCファイルに入れてコンパイルし、実行できる有効なバイナリを取得することができます。

#include <linux/kd.h>

#include <sys/ioctl.h>

#include <fcntl.h>
#include <unistd.h>

#include <err.h>
#include <stdio.h>
#include <stdlib.h>

static void
usage(char *argv0)
{
    fprintf(stderr, "Usage: %s <on|off>\n", argv0);
    exit(EXIT_FAILURE);
}

int
main(int argc, char *argv[])
{
    int fd;
    int on;
    unsigned char state;

    if (argc != 2)
        usage(argv[0]);

    if (strcmp(argv[1], "on") == 0)
        on = 1;
    else if(strcmp(argv[1], "off") == 0)
        on = 0;
    else
        usage(argv[0]);


    fd = open("/dev/console", O_RDWR);
    if (fd == -1)
        err(EXIT_FAILURE, "open /dev/console");

    if (ioctl(fd, KDGETLED, &state) == -1)
        err(EXIT_FAILURE, "KDGETLED");

    if (on)
        state |= LED_CAP;
    else
        state &= ~LED_CAP;

    if (ioctl(fd, KDSETLED, state) == -1)
        err(EXIT_FAILURE, "KDSETLED");

    close(fd);

    return 0;
}

これをたとえばというファイルに入れます。 caps.cそしてそれをコンパイルします:

$ gcc -o caps caps.c

次に、次のように実行できます

$ ./caps on

lEDをオンにするまたは

$ ./caps off

オフにします(切り替えは読者の練習問題として残されています)。

注:開くには/dev/consoleスーパーユーザー権限が必要です。

さらに別の注意:これにより、端末またはXサーバーがCapsLock LEDをときどき変更することも妨げられません(例: Caps が押されます)。これはOSXでも機能しませんが、これを行うための標準化された方法がないため、Linuxでのみ機能します。最後に、複数のキーボードのLEDを個別に変更することはできません。

6
Andreas Wiese

そのCコードはとにかく機能しません--fdopen()は複数の引数を必要とし、ファイル記述子ではなくファイルストリームを返します。

数年前にこれを行ったことを覚えています。Xlib経由で考えましたが、古いコードが見つかりませんでした(コレクションが削除されることがあります)が、誰かがgithubなどでこれを行うための簡単なアプリを持っている必要があると思いました。低くて見よ、私が最初に見つけたページは これ 投稿した記憶はないが、4年前に私が書いたものだった(「akashiraffee」は私がオンラインでよく使った名前だった時間)。

実際にはXlibを使用していません-あなたがやろうとしていたようにioctl()を使用しているので、GUIなしで動作するはずです。私はそれを片付けて、5LEDキーボードでここで試しました:

#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <linux/kd.h>
#include <sys/ioctl.h>

int main (void) {
    int tty = open("/dev/console", 0), led;
    unsigned long int arg;

    if (tty < 3) {
        perror("open: ");
        return -1;
    }

    if (ioctl(tty,KDGKBTYPE, &arg) > 0) perror("ioctl: ");
    if (arg == KB_101) puts("You have a 101 key keyboard.");

    for (led = 1; led < 9; led++) {
        if (ioctl(tty,KDSETLED, led) > 0) perror("ioctl led on: ");
        printf("LED %d on...hit enter", led);
        getchar();
        if (ioctl(tty,KDSETLED, led+0xff) > 0) perror("ioctl led off: ");
        printf("off (hit enter)\n");
        getchar();
    }

    close(tty);

    return 0;
} 

gcc whatever.c -o testledsをコンパイルしてから./testledsをコンパイルします(スーパーユーザー特権が必要です)。最初の7つは私のために働いた。それらのいくつかは個別のLEDであり、それらのいくつかは組み合わせです。

キーボードを分解しました

もちろん、それをテストするにはENTERが必要です。そうでない場合は、コメントを残してください。代わりに、遅延を使用して自動的にテストするように変更します。最終的に機能する場合は、番号でライトを切り替えるために使用できるものに変えていただければ幸いです(例:toggleLED 3)。

3
goldilocks

Linux

あなたが投稿したのはCコードのスニペットです。 (そして、機能するものでさえありません。)それはシェルプロンプトでは機能しません。

ioctlへのシェルインターフェースはありませんが、Perlを使用できます。

#!/usr/bin/Perl
require "sys/ioctl.ph";
if (@ARGV) {
    $ioctl = 0x4b32; # KDSETLED
    $ARGV[0] =~ /^[0-8]+$/ or die "$0: $ARGV[0]: invalid argument";
    $arg = int($ARGV[0]);
} else {
    $ioctl = 0x4b31; # KDGETLED
    $arg = "?";
}
sysopen CONSOLE, "/dev/console", "r" or die "$0: /dev/console: $!\n";
ioctl CONSOLE, $ioctl, $arg or die "$0: ioctl: $!\n";
print ord($arg), "\n" unless @ARGV;

またはPython:

#!/usr/bin/env python
import array, fcntl, os, sys
console = open("/dev/console", "r")
if len(sys.argv) > 1:
    fcntl.ioctl(console, 0x4b32, int(sys.argv[1])) # KDSETLED
else:
    arg = array.array('B', [0xff]) # KDGETLED
    fcntl.ioctl(console, 0x4b31, arg, True)
    print arg[0]

どちらのプログラムも、引数なしで実行された場合は現在のLED設定を出力し、引数が渡された場合はLEDを変更します。 LED設定は、Scroll Lockの場合は1、Num Lockの場合は2、CapsLockの場合は4の合計として表されます。引数8を渡すと、OSのロック設定に対応するようにLEDをリセットできます。

独自のプログラムを呼び出す代わりに、標準の コンソールツール から setleds ユーティリティを呼び出すこともできます。

テキストモードコンソール(Xの下でもリモートでもない)にログオンするか、rootとして実行する必要があります。

Linux、特定のキーボード

コンソールデバイスの代わりにそのデバイスにアクセスすることにより、特定の入力デバイスのLEDをオンまたはオフにすることもできます。 ioctlは異なります。 evdevインターフェース を使用して EV_LEDイベント

このインターフェースを使用する最も簡単な方法は、 evdev Pythonパッケージ(pip install evdev)。

</dev/input/by-id/usb-_USB_Keyboard-event-kbd \
python -c 'import evdev; dev = evdev.InputDevice("/dev/stdin"); print dev.leds()'

その他の例については、 チュートリアル の「LED状態の取得と設定」を参照してください。

OSX

Mac OS Xでは、 HIDインターフェイス を介してキーボードのLEDにアクセスできます。例と説明を見つけることができます Mac OS X Internals または サイキック折り紙