The next JAVA library(4)

次は、キー入力の、機種依存部分について考えてみます。
auVodafoneは、MIDPなので、同じ形で処理することが出来ますが、DoCoMoは独自仕様のため、別の書き方をしなければなりません。

//au,vodafone
public void keyPressed(int keyCode){
    //キーが押されたときの処理
}
public void keyReleased(int keyCode){
    //キーが離されたときの処理
}

//DoCoMo
public void processEvent(int type, int param){
    if(type==Display.KEY_PRESSED_EVENT){
        //キーが押されたときの処理
    else if(type==Display.KEY_RELEASED_EVENT){
        //キーが離されたときの処理
    }
}

分け方は、プリプロセッサで分けます。
自分の場合であれば、それぞれの機種用のMakefileからプリプロセッサをかける際に、-Dオプションに、機種判別用の名前を定義しています。
これでキー入力の機種ごとの操作はおしまい。


……そんなわけありません(・∀・)
ここで問題になるのが、ソフトキーの入力。
DoCoMoは、processEventから取得できますが、MIDPは、CommandListenerというインターフェースクラスに、ソフトキーの入力が入ってきます。
しかも、ソフトキー1、ソフトキー2という形で入ってくるのではなく、MIDPのソフトキーの実体である、Commandクラスが渡されます。
なので、処理的には、

public void commandAction(Command c, Displayable d){
    if(c == /*ソフトキー1*/ ){
        realKey |= CKEY_SOFT1;
    }else if(c == /*ソフトキー2*/ ){
        realKey |= CKEY_SOFT2;
    }
}

こんな感じになります。
しかし、問題は、どうやってソフトキー1とソフトキー2を判定させるかです。
もし、コマンドの数だけ最初に用意すると、判定分が少々ややこしくなりますし、それに汎用的では無くなるので、ライブラリとして成り立ちません。
なので、ここは、最初からCommandを2つしか用意しないことにします。
そして、ラベルの変更の仕方ですが、addCommandやremoveCommandは機種依存の機能なのでこの方法ではやりません。それに、これって相当使い勝手が悪いです(;´Д`)
どっちかっていうと、DoCoMoのsetSoftLabelの方が優れていると思うので、そちらの方法に合わせます。

//au,Vodafone用の処理
#define ef else if
//2つしか使わない
private Command[] command = {
    new Command("", Command.SCREEN, 1),
    new Command("", Command.BACK, 2),
};

//リスナのセットと、何も書いていないコマンドをaddCommand()する
{
    setCommandListener(this);
    addCommand(command[0]);
    addCommand(command[1]);
}

public void commandAction(Command c, Displayable d){
    if(c == command[0]){
        keyPressed(CKEY_SOFT1);
    }ef(c == command[1]){
        keyPressed(CKEY_SOFT2);
    }
}

public void _setLabel(int n, String s){
    if(n == CKEY_SOFT1) n = 0;
    ef(n == CKEY_SOFT2) n = 1;
    else return;
    if(n == 1){
        removeCommand(command[1]);
        command[1] = new Command(s, Command.BACK, 2);
        addCommand(command[1]);
    }ef(n == 0){
        //CKEY_SOFT1の場合は両方ともremoveCommand()
        //してからaddCommand()する
        removeCommand(command[1]);
        removeCommand(command[0]);
        command[0] = new Command(s, Command.SCREEN, 1);
        addCommand(command[0]);
        addCommand(command[1]);
    }
}

protected void _remLabel(int n){
    _setLabel(n, "");
}

protected String _getLabel(int n){
    if(n == CKEY_SOFT1) n = 0;
    ef(n == CKEY_SOFT2) n = 1;
    return command[n].getLabel();
}
//DoCoMo用の処理
private String[] labelName = new String[2];
protected void _setLabel(int n, String s){
    if(n == CKEY_SOFT1) n = 0;
    ef(n == CKEY_SOFT2) n = 1;
    else return;
    labelName[n] = s;

    if(n == 1){
        setSoftLabel(Frame.SOFT_KEY_2, s);
    }ef(n == 0){
        setSoftLabel(Frame.SOFT_KEY_1, s);
    }
}

protected void _remLabel(int n){
    _setLabel(n, "");
}

protected String _getLabel(int n){
    if(n == CKEY_SOFT1) n = 0;
    ef(n == CKEY_SOFT2) n = 1;
    return labelName[n];
}

長い(;´Д`)
まあ、これで、_setLabel()と_remLabel()と_getLabel()を使って、共通のソフトキーの処理が出来るようになりました。
あ、MIDP側の処理で、CKEY_SOFT1の場合に、両方ともremoveCommandしているのは、ソフトキー1側のCommandは、優先順位が高いため、こいつを先にremoveCommandしてしまうと、ソフトキー2側にあったCommandがずれてきて、ソフトキー1側に来てしまうからです。それも直ぐにremoveCommandされるのですけど、一瞬だけ画面に表示されて、おかしく見えてしまいます。それを防ぐために、先にソフトキー2側のCommandをremoveCommandしているのです。


これで大体の作業は終わりですが、まだ問題があります。
それは、ソフトキーが離されたことを感知する機能が、MIDPには無い、ということです。
これはどうしようもないことなので、とりあえず、_keyUpdate()を実行する際に、こいつをクリアしましょう。

protected void _keyUpdate(){
    oldKey = fixKey;
    fixKey = frameKey;
    //ソフトキーのクリア
    realKey &= ~(CKEY_SOFT1|CKEY_SOFT2);
}

ということは、当然_isKeyPress()で、ソフトキーを判定することは出来ません。
まあ、ソフトキーに対して_isKeyPress()っていうのはそうそう無いと思うので、これで我慢しておきます。


あと、蛇足ですが、昨日、キーの入力を拡張したいときは、オーバーライドをすればいいと書きましたが、keyPressed()や、processEvent()等のメソッドは、機種依存の名前なので、別々にオーバーライドしないといけません。
出来る限りそういったのは意識したくないので、これらは全てfinal宣言をしておいて、このメソッドから、共通のメソッドを呼び出します。

//共通
protected void _pushDown(int keyCode){
    realKey |= k;
}

protected void _pushUp(int keyCode){
    realKey &= ~k;
}

//au,Vodafone
final public void keyPressed(int keyCode){
    _pushDown(keyCommon(keyCode));
}

final public void keyReleased(int keyCode){
    _pushUp(keyCommon(keyCode));
}

//keyCodeを、CKEY_xxxxに変換するメソッド
private void keyCommon(int keyCode){
    //au,Vodafone用keyCommon
}

//DoCoMo
final public void processEvent(int type, int param){
    if(type==Display.KEY_PRESSED_EVENT) _pushDown(keyCommon(param));
    ef(type==Display.KEY_RELEASED_EVENT) _pushUp(keyCommon(param));
}

private void keyCommon(int keyCode){
    //DoCoMo用keyCommon
}

これで、必要に応じて_pushDown()と_pushUp()をオーバーライドすれば、機種を気にすることなくプログラムを書くことが出来ます。


今日のはいつにもまして長かったなぁ……(;´Д`)