Now browsing the archives for 6月, 2007.

[userChrome.js] 軽量マウスジェスチャー(ホイールジェスチャ・ロッカージェスチャ対応版) ~途中経過~

6/30 追記
ロッカージェスチャ有効時、選択範囲をテキストボックスへドラッグ&ドロップすると右クリックが効かなくなるバグを修正。

「Operaユーザは「右押しながら左クリック」をよく使う」というアンケート結果に衝撃を受けたわけではないですが、軽量マウスジェスチャへ、以下の2機能を追加したバージョンを作成しました。
 ・ホイールジェスチャ (右クリックしながらホイール回転でタブ切り替え)
 ・ロッカージェスチャ (右クリックしながら左クリックで戻る、左クリックしながら右クリックで進む)

ホイールジェスチャおよびロッカージェスチャ実行時には、 _performAction メソッドへ以下のような文字列が渡りますので、実行するアクションをカスタマイズ可能です。
 ・ホイールジェスチャ(下に回転): W+
 ・ホイールジェスチャ(上に回転): W-
 ・ロッカージェスチャ(右クリックしながら左クリック): L<R
 ・ロッカージェスチャ(左クリックしながら右クリック): L>R

ただし、ロッカージェスチャに未解決の問題点があって、例えば右クリックしながら左クリックを連続で何回か押して連続で戻る操作をしているとき、ページのローディングが行われている瞬間(くるくるアイコンが回転している瞬間)を狙って右クリックを放すと、放したことが認識されずに右クリックが続いていると誤認識され、その後の動作がおかしくなる。bfcache が効いていると再現しにくいので、いったんキャッシュをクリアするとページ遷移のたびにローディングされ、上記問題が再現しやすくなる。

とはいえ、そもそも All-in-One Gestures ではロッカージェスチャは連続でできない(右クリック押しながら一回左クリックをするとその時点で終了する)ため、 userChrome.js 版マウスジェスチャでもその動きにすれば上記問題点は解決すると思われる。反面、 Optimoz Mouse Gestures や本家 Opera では連続クリックが可能である。

ロッカージェスチャを望んでいる方は、この連続クリック機能が必須であるか、無くてもいい程度のものか、あるいはまったくもって不要かなどについて教えてくださるとありがたいです。ただ、連続クリックが必須という意見が大半であったとしても、今後がんばっても上記問題を解決できないままである可能性が高いです。

TOP

about:feeds の置換で自前のXUL製フィードビューアを使う

昨年開催された Firefox Developers Conference にて、 Firefox 2 で新たに搭載された Feed Content Access API を利用した独自フィードビューアの実装例を示したのだが、 Firefox 標準のフィードプレビュー (chrome://browser/content/feeds/subscribe.xhtml) を自前のXUL製フィードビューアに置き換える方法がわからず、やむを得ず自前のXUL製フィードビューアの chrome URL を「はてなRSS」や「livedoor reader」と同じようにWebサービスとして登録し、フィードを読み込むとその chrome URL へ遷移させることでビューアを置き換えるようにしていた。
(詳しくは FeedContentAccessAPI.pdf の「第二段階」を参照)

しかし、 nanto さんによる XPCOM コンポーネントの置換: Days on the Moon のやり方をそのまんま使って「about:feeds」を置換することで、前述のような遠回りなやり方をせずとも、いとも簡単に Firefox 標準のフィードプレビューを自前のXUL製フィードビューアに置き換えることに成功した。「about:feeds」を置換するにあたり、自分で考えてコードを書く必要のある部分はせいぜい nsIAboutModule の newChannel メソッドくらいのもので、以下のように自前のXUL製フィードビューアの chrome URL でチャネルを作って返すだけ。

newChannel: function(aURI) {
    var ios = Cc["@mozilla.org/network/io-service;1"].getService(Ci.nsIIOService);
    var channel = ios.newChannel("chrome://sample/content/feedview.xul", null, null);
    channel.originalURI = aURI;
    return channel;
},

この方法のおいしいところは、 Feed Stream Converter 側でパースした結果を nsIFeedResultService 経由で自前のXUL製フィードビューア側から取り出して使うことができるという点である。前述の苦し紛れの方法(Webサービスとして登録した chrome URL へ遷移)ではそれが不可能なので、遷移した先のXULで XMLHttpRequest とかを使って改めてフィードの取得とパースをしてやる必要があった。

ちなみに nsIFeedResultService とは、 Feed Stream Converter がフィードをパースした結果をグローバルにアクセス可能なオブジェクトとして保持することで、実際にフィードの画面表示を行う Feed Writer から参照できるようにするための XPCOM である。 Feed Stream Converter がパース結果を nsIFeedResultService へ登録する処理の流れは FeedConverter.js の handleResult を見ればわかる。 Firefox 標準のフィードプレビューを使う設定になっている場合、つまり設定値「browser.feeds.handler」が「ask」の場合、 nsIFeedResultService#addFeedResult でパース結果を登録してから「about:feeds」のチャネルを開くのに対して、Webサービスを使用する設定の場合、つまり設定値「browser.feeds.handler」が「web」の場合、 nsIWebContentConverterService#loadPreferredHandler を使って新たな URI をロードし直すだけの処理となっている。

なお、 nsIFeedResultService からのパース結果の取り出し方は、 FeedWriter.js の _getContainer を見ればわかる。

var channel = window.QueryInterface(Ci.nsIInterfaceRequestor)
              .getInterface(Ci.nsIWebNavigation)
              .QueryInterface(Ci.nsIDocShell_MOZILLA_1_8_BRANCH)
              .currentDocumentChannel;
var feedSvc = Cc["@mozilla.org/browser/feeds/result-service;1"]
              .getService(Ci.nsIFeedResultService);
var result = feedSvc.getFeedResult(channel.originalURI);  // nsIFeedResult

TOP

Firefox Developers Conference Summer 2007

昨日開催された Devcon 2007 のプレゼン資料をアップしました。その他にも、過去に使用したプレゼン資料も整理してまとめてアップしました。
» プレゼン資料のページ

なお、PowerPoint ファイルから PDF への変換は Drawloop を使用しました。登録さえすれば無料で Word / Excel / PowerPoint から PDF への変換が可能となる Webサービスで、 Ajax な UI もシンプルで使いやすい。以前は日本語フォント未対応だったが、今はまったく問題なし。大変ありがたいです。

TOP

userChrome.js でE4Xを使う

これまで、userChrome.js スクリプトでスタイルシートを追加することはできなくて、別途 userChrome.css を使用しなければならないと思っていた。ところが、nanto_viさんによるE4X in Firefox 発表資料: Days on the Moon の userChrome.js 用スクリプトを見ればわかるように、 E4Xを使うことによって userChrome.js のみでスタイルの定義追加が可能であることが判明。それだけでなく、E4Xを使えば userChrome.js 内に XML を直接書いてそのままブラウザへオーバーレイなんてことも簡単に可能。ボタンやメニューをたくさん追加したいときなんかに、いちいち document.createElement する必要がなくなる。すばらしい。

さっそく、 Colorful Tabs を修正して、 userChrome.css への追記を不要にさせた。

TOP

[userChrome.js] 軽量マウスジェスチャをWindows/Linuxに対応させる

通りすがりさんによるパッチをベースに、[userChrome.js] 軽量マウスジェスチャを Windows/Linux に対応させました。以下は今回修正した内容についてメモです。

以前はマウスジェスチャ中の状態遷移を数値型のフラグ _state を使って以下のように制御していた。

イベント _state フラグの変化 意味
mousedown 0 → 1 右クリック開始
mousemove (1のまま変化なし) 右クリックしたままマウス移動中
mouseup 1 → 2 ジェスチャ認識あり
1 → 3 ジェスチャ認識なし(マウスの移動量が微小)
contextmenu 2 → 0 コンテキストメニューの表示を抑止する
3 → 0 コンテキストメニューの表示を抑止しない

しかしながら、 Windows では上記のように mousedown→mousemove→mouseup→contextmenu という順序でイベントが発生するものの、 Linux では mousedown→contextmenu→mousemove→mouseup という順序で発生するため、制御がうまくいかなかった。そこで、数値型のフラグを廃止し、代わりに以下のような3つの真偽値フラグを使うようにした。

フラグ 意味
_isMouseDown 右クリックが押されているかどうか。
mousedown イベントで true になり、 mouseup イベントで false になる。
_suppressContext この後の contextmenu イベントを抑止するかどうか。
mouseup イベント発生時にジェスチャの認識があれば true にし、その後の contextmenu イベントを抑止する。
_shouldFireContext 後で contextmenu イベントを擬似的に発生させる必要があるかどうか。 Linux 専用。
Linux の場合は mousedown イベント直後に contextmenu イベントが発生するが、これを抑止した際にフラグを true にしておき、その後の mouseup イベント発生時にフラグが立っていれば擬似的に contextmenu を発生させる。

これによってスクリプトの一部は以下のように変更された。青色の部分が Linux 専用となる処理である。

    _isMouseDown: false,
    _suppressContext: false,
    _shouldFireContext: false,

    handleEvent: function(event)
    {
        switch (event.type) {
            case "mousedown": 
                // [1] ジェスチャ開始
                if (event.button == 2) {
                    this._isMouseDown = true;
                    this._startGesture(event);
                }
                break;
            case "mousemove": 
                // [2] ジェスチャ継続中
                if (this._isMouseDown) {
                    this._progressGesture(event);
                }
                break;
            case "mouseup": 
                // [3] ジェスチャ終了~アクション実行
                if (this._isMouseDown) {
                    this._isMouseDown = false;
                    this._suppressContext = !!this._directionChain;
                    this._stopGesture(event);
                    // [Linux] Win32を真似てmouseup後にcontextmenuを発生させる
                    if (this._shouldFireContext) {
                        this._shouldFireContext = false;
                        this._displayContextMenu(event);
                    }
                }
                break;
            case "contextmenu": 
                // [4-1] アクション実行後のコンテキストメニュー表示を抑止する
                // [4-2] 方向が認識されない微小な動きの場合は抑止しない
                // [Linux] mousedown直後のcontextmenuを抑止して...
                if (this._suppressContext || this._isMouseDown) {
                    this._suppressContext = false;
                    event.preventDefault();
                    event.stopPropagation();
                    // [Linux] ...代わりにmouseup後にcontextmenuを発生させる
                    if (this._isMouseDown) {
                        this._shouldFireContext = true;
                    }
                }
                break;
        }
    },

    _displayContextMenu: function(event)
    {
        var evt = event.originalTarget.ownerDocument.createEvent("MouseEvents");
        evt.initMouseEvent(
            "contextmenu", true, true, event.originalTarget.defaultView, 0,
            event.screenX, event.screenY, event.clientX, event.clientY,
            false, false, false, false, 2, null
        );
        event.originalTarget.dispatchEvent(evt);
    },

TOP

マウスジェスチャについてのアンケート結果

マウスジェスチャについてのアンケートにご協力ありがとうございました。

Q1. あなたはマウスジェスチャの拡張機能を使っていますか?

All-in-One Gestures を使っている 77
Optimoz Mouse Gestures を使っている 9
userChrome.js 用マウスジェスチャを使っている 99
使っていない 14

Q2. マウスジェスチャ機能は必要ですか?

はい 182
いいえ 8
わからない 7

Q3. ロッカージェスチャ機能(右クリックしながら左クリック)は必要ですか?

はい 56
いいえ 116
わからない 27

Q4. ホイールジェスチャ機能(右クリックしながらマウスホイール)は必要ですか?

はい 87
いいえ 93
わからない 20

Q5. ミドルクリックでのホイールジェスチャ機能(ミドルクリックしながらマウスホイール)は必要ですか?

はい 12
いいえ 158
わからない 30

Q6. タブバー上でのマウスホイールによってタブを切り替える機能は必要ですか?

はい 85
いいえ 98
わからない 17

Q7. マウスジェスチャ中の軌跡描画(マウストレイル)は必要ですか?

はい 36
いいえ 154
わからない 10

Q8. マウスジェスチャ中のステータスバー表示は必要ですか?

はい。「LR」のように、現在の方向を表示すべき。 31
はい。「LR (タブを開く)」のように、現在の方向と機能名称を表示すべき。 123
いいえ 41
わからない 5

Q9. ジェスチャの方向の表現方法はどれが最適ですか?

L、R、U、D 71
左、右、上、下 7
←、→、↑、↓ 111
わからない 11

Q10. 斜め方向のジェスチャの認識は必要ですか?

はい 18
いいえ 163
わからない 18

Q11. ジェスチャのタイムアウト(ジェスチャ中に数秒間じっとしているとジェスチャの認識を停止する機能)は必要ですか?

はい 114
いいえ 55
わからない 29

Q12. ジェスチャ中に通過したすべてのリンクをタブで開く機能は必要ですか?

はい 41
いいえ 120
わからない 38

Q13. 「タブを閉じる」機能に最適なジェスチャの割り当ては?

↓→ 68
46
↓↑ 10

Q14. 「新しいタブを開く」機能に最適なジェスチャの割り当ては?

25
19
←→ 7

Q15. 「閉じたタブを元に戻す」機能に最適なジェスチャの割り当ては?

↓← 20
↓↑ 18
↑↓ 11

Q16. マウスジェスチャに求めるものは?

動作の軽さ 168
機能の豊富さ 32
設定のしやすさ 100
ユーザスクリプトへの対応 52

TOP