キーボードの LED の制御方法

[戻る]

Windows において, キーボードの LED の点灯を制御させたくなり, ちょっと調べてみました.

一番簡単な方法は, 仮想的にロックキーが押されたようにすることの ようです. 例えば Scroll Lock だと, 次のようにすれば LED が明滅します.

#include <windows.h>

int main(int argc, char **argv){
  for (int i=0;i < 10;i++){
    keybd_event(VK_SCROLL, 0, 0, 0);
    keybd_event(VK_SCROLL, 0, KEYEVENTF_KEYUP, 0);
    Sleep(500);

    keybd_event(VK_SCROLL, 0, 0, 0);
    keybd_event(VK_SCROLL, 0, KEYEVENTF_KEYUP, 0);
    Sleep(500);
  }
  return 0;
}

ScrollLock キーなんて, まず使わないからいいだろうと とある監視プログラムに組み込んでみたのですが, ある時別件で X-Deep/32 上で emacs を操作していると, いきなりビープ音が鳴り響きます. 「未定義のキーを押された」と解釈されたようです.

何か素敵な関数は無いかと色々探してみたのですが, I/O ポートを叩く原始的な方法しか解は無さそうです. とは言え, Xp 系ではプログラムから直接 I/O を叩けません.

似たようなものに, パラレルポートを入出力 I/O として使う問題が ありますが, こちらには GiveIO.sys という 便利な解があります. ある時, GiveIO.sys はパラレルポート周りの I/O (0x378〜a: 機種によって若干違う) を開放してるのでなく, inp(), outp() 全体を開放しているのでないかと 考え, 実験してみました.

予想は的中し, 無事以下のようなコードで LED のみを制御できるようになりました.

#include <windows.h>
#include <conio.h>

int main(int argc, char **argv){
  HANDLE h = CreateFile("\\\\.\\giveio", GENERIC_READ, 0, NULL,
	                OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);

  if (h == INVALID_HANDLE_VALUE) {
    fprintf(stderr, "Error: no giveio.sys\n");
    exit(0);
  }

  CloseHandle(h);

  for (int i=0;i < 10;i++){
    while (_inp(0x64) & 2);
    _outp(0x60, 0xed);
    while (_inp(0x64) & 2);
    _outp(0x60, 0x01);
    Sleep(500);

    while (_inp(0x64) & 2);
    _outp(0x60, 0xed);
    while (_inp(0x64) & 2);
    _outp(0x60, 0x00);
    Sleep(500);
  }
  return 0;
}
while 文でぶん回して CPU パワーを無駄食いしてますし, 最適化オプションによっては走らないかもしれません. これはあくまでテスト用コードですので, 実際は適当に工夫してください.

ちなみに, プログラムを 95/98/Me 系でも動かすためには HANDLE h= 〜 CloseHandle(h); の処理を NT/2000/Xp でのみ 走らせる必要があります. 判定は次のような感じでしょうか.

bool IsWindowsNT(){
  OSVERSIONINFOA *posvi = (OSVERSIONINFOA *)_alloca(sizeof(OSVERSIONINFOA));

  posvi->dwOSVersionInfoSize = sizeof(OSVERSIONINFOA);
  GetVersionExA(posvi);

  if(posvi->dwPlatformId == VER_PLATFORM_WIN32_NT)
    return true;
  return false;
}


[追記]: API を使う方法が分かりました(2011.1) → こちら
2006.10