Cross Browser のための DHTML
最終更新日:

input data

簡易キー入力関数

上のサンプルは keydown/up イベントを使用して英数字を入力するレイアの例です。

入力したいレイアをクリックすると入力モードになり、 キーを入力するとそのレイア上にエコーバック表示し、 「改行」キーで確定します。
また、確定した文字列は下のテキスト入力領域に表示されます。

途中で入力を中断する場合は、再度レイアをクリックします。

この機能は通常 FORM で実現しますが、レイアに FORM を使用した場合、 NC4 ではそのレイア上に他のレイアがオーバラップしても FORM の要素が見えてしまいます。 そこで、回避策として使用できないかの実験的な意味合いの機能です。 f(^^;

使い方

先ず、入力するレイアを作成し、キー入力対象として登録します。

function init(){
  div1=createLayer(50,100,300,200);
  ech_attachKeyInput(div1,
       '#ffffee','fistyle','#3399cc','fostyle',
       enterCB,null);
  setDivVisibility(div1,true);
}

ここではレイアを直接生成することにします ( 条件ではありません。趣味です f(^^; )。

createLayer 関数は onLoad イベント以降にレイアを生成する関数で、 「ライブラリ集」に定義してあります。

ech_attachKeyInput 関数は指定したレイアにキーイベント処理を追加する関数で、 以下の引数をとります。

ech_attachKeyInput(div,fic,fis,foc,fos,eCB,eCD)
div
対象とするレイア
fic,foc
入力モードの場合の背景色( fic )とそうでない時の背景色( foc )
fis,fos
入力モードの場合の文字のスタイルのスタイル名( fis )と そうでない時のスタイル名( fos )
eCB,eCD
確定操作を行なった場合に呼出すユーザ定義関数( eCB )とユーザ定義データ( eCD )

入力モードのスタイルはクラスとして予め作成しておきます。

.fistyle{ font-size:12pt; color:#cc6699; }

入力モードのでない時のスタイルはクラスとして予め作成しておきます。

.fostyle{ font-size:12pt; font-weight:bold; color:#eeeeff; }

確定操作を行なった場合に何らかの処理をする場合に登録します。 I/F は以下の通りです。

enterCB(div,client,value)
div
確定されたレイアオブジェクト
client
ech_attachKeyInput関数で指定したユーザ定義データ
value
確定された文字列

setDivVisibility関数は指定されたレイアの可視性を設定する関数で、 「ライブラリ集」に定義してあります。

次に、確定処理の関数を定義します。

function enterCB(div,client,value){
  document.f.t.value=value;
}

ここでは、FORM 「f」内にあるテキスト入力域「t」に、 確定された文字列( value )を表示しています。

これだけではキー入力状態にならないので、そのトリガーとなる処理を登録します。

function init(){
  div2=createLayer(50,100,300,200);
  ech_attachMouseDrag(div,
      null,null,null,null,null,null,
      clickCB,div1);
  setDivVisibility(div2,true);
}
function clickCB(ctrl,client){
  if(grabKey!=client) ech_focusIn(client);
  else                ech_focusOut(client);
}

ここでは、入力レイア上をクリックすることで入力状態をトグルにするため、 同じサイズの透明なレイアを作成します

ech_attachMouseDrag 関数は指定したレイア上のドラッグに関する処理を 登録するための関数で、「汎用イベントハンドラ」に定義されています。

ここでは、ドラッグ処理ではなくクリック処理のみ登録します。

grabKey には入力状態にあるレイアが設定してある変数で、 本来ここで紹介している関数の内部変数ですが、 手抜きをするために直接参照しています。

ech_focusIn 関数は指定されたレイアを入力状態にする関数で、 I/F は以下の通りです。

ech_focusIn( div )
div
入力状態にするレイアのオブジェクト

ech_focusIn 関数は指定されたレイアの入力状態を解除する関数で、 I/F は以下の通りです。

ech_focusOut( div )
div
入力状態を解除するレイアのオブジェクト

オブジェクトのプロパティとメソッド

この関数は「汎用イベントハンドラ」で使用している EventCtrl オブジェクトに いくらかのプロパティとメソッド及びアクセス関数を追加して実現しています。

メソッド

確定処理通知用ユーザ定義関数
keyenter( div, client, value );
div
確定処理の発生したレイアオブジェクト
client
ech_attachKeyInput 関数で登録したユーザ定義データ
value
確定した文字列

プロパティ

lastKey
最後に入力されたキーのキーコード( ブラウザ依存のため参照不可 )

inputDataLast
入力された文字列の配列( 文字単位 )

inputData
入力された文字列

echoBacks
レイアオブジェクトに表示している文字列

focusInColor,focusInClass
入力状態にある時の背景色( focusInColor )と文字スタイル名( focusInClass )

focusOutColor,focusOutClass
入力状態にない時の背景色( focusOutColor )と文字スタイル名( focusOutClass )

keyenterClient

関数

キーイベント処理登録関数
ech_attachKeyInput(div,
    ficol,ficls,focol,focls,entcb,entcd);
div
登録対象のレイアオブジェクト
ficol,ficls
入力状態の時の背景色( ficol )と文字スタイル名( ficls )
focol,focls
入力状態でない時の背景色( ficol )と文字スタイル名( ficls )
entcb,entcd
確定時に通知するユーザ定義関数( entcb:不要時は null )とユーザ定義データ( entcd )

入力状態設定関数
ech_focusIn(div);
div
入力状態にするレイアオブジェクト

入力状態解除関数
ech_focusOut(div);
div
入力状態にするレイアオブジェクト

入力値クリア関数
ech_keyInputClear(div);
div
クリアするレイアオブジェクト

keydown,keyupイベント処理( 内部関数 )
ech_keydown(e), ech_keyup(e)
e
イベント( IE4 の場合はダミー )

1文字をHTMLで表示可能な文字に変換する関数
ech_toEntities(c);
c
文字

キーコード取得関数
whichKey(e);
e
イベント( IE4 の場合はダミー )

キーコード/文字変換関数
fromCharCode(c);
c
文字

オブジェクトのソースコード

NC4 専用関数

// キーコード取得関数
function whichKey(e){ return e.which; }
// キーコード/文字変換関数
function fromCharCode(c){
  if(c==0x0d) return "\n";
  return String.fromCharCode(c);
}

リターンコード「0x0d」は扱いやすいように改行コード「0x0a」に変換します

IE4 専用関数

// キーコード取得関数
function whichKey(e){
  var kc=event.keyCode;
  switch(kc){
  // shift control  alt      caps lock
  case 16: case 17: case 18: case 240: kc=0; break;
  // shift+0
  case 48: if(event.shiftKey) kc=0; break;
  }
  return kc;
}

モディファイキーはキーコードを返しません。

// キーコード/文字変換関数
function fromCharCode(c){
  var ch=String.fromCharCode(c);
  switch(c){

IE4 の場合、キーコードを取得して fromCharCode で文字列変換しても、 モディファイアを考慮してくれませんから、自分で変換します

  case 13:  ch="\n"; break;
  // カーソルキー
  case 37:  ch="left"; break;
  case 38:  ch="up"; break;
  case 39:  ch="right"; break;
  case 40:  ch="down"; break;
  // テンキー
  case 106: ch='*'; break;
  case 107: ch='+'; break;
  case 109: ch='-'; break;
  case 110: ch='.'; break;
  case 111: ch='/'; break;
  // 記号
  case 186: ch=(event.shiftKey?'*':':'); break;
  case 187: ch=(event.shiftKey?'+':';'); break;
  case 188: ch=(event.shiftKey?'<':','); break;
  case 189: ch=(event.shiftKey?'=':'-'); break;
  case 190: ch=(event.shiftKey?'>':'.'); break;
  case 191: ch=(event.shiftKey?'?':'/'); break;
  case 192: ch=(event.shiftKey?'`':'@'); break;
  case 219: ch=(event.shiftKey?'{':'['); break;
  case 220: ch=(event.shiftKey?'|':'\\'); break;
  case 221: ch=(event.shiftKey?'}':']'); break;
  case 222: ch=(event.shiftKey?'~':'^'); break;
  case 226: ch=(event.shiftKey?'_':'\\'); break;
  default:
    //テンキー変換
    if(c>=96 && c<=105) ch='0123456789'.charAt(c-96);
    else if(event.shiftKey){
      // 数値キーのシフトポジション
      if(ch>=0 && ch<=9) ch=' !"#$%&\'()'.charAt(ch);
      // 英字のシフトポジション
      else ch=ch.toUpperCase();
    } else ch=ch.toLowerCase();
    break;
  }
  return ch;
}

共通関数

grabKey=null; // 入力状態にあるレイア
// 出力用文字変換関数
function ech_toEntities(c){
  switch(c){
  case '\&': return '&';  break;
  case '\<': return '<';   break;
  case '\>': return '>';   break;
  case '\"': return '"'; break;
  }
  return c;
}
// keydown 処理
function ech_keydown(e){
  if(grabKey){
    var div=grabKey, ctrl=div.eventCtrl;
    var c,k=whichKey(e);
    ctrl.lastKey=k;
    if(k!=0){  // 有効なキー
      c=fromCharCode(k);
      switch(c){
      // 確定操作
      case "\n": ech_focusOut(div);
        if(ctrl.keyenter)
          ctrl.keyenter(div,
              ctrl.keyenterClient,ctrl.inputData);
        break;
      // 後退キー
      case "\b":
        if(ctrl.inputDataLast.length>0){
          var lc=ctrl.inputDataLast
             [ctrl.inputDataLast.length-1];
          ctrl.inputDataLast=
             ctrl.inputDataLast.slice(0,-1);
          var str=ctrl.inputData,ebs=ctrl.echoBacks;
          ctrl.inputData=str.substring
             (0,str.length-lc.length);
          ctrl.echoBacks=ebs.substring
             (0,ebs.length-ech_toEntities(lc).length);
          writeDivHTML(div,true,true,
              '<font class="'+ctrl.focusInClass+'">'+
              ctrl.echoBacks+'</font>');
        }
        break;

IE4 の Array オブジェクトに pop メソッドが実装されていれば

var lc=ctrl.inputDataLast.pop();

の一行で済むんだが...

      // 通常の文字入力
      default:
        if(c.length==1){
          ctrl.inputDataLast
              [ctrl.inputDataLast.length]=c;
          ctrl.inputData+=c;
          ctrl.echoBacks+=ech_toEntities(c);
          writeDivHTML(div,true,true,
              '<font class="'+ctrl.focusInClass+'">'+
              ctrl.echoBacks+'</font>');

IE4 の Array オブジェクトに push メソッドが実装されていれば

ctrl.inputDataLast.push(c);

と奇麗になるのだが...

        }
      }
      return false;
    }
  }
  return true;
}
// keyup 処理
function ech_keyup(e){}

内容がありませんが、本来はキーリピート処理をいれるつもりでした。f(^^;;;

// 入力状態設定関数
function ech_focusIn(div){
  if(div.eventCtrl){
    if(grabKey!=div){
      if(grabKey!=null) ech_focusOut(grabKey);
      var ctrl=div.eventCtrl;
      setDivBackgroundColor(div,ctrl.focusInColor);
      if(ctrl.echoBacks!=''){
        writeDivHTML(div,true,true,
          '<font class="'+ctrl.focusInClass+'">'+
          ctrl.echoBacks+'</font>');
      }
      grabKey=div;
    }
  }
}
// 入力状態解除関数
function ech_focusOut(div){
  if(div.eventCtrl){
    if(grabKey==div){
      var ctrl=div.eventCtrl;
      setDivBackgroundColor(div,ctrl.focusOutColor);
      if(ctrl.echoBacks!=''){
        writeDivHTML(div,true,true,
          '<font class="'+ctrl.focusOutClass+'">'+
          ctrl.echoBacks+'</font>');
      }
      grabKey=null;
    }
  }
}
// 確定文字列削除関数
function ech_keyInputClear(div){
  if(div.eventCtrl){
    var cls,ctrl=div.eventCtrl;
    if(grabKey==div) cls=ctrl.focusInClass;
    else             cls=ctrl.focusOutClass;
    ctrl.inputDataLast=new Array();
    ctrl.inputData=''; ctrl.echoBacks='';
    writeDivHTML(div,true,true,'');
  }
}
// キーイベント処理登録関数
function ech_attachKeyInput(
    div,ficol,ficls,focol,focls,entcb,entcd){
  if(!div.eventCtrl) div.eventCtrl=new EventCtrl(div);
  var ctrl=div.eventCtrl;
  ctrl.lastKey=null;
  ctrl.inputDataLast=new Array();
  ctrl.inputData=''; ctrl.echoBacks='';
  ctrl.focusInColor=ficol; ctrl.focusOutColor=focol;
  ctrl.focusInClass=ficls; ctrl.focusOutClass=focls;
  ctrl.keyenter=entcb; ctrl.keyenterClient=entcd;
  if(document.layers){
    document.onkeydown = ech_keydown;
    document.onkeyup   = ech_keyup;
    document.captureEvents(Event.KEYDOWN|Event.KEYUP);
  } else if(document.all){
    document.onkeydown = ech_keydown;
    document.onkeyup   = ech_keyup;
  } else return null;
  setDivBackgroundColor(div,focol);
  return ctrl;
}

注意事項

キーコードの問題
このコードではブラウザから渡されるキーコードを直接判定しています。 特に IE4 では、英記号などのキーコードを fromCharCode 関数を使用して得た文字は キーボードの文字とは全く異なる文字になるのでかなりのキーコードを判定しています。

このような処理を行なうと、他のキーボードやプラットフォームで互換性のあるコードに なっているかが問題となりますが、 現在のところキーコードの仕様を発見するに至っていません。 f(^^;;;

そのため、他のキーボード( 106日本語キーボード以外 )やプラットフォーム( Mac, UNIX )などで、 正常に動作する保証はありません。

入力できる文字の範囲
この方式ではファンクションキーなどの特殊なキーは取得できません。
従って、文字入力中に特殊なモード変換を行なうことはできないでしょう。

後退キーの問題
一応「後退( Backspace )」キーで最後の文字を削除する機能がありますが、 IE4 ではこのキーを操作すると「戻る」操作になります。 これは、IE4 では mouseイベントと同様、 後続する処理を継続するかどうかの制御ができないためでもありますが、 そのため、最後の文字を削除するには「Shift」などのモディファイアキーを押しながら 「後退( Backspace )」キーを操作して下さい。

日本語入力の問題
当然、日本語入力はできませんし、将来もこの問題は解決されないでしょう。

やっぱりパフォーマンス
「怪談! Cross Browser」でも書いていますが、 NC4 では、やはり document.write メソッドは遅い。 人のキー入力のスピードなら大丈夫だろうと思ったんだけど、 結構速く入力できるんですね。 f(^^;,.


(C)Copyright 1998 ShinSoftAll rights reserved.