2013年11月1日金曜日

『ログオン後のNumLock状態はレジストリで制御できる』という大嘘

当記事はWindows7を対象に書いているので、他のバージョンでは動作に差異があるかもしれません。あらかじめご了承ください。
「NumLock状態を制御したい」という要件
ITインフラの(というか社内OA構築系の)仕事をしていると、顧客から「端末のNumLockは全台一律(On|Off)にしてよ」という要件が出ることがたまにある。
で、その方法をググると、「レジストリの値を変更すれば良い」という情報が山ほど出てくる。ところが、得られる情報は半分は正しくて、半分は嘘である。
ログオン画面(ようこそ画面)のNumLock状態はレジストリで制御可能
Windowsのログオン画面(=ようこそ画面)におけるNumLockの状態は
HKEY_USERS\.Default\Control Panel\Keyboard\InitialKeyboardIndicators
に値を書き込むことで制御できる。
余談だが、値はどうみても数値なのにString(REG_SZ)型で、初期値が2147483648という謎のエントリ(Int32の上限ですかね)。
値を0にするとNumLock Off、値を2にするとNumLock Onだ
(2進数のフラグになっていて、1がCapsLock On、4がScrollLock On)。
これは何の問題もない。
ログオン後のNumLock状態の制御は、単にレジストリを変更してもダメ!
問題は、ログオン後のNumLockキーの状態の制御である。
ググると
HKEY_CURRENT_USER\Control Panel\Keyboard\InitialKeyboardIndicators
に値を書き込めばいい、という情報が山ほど出てくるが、嘘。ここにはログオフ時にNumLock(だけでなくCapsLock、ScrollLock)の状態が記録される仕組みになっている。従って、あらかじめログオフ前に値を書き込んでおいても、ログオフ時に上書きされてしまう。
グループポリシーでレジストリに値を書き込めばイケるのか…? 否!
ログオフ前に書いてもダメなら、ログオン時に書き込めばいいんでは? ということで、グループポリシーでレジストリを変更するという発想に辿り着く人は沢山いるようで、ググると大量に情報が出てくる。しかしこれも嘘だ。
散々試行した末での結論だが、ログオン処理のシーケンスは下記の順番のようである。
  1. HKEY_CURRENT_USER\Control Panel\Keyboard\InitialKeyboardIndicatorsの値を読み取り、NumLockの状態を決める
  2. グループポリシーの適用処理が動き、レジストリが書き換わる

つまり、レジストリを書き換える前にNumLockの状態は既に決まっているのである。ダメじゃん。
結論はバッドノウハウ
半ば途方に暮れつつネットの大海原を漂っていたところ、ログオンスクリプト(VBScript)でNumLockをSendKeysするという技に辿り着いた。
ハッキリ言ってバッドノウハウだが仕方ない。
OKwaveの下記ページが参考になる。
vbscriptでNUMLOCK判定したい
現在のNumLockの状態をWordVBAのプロパティで取得するという荒業。マジでこんな情けない方法しかないのかね…。"Hey, Scripting Guy!"にも載ってるが。Word入れてない端末はどうすんだよ。
How Can Tell Whether the NumLock Key is On or Off? - Hey, Scripting Guy! Blog - Site Home - TechNet Blogs

とりあえず、上記OKwaveに載ってたコードに申し訳程度のエラーハンドルを入れておいた。下記はNumLockをOffにするコード。Onにしたい時は最終行のTrueをFalseにすればよい。
DIM NumOnBL
On Error Resume Next
Set objWord = CreateObject("Word.Application")
NumOnBL= objWord.NumLock
objWord.Quit
On Error Goto 0
set WshShell = CreateObject("WScript.Shell")
IF NumOnBL = True THEN WshShell.SendKeys "{NUMLOCK}"

0 コメント:

コメントを投稿