TouchPad を備えたラップトップにマルチタッチ・ジェスチャーのサポートを追加する

synclient と X の合成イベントを使って「3 本指によるスワイプ」「ピンチオープン」「ピンチクローズ」操作を可能にする

Synaptics TouchPad の synclient プログラムの出力を分析することによって、Linux® アプリケーションで「スワイプ」や「ピンチ」といった操作を使えるようにしましょう。

Nathan Harrington, Programmer, EMC

Nathan HarringtonNathan Harrington は IBM のプログラマーで、現在は Linux とリソース探索技術に取り組んでいます。



2008年 6月 03日

アプリケーションの中に新しい対話モードを統合する上で、マルチタッチ・インターフェースには非常に大きな利点があります。Mac OS X や Microsoft® Windows® 用のマルチタッチ・インターフェース対応の新しいハードウェアやドライバーでは、ポイント・アンド・クリック以上のさまざまな操作が可能になるため、アプリケーションでのより効率的なナビゲーションが実現できます。この記事では、こうした新しい操作のいくつかを Linux® 対応の古いハードウェアでサポートするために必要なツールとコードについて説明します。ここで紹介する、synclient プログラムの出力をベースに作成した Perl コードによって、「3 本指によるスワイプ (3 本指を滑らす)」操作や「ピンチオープン (2 本の指の間を広げる)」「ピンチクローズ( 2 本の指の間を狭める)」といった操作にアプリケーションの特定の機能を割り当てることができます。

要件

ハードウェア

ここで説明するコードは、Synaptics TouchPad を備えたコンピューターでのみ使用できるように設計されており、IBM® の ThinkPad T30 上で開発されたものです。Synaptics のタッチパッドは Acer の Aspires から東芝の Tecrasまで、多くのラップトップに装備されています。Synaptics TouchPad ソフトウェア・プロジェクトのハードウェア互換性リストを「参考文献」に挙げましたので、皆さんのラップトップが該当するかどうかを確認してみてください。

ソフトウェア

evdev をサポートした最近の Linux カーネルが必要です。幸い、最近の大部分のディストリビューションにはこの機能が組み込まれています。多くのディストリビューションには、TouchPad のイベントをモニターするために使われる synclient を含んだ Synaptics パッケージも付属しています。例えば Fedora Core には、ユーザーが最小限の変更をするだけで TouchPad を使えるようになる、適切な X ウィンドウ・システムの構成も含まれています。他のディストリビューション (例えば Ubuntu V7.10 など) の場合には、Synaptics パッケージ (sudo apt-get install tpconfig コマンドによりインストールされます) を適切に動作させるには、さらに構成が必要かもしれません。Synaptics TouchPads による基本的な機能を Linux で実現するための詳細情報に関しては「参考文献」を参照してください。

また TouchPad イベントの処理に対して 1 秒以下の細かな制御をするために、CPAN の Time::HiRes モジュールが必要です。さらに、X ウィンドウの合成イベントをアプリケーションに送信するために X11::GuiTest モジュールも必要です。これらのツールに関しては「参考文献」を参照してください。


基本的な機能を確認する

TouchPad を使ったマウス制御が有効になっている場合には、指による操作をサポートするために複数の指を適切に検出できるかどうかを調べます。synclient -m 100 を実行し、TouchPad でさまざまなタッチ操作を試します。すると次のようなものが出力されるはずです。

リスト 1. synclient -m 100 の出力の例
    time     x    y   z f  w  l r u d m     multi  gl gm gr gdx gdy
  13.872  5680 4409   0 0  0  0 0 0 0 0  00000000   0  0  0   0   0
  14.891  1072 3945  28 1  4  0 0 0 0 0  00000000   0  0  0   0   0
  14.994  3529 2667 104 2  5  0 0 0 0 0  00000000   0  0  0   0   0
  15.605  3669 3667   0 0  0  0 0 0 0 0  00000000   0  0  0   0   0
  16.625  2628 2841 255 3  5  0 0 0 0 0  00000000   0  0  0   0   0
  17.951  3117 2843 255 3  5  0 0 0 0 0  00000000   0  0  0   0   0
  18.053  2902 3142   3 1 15  0 0 0 0 0  00000000   0  0  0   0   0
  18.155  2430 3062   0 0  0  0 0 0 0 0  00000000   0  0  0   0   0

1 本の指と 2 本の指、そして 3 本の指によるタッチ操作を試し、イベントが適切に検出されることを確認します。最初に追加するのは「3 本指によるスワイプ」操作なので、TouchPad が 3 本の指を検出できることを確認します。2 本の指の間隔を大きく変化させながら TouchPad に押し当てると、TouchPad がゼロ本の指を検出し、また X 座標と Y 座標の読み取り値を検出する様子に注意してください。以下で説明する処理スクリプトは、こうした特性の一部を利用してピンチオープンとピンチクローズを検出しています。Ctrl+c を押すと synclient プログラムが終了します。


このプログラムの手法の概要

syclient 出力を使って TouchPad の状態をモニターする方法は、Linux アプリケーションにインターフェース・オプションを追加するための単純で効果的な方法です。下記に紹介する gestureListener.pl プログラムは、パイプを開いて synclient プログラムから読み取り、TouchPad イベントを処理して指による操作を検出します。これらの特定の操作は、X ウィンドウ・システムで現在フォーカスされているアプリケーションに送信されるキーボード・コマンドとリンクされています。


スワイプ操作

「3 本指によるスワイプ」操作は 3 本の指が TouchPad 上を単純に左または右に移動するだけでよいため、比較的簡単に検出することができます。リスト 2 は gestureListener.pl プログラムの最初の部分を示しています。この部分は synclient 出力の処理を開始して指による操作を検出するために必要です。

リスト 2. gestureListener.pl プログラムの最初の部分
#!/usr/bin/perl -w  
# gestureListener.pl listens for pinch and swipe events
use strict;
use Time::HiRes();
use X11::GUITest qw( :ALL );

my @xHist = ();               # x coordinate history
my @yHist = ();               # y coordinate history
my @xHistThree = ();          # x coordinate history (three fingers)

my $lastTime = 0;             # time monitor for TouchPad event reset
my $eventTime = 0;            # ensure enough time has passed between events
my $eventString = "default";  # the event to execute
my $centerTouchPad = 3000;    
my $openSt         = 1000;    # start of open pinch
my $openEn         = 500;     # end of open pinch
my $closeSt        = 1000;    # start of close pinch
my $closeEn        = 1000;    # end of close pinch

my $synCmd = qq{synclient TouchpadOff=1 -m 10};
my $currWind = GetInputFocus();
die "couldn't get input window" unless $currWind;
open(INFILE," $synCmd |") or die "can't read from synclient";

特定の Synaptics のハードウェアやドライバーのレベルによって、centerTouchPad 変数や他のパラメーターにはカスタマイズが必要な場合があることに注意してください。synclient コマンドの TouchPadOff=1 オプションは、通常の TouchPad イベントをオフにします。ただし (ThinkPads などの) 赤い「マウス・スティック」は相変わらず使うことができ、PS2 マウスと USB マウスも使うことができます。TouchPad をオフする必要はありませんが、オフすることによって、スワイプやピンチといった操作から、操作とは無関係のマウス・イベントを識別する際の問題を軽減することができます。

GetInputFocus を呼び出すと、現在フォーカスされているウィンドウの ID を知ることができます。これによって、(後ほど使用する) SendKeys コマンドは現在フォーカスされているウィンドウに X ウィンドウの合成イベントを送信することができます。リスト 3 はメイン・プログラムのループを開始し、そして synclient の出力を読み取ります。

リスト 3. メイン・ロジックのループの開始
while( my $line  = <INFILE>)
{
  chomp($line);
  my(  $time, $x, $y, $z, $f ) = split " ", $line;
  next if( $time =~ /time/ ); #ignore header lines
  
  if( $time - $lastTime > 1 )
  { 
    @xHist = ();
    @yHist = ();
    @xHistThree = ();
  }#if time reset
  
  $lastTime = $time;

TouchPad の操作の間でキャリー・オーバーが起こるのを防止するために、タイムアウトするごとにイベント検出の履歴の配列をリセットすることが重要です。リスト 4 はメイン・プログラムのループで 3 本の指を検出する動作の開始部分を示しています。

リスト 4. 3 本の指による操作の処理
  # three finger swipe detection
  if( $f eq "3" )
  {
    @xHist = ();
    @yHist = ();

    push @xHistThree, $x;
        
    if( @xHistThree > 10 )
    { 
      my @srt = sort @xHistThree;
      my @revSrt = reverse sort @xHistThree;

      if( "@srt" eq "@xHistThree" )
      { 
        # alt + right arrow - forward
        $eventString = "'%({RIG})";
      }elsif( "@revSrt" eq "@xHistThree" ) 
      {   
        # alt + left arrow - back
        $eventString = "'%({LEF})";
      }#if forward or backward

      @xHistThree= ();
        
    }#if more than 10 data points in 3 finger array

3 本の指のデータが 10 点で検出できると、X 座標が処理され、昇順と降順のソート行われます。昇順ソートの結果と現在の X 座標の値が一致している場合には、右向きのスワイプ条件がセットされます。逆に、降順ソートの結果と一致している場合には、左向きのスワイプ条件がセットされます。eventString 変数はこの条件を保持し、次のように実行されます。

リスト 5. メイン・ロジックの続き (イベントの実行)
  }else
  { 
    # reset all data points, yes you can have 0 fingers at x,y
    @xHist = ();
    @yHist = ();  
    @xHistThree = ();
  }# if not one or two or three fingers
  
  # only process one event per time window
  if( $eventString ne "default" )
  { 
    if( abs(time - $eventTime) > 1 )
    { 
      $eventTime = time;
      SendKeys( "$eventString");
    }#if enough time has passed
    $eventString = "default";
  }#if non default event

}#synclient line in

close(INFILE);

この時点で 3 本の指が検出されていなければ、ピンチあるいはスワイプ操作用の各データ構造はリセットされます。イベントがセットされ、現在の時刻が最後のイベント実行時刻から十分に経過している場合には、新しいイベントが実行されます。SendKeys サブルーチンは適切なイベント (Alt + 左矢印または右矢印) を、現在フォーカスされているアプリケーションに送信します。デモ・ビデオ (「参考文献」を参照) を見るとわかるように、「3 本の指」によるこれらの操作は、ブラウズした履歴の「戻る」「進む」を実行するために使われています。


ピンチ操作

ピンチ操作の検出はかなり複雑で、この記事を作成するために使用した古いハードウェアでは特に複雑です。ピンチオープン操作とピンチクローズ操作を kst のようなツールを使ってリアルタイムでモニターする方法は、対象とする特徴を TouchPad のデータから抽出する上で便利な方法です。リスト 6 のコードを 65 行目 (else の上) に挿入し、ピンチクローズ操作を検出するためのセクションを開始します。

リスト 6. ピンチクローズ操作の検出
  }elsif( $f eq "2" || $f eq "1" )
  {
    # accept 1 or 2 finger entries as part of pinch section
    @xHistThree = ();
  
    push @xHist, $x;
    push @yHist, $y;
    
    if( @xHist > 50 )
    {
      if( (getStrAvg(\@xHist) > $closeSt && getStrAvg(\@yHist) > $closeSt) &&
          (getEndAvg(\@yHist) < $closeEn && getEndAvg(\@yHist) < $closeEn) )
      {
        # wide to narrow detected, now search for enough 'wiggle'

        my $tenX = 0; 
        my $tenY = 0;
        for my $each( @xHist[40..49] ){ $tenX += $each }
        for my $each( @yHist[40..49] ){ $tenY += $each }
        $tenX = $tenX / 10;
        $tenY = $tenY / 10;

        my $diffX = 0;
        my $diffY = 0;
        for my $each( @xHist[40..49] ){ $diffX += abs( $each - $tenX ) }
        for my $each( @yHist[40..49] ){ $diffY += abs( $each - $tenY ) }

        # ctrl - decrease font size
        if( ($diffX+$diffY) > 80 ){ $eventString = "^({-})" }
        
        @xHist = ();
        @yHist = ();
        @xHistThree = ();

      }#if x and y in range

    }#if enough data for 50 close pinch detection

ピンチ操作検出のステップでは全体的な追跡機能を高めるために、1 本の指でも 2 本の指でもよいとしています。ピンチ操作の動きの一環として 1 本または 2 本の指によるタッチを受け入れるようにすると、タッチとリリースの微妙なタイミングのずれや、ピンチ操作の動きの中で 1 本の指が TouchPad からわずかに離れてしまう動きに対して、より容易に対応することができます

50 以上のデータ・ポイントが収集できると、過去 50 回のデータ・ポイントを平均した開始位置と終了位置が計算されます。3 番目の if 文は異なる 4 つのチェックを行い、ピンチクローズ操作の開始ポイントと終了ポイントがピンチクローズ検出用の適切な部分に入っていることを確認します。具体的には、開始ポイントの X の平均と Y の平均がピンチクローズの開始ポイントよりも大きいかどうかを確認します。つまり開始ポイントの指の位置はコーナーになければなりません。逆に、終了ポイントの X の平均と Y の平均はピンチクローズの終了ポイントより内側になければなりません。getStrAvggetEndAvg は、より信頼性の高いデータ・ポイントとしてチェックに使用するために、3 つの開始ポイントと終了ポイントの平均を作成します。

真のマルチタッチ機能であれば、各指の位置の X 座標と Y 座標を読み取ることができます。入手可能な Synaptics ハードウェアにはこの機能がありませんが、2 本の指によるタッチポイントが synclient プログラムからの 1 つの出力として「平均化」されることで、一貫性のある振る舞いを提供することができます。synclient プログラムの出力をモニタリングしてみると、2 本の指が南西と北東のコーナーをタッチすると、値が TouchPad のコーナーを示す値から中心を示す値に素早く変わることがわかります。2 本の指がコーナーに置かれたままの場合には、synclient の出力の X 座標と Y 座標は中心の近くを示します。2 本の指が中心に向かって移動すると、この自動平均される値は多少変動します。このデータの変動は、指が動かずにコーナーに置かれている際のデータ・ポイントの総合的な平均とは異なり、上記のコード部分によって検出され、ピンチクローズであることが示されます。

すると、まず X 座標と Y 座標の履歴のうち、最新の 10 個の値が平均されます。そして最新の 10 個の値それぞれと、その 10 個の値の平均との差が計算されます。全体としての差が十分に大きければ (この場合は 80 よりも大ならば)、十分なデータの揺れが検出されたことになり、ピンチクローズの条件が eventString の中にセットされます。

今度は、リスト 7 に示すコードを 103 行目 (ピンチクローズ検出用の 50 ポイントが収集できたかを確認する if の閉じ括弧の下) に追加し、ピンチオープンを検出します

リスト 7. ピンチオープンの検出
    #open pinch requires substantially fewer data points
    if( @xHist > 10 )
    {
      if( (getStrAvg(\@xHist) < $openSt && getStrAvg(\@yHist) < $openSt) &&
          (getEndAvg(\@yHist) > $openEn && getEndAvg(\@yHist) > $openEn) )
      {
        # ctrl + increase font size
        $eventString = "^({+})"; 

        @xHist = ();
        @yHist = ();
        @xHistThree = ();
      }#if absx and absy

    }#if enough data

ピンチオープンを検出する場合、高い信頼性で検出するのに必要なデータ・ポイントは大幅に少ない上、データの揺れを検出するステップが必要ありません。kst のようなプログラムを使ってリアルタイムでモニタリングすると、synclient の出力はピンチオープン操作用に収集されたデータ・ポイントの方がピンチクローズ操作の場合と比べて、ずっと広範囲なデータを示します。2 本の指の位置を自動的に平均化しても、ピンチオープン操作の最中の synclient の X 座標と Y 座標には大きな影響がありません。従って、操作を正確に検出するためにデータの揺れを認識する必要はもうありません。リスト 8 は平均化サブルーチン、getStrAvggetEndAvg を示しています。

リスト 8. 2 つの平均化ルーチン
sub getStrAvg
{     
  my $arrRef = $_[0];
  my $val = (@$arrRef[0] + @$arrRef[1] + @$arrRef[2]) / 3;
  $val = abs( $val - $centerTouchPad ); 
  return($val);
}#getStrAvg
        
sub getEndAvg
{       
  my $arrRef = $_[0];
  my $val = (@$arrRef[@$arrRef-3] + @$arrRef[@$arrRef-2] + 
               @$arrRef[@$arrRef-1]) / 3;
  $val = abs( $val - $centerTouchPad );
  return($val);
}#getEndAvg

リスト 8 のコードを 144 行目 (ファイルの最後) に置くと、gestureListener.pl プログラムが完成します。getStrAvggetEndAvg はそれぞれ、最初の 3 つの配列要素の平均と最後の 3 つの配列要素の平均を返します。

使い方

このプログラムを実行するには、単純に perl gestureListener.pl コマンドを実行するだけです。Web をブラウズするためのウィンドウにフォーカスを移し、右向きにスワイプしたり左向きにスワイプしたりしてブラウズした履歴の間を移動してみます。トラック・パッドのサイズが小さいこと、ハードウェア固有の制約があることにより、高い信頼性で指による操作のイベントを発生させられるようになるまでには、少し練習が必要かもしれません。デモ・ビデオ (「参考文献」を参照) を見て、著者の ThinkPad ではうまくいっている手の動きを参考にしてください。TouchPad による「マウスらしさ」を再度有効にするためには、gestureListener.pl プログラムを終了してから synclient TouchPadOff=0 を実行します。


まとめ、そして他の例

操作とイベントの間のリンク

SendKeys コマンドによってどのような機能が呼び出されるかにかかわらず、このコマンドは現在フォーカスされているアプリケーションに適切なコマンド (Alt+Left, Ctrl+/- など) を送信する、ということを思い出してください。比較的簡単な変更としては、さまざまなキー・ストロークやマウス・イベントを指定し、ウィンドウの名前を元にアプリケーションに送信することが考えられます。

他の例と変更

この記事では synclient の出力の分析と処理、そして X の合成イベントの作成を組み合わせる方法を説明しましたが、これは Synaptics TouchPad に機能を追加するための、ほんの 1 つの例にすぎません。さらに他の操作を認識する機能を追加することを考えてみてください (例えば、synclient 出力からさらに特徴を抽出することによって、2 本の指で回転する (ピンチとローテートを組み合わせた) 操作を認識するなど)。あるいは Synaptics ドライバーのソース・コードを変更してカーネル・レベルで追加の機能をサポートし、この新しい入力チャネルを活用するようにアプリケーションを作り直すことなどが考えられます。


ダウンロード

内容ファイル名サイズ
Sample codeos-touchpad.gestureListener_0.1.zip2KB

参考文献

学ぶために

  • YouTube.com でマルチタッチのデモ・ビデオを見てください。
  • Linux に TouchPad ドライバーを実現する Synaptics プロジェクトについて学んでください。
  • Synaptics プロジェクトの Web サイトでハードウェア互換性のリストを見てください。
  • TuxMobilUbuntu には Synaptics TouchPad をセットアップするためのリソースがあります。
  • CPAN から Time::HiRes モジュールを入手してください。
  • CPAN には Dennis Paulsens による素晴らしい X11::GuiTest モジュールがあります。
  • developerWorks podcasts では、ソフトウェア開発者のための興味深いインタビューや議論を聞くことができます。
  • developerWorks technical events and webcasts で最新情報を入手してください。
  • IBM オープンソース開発者にとって関心のある、世界中で今後開催される会議や業界展示会、ウェブキャスト、その他のイベントについて調べてみてください。
  • developerWorks の Open source ゾーンをご覧ください。オープンソース技術を使った開発や、IBM 製品でオープンソース技術を使用するためのハウ・ツー情報やツール、プロジェクトの更新情報など、豊富な情報が用意されています。
  • IBM とオープンソース技術、そして製品機能を調べ、学ぶために、無料の developerWorks On demand demos をご覧ください。

製品や技術を入手するために

議論するために

  • 皆さんの次期オープンソース開発プロジェクトを IBM trial software を使って革新してください。ダウンロード、あるいは DVD で入手することができます。
  • IBM 製品の試用版をダウンロードし、DB2® や Lotus®、Rational®、Tivoli®、WebSphere® などが提供するアプリケーション開発ツールやミドルウェア製品をお試しください。

コメント

developerWorks: サイン・イン

必須フィールドは(*)で示されます。


IBM ID が必要ですか?
IBM IDをお忘れですか?


パスワードをお忘れですか?
パスワードの変更

「送信する」をクリックすることにより、お客様は developerWorks のご使用条件に同意したことになります。 ご使用条件を読む

 


お客様が developerWorks に初めてサインインすると、お客様のプロフィールが作成されます。会社名を非表示とする選択を行わない限り、プロフィール内の情報(名前、国/地域や会社名)は公開され、投稿するコンテンツと一緒に表示されますが、いつでもこれらの情報を更新できます。

送信されたすべての情報は安全です。

ディスプレイ・ネームを選択してください



developerWorks に初めてサインインするとプロフィールが作成されますので、その際にディスプレイ・ネームを選択する必要があります。ディスプレイ・ネームは、お客様が developerWorks に投稿するコンテンツと一緒に表示されます。

ディスプレイ・ネームは、3文字から31文字の範囲で指定し、かつ developerWorks コミュニティーでユニークである必要があります。また、プライバシー上の理由でお客様の電子メール・アドレスは使用しないでください。

必須フィールドは(*)で示されます。

3文字から31文字の範囲で指定し

「送信する」をクリックすることにより、お客様は developerWorks のご使用条件に同意したことになります。 ご使用条件を読む

 


送信されたすべての情報は安全です。


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=60
Zone=Open source
ArticleID=316799
ArticleTitle=TouchPad を備えたラップトップにマルチタッチ・ジェスチャーのサポートを追加する
publish-date=06032008