ModefierKeyを取得する

艦板-KanPan-では起動時にShiftキー/Ctrlキーの押し下げ状態を見てキャッシュやCookieを消去しつつ起動できたりする。この動作はもともとOptionキーを押しながらクリックしたり実行したりすると振る舞いが変わるiTunesやAirMac Utilityに触発された小技だ・・・が、ではどうやってこれらのModefierKey状態を取得する?


    OSXの場合

    OSXの場合、AppKit/FrameworkのNSEvent->modifierFlagsを利用することでModefierKeyのビットフラグ値1を取得することが出来る。OSX付属のPerlやPythonにはAppKitのバインディングが標準でインストールされているため、例えばPerlでは以下のようにすればビットフラグ値を標準出力へ返すことが出来る。コメント他を除けば実質5行だ。

    #!/usr/bin/perl
    
    =comment=
    enum {  
       NSAlphaShiftKeyMask  = 1 << 16,
       NSShiftKeyMask       = 1 << 17,
       NSControlKeyMask     = 1 << 18,
       NSAlternateKeyMask   = 1 << 19,
       NSCommandKeyMask     = 1 << 20,
       NSNumericPadKeyMask  = 1 << 21,
       NSHelpKeyMask        = 1 << 22,
       NSFunctionKeyMask    = 1 << 23,
       NSDeviceIndependentModifierFlagsMask  = 0xffff0000U 
    };
    =cut=
    
    use strict;  
    use warnings;  
    use Foundation;
    
    @NSEvent::ISA = qw(PerlObjCBridge);
    
    my $AppKit = '/System/Library/Frameworks/AppKit.framework';  
    NSBundle->bundleWithPath_($AppKit)->load;
    
    print +(NSEvent->modifierFlags);  
    exit 0;
    
    __END__  
    

    Bashスクリプト等からModefierKey状態を扱いたい場合はこのスクリプトコマンドを呼び出せば充分用が足りる。

    #/bin/bash
    printf '%x¥n' $(modefierkey.pl)  
    
    #/bin/bash
    (($(modefierkey.pl) && 2**17)) && echo ShiftDown || echo ShiftUp
    

    Windowsの場合

    前述のコードを Windows Visual Basic2 に転写すると次のようになる。OSXで言うcommandキー、fnキーに相当するものはないが、代わりにScrollLockキーを取得することが出来る。

    Module Module1
    
        Sub Main()
    
            'OSX Cocoa
            'enum {
            '   NSAlphaShiftKeyMask  = 1 << 16,
            '   NSShiftKeyMask       = 1 << 17,
            '   NSControlKeyMask     = 1 << 18,
            '   NSAlternateKeyMask   = 1 << 19,
            '   NSCommandKeyMask     = 1 << 20,
            '   NSNumericPadKeyMask  = 1 << 21,
            '   NSHelpKeyMask        = 1 << 22,
            '   NSFunctionKeyMask    = 1 << 23,
            '   NSDeviceIndependentModifierFlagsMask  = 0xffff0000U 
            '};
    
            Dim intMask As Integer = 0
    
            If My.Computer.Keyboard.CapsLock Then
                intMask += 1 << 16
            End If
            If My.Computer.Keyboard.ShiftKeyDown Then
                intMask += 1 << 17
            End If
            If My.Computer.Keyboard.CtrlKeyDown Then
                intMask += 1 << 18
            End If
            If My.Computer.Keyboard.AltKeyDown Then
                intMask += 1 << 19
            End If
            If My.Computer.Keyboard.NumLock Then
                intMask += 1 << 21
            End If
            If My.Computer.Keyboard.ScrollLock Then
                intMask += 1 << 24
            End If
    
            Console.Write(intMask)
        End Sub
    
    End Module  
    

    Nw.jsの場合

    そもそもコンソールプラットフォームであるNode.jsではModefierKeyを取得する手段は用意されていない3が、Nw.jsではGUIウィンドウが存在するのでそちらのwindow.eventからAlt/Ctrl/Shiftの3種類のキー状態真偽値を取得することが出来る。ChromiumベースのGUIプラットフォームなのだからこれは出来て当然だ。

    &lt;script language="javascript"&gt;
    switch (true) {  
      case window.event.altKey   : console.log('altKey');   break;
      case window.event.ctrlKey  : console.log('ctrlKey');  break;
      case window.event.shiftKey : console.log('shiftKey'); break;
    }
    &lt;/script&gt;
    

    ただし注意が必要なのは、ウィンドウ本体を示すwindowグローバルオブジェクトはGUI内の<script>タグでロードされたコードのほうにしか継承されていない点4だ。つまりpackage.jsonのnode-mainでバックグラウンドロードされたNode.jsネイティブなコードの方からは直接使えない。また当然のことながらウィンドウ表示前・初期化前にはこれらのキー状態を取得出来ないという制約もある。故に「Altキーを押しながらドロップダウンメニューを開いた場合は内容をかえる」といった使いドコロになる。


    艦板ではどうしたか

    艦板では結局GUI初期化前にModefierKey状態をしたかったので、外部コマンドを child_process.execSync() で呼び出して結果を得るようになっている。ちなみにこの時の動作はWindows版の場合;

    • ModefierKeyを調べて押されていなければそのまま起動継続する
    • ModefierKeyが押されていた場合でも、キャッシュクリア済であったならそのまま起動継続する
    • キャッシュクリアされていなかったら外部キャッシュクリアコードにexecして自分は終了する
    • 外部キャッシュクリアコード5は自分でModefierKeyを再確認し、キャッシュフォルダを掃除したあとに艦板をexecして自身は終了する

    ・・・などと存外面倒なことをやっている。


    1. キーとビット値の対応とcocoaでの名称はコメントを参照して頂きたいが、AlphaShiftKeyはcaps/CapsLockキー、AlternateKeyはalt/option/appleキーのことである。

    2. 要コンパイル。VS Express版だと for Desktopエディションが必要。

    3. プラットフォーム別に全く異なる実装をビルドする必要があるし、そもそもNode.jsの主戦場はCLIやサーバホスティング用途なので、ModefierKeyを見る要件は殆ど無い。なのでこれが必要になるのはNw.jsのようなGUIフレームワークと組み合わせた場合に概ね限られるといえる。

    4. 親ウィンドウが生成される前から動き出すインスタンスなので継承しようがないとも言える。だが単に継承されていないから使えないだけなので、知ってるほう(GUI)が知らないほう(Native)に module.exports 経由で教えてやれば利用できる。同様にNw.jsのguiオブジェクトも教えてやればバックグラウンド側から各種ウィンドウ操作ができる。

    5. Windows版同梱のWinRapper.exeがそれ。OSXのほうは Info.plistに登録された Bashシェル (launch.sh) が modefierkey.pl を呼び出し、必要ならキャッシュ削除処理をしてから Nw.js を起動する段取りだからずっとシンプルだ。

    RECENT LINKS