SAORIでSQLite
中文偽春菜後援會論壇でsqlori.dllというSAORIがリリースされています。
早速試してみた
スクリーンショットを折りたたみ
伺かゴースト更新記録
確認したbasewareはSSP/2.01.84
「]」の前に「\」を入れてエスケープする
\![raise,OnTest,\0\s[0\]こんにちは。\e]\e
最後の「]」の前に「\」を使いたい場合は「\」を「\」でエスケープする
\![raise,OnTest,円マーク→\\]\e
引数全体を「"」で囲む(SSP限定?)
\![raise,OnTest,"\0\s[0]こんにちは。\e"]\e
引数全体を「"」で囲む(SSP限定?)
\![call,ghost,"媛儀prototype,re:try"]\e
引数全体を「"」で囲んだ後、「"」を2個続けて記述したところが「"」として扱われる(SSP限定?)
\![call,ghost,"the ""MobileMaster"""]\e
SSP/2.01.80-81あたりで追加されたマウスジェスチャーの仕様が不評のようです。
そもそもSHIORI側でできそうなことをあえてベースウェアで実装するに至ったのには何か深い理由があるであろうことは想像に難くないですがこれではちょっとあんまりですね。
もうちょっと使いやすく。SHIORI側で柔軟に制御することを目標とする。
#define TOLERANCE 10 OnMouseDown { // 右クリック if reference[5] == 1 { this._isMousedown = 1 this._startGuesture(reference) } } OnMouseMove { if this._isMousedown { this._progressGesture(reference) } } OnMouseUp { if this._isMousedown { ERASEVAR('this._isMousedown') this._stopGuesture(reference) return } } this._startGuesture { this._lastX = _argv[0] this._lastY = _argv[1] this._directionChain = '' this.startX = _argv[0] this.startY = _argv[1] this._scope = _argv[3] this._collision = _argv[4] } this._progressGesture { _x = _argv[0] _y = _argv[1] _dx = _x - this._lastX; if (_dx < 0) { _dx *= -1 } _dy = _y - this._lastY; if (_dy < 0) { _dy *= -1 } if (_dx < TOLERANCE) && (_dy < TOLERANCE) { return } _direction = '' if (_dx > _dy) { if _x < this._lastX { _direction = 'L' } else { _direction = 'R' } } else { if _y < this._lastY { _direction = 'U' } else { _direction = 'D' } } _lastDirection = SUBSTR(this._directionChain, -1, 1) if (_direction != _lastDirection) { this._directionChain += _direction } this._lastX = _x this._lastY = _y } this._stopGuesture { if this._directionChain != '' { "\![raise,OnMouseGestureEx/ ,%(this._scope)/ ,%(this._lastX)%(CHR(1))%(this._lastY)/ ,%(_argv[4])/ ,%(this.startX)%(CHR(1))%(this.startY)/ ,%(this._collision)/ ,%(this._directionChain)]\e" } ERASEVAR('this._scope') ERASEVAR('this._collision') ERASEVAR('this._lastX') ERASEVAR('this._lastY') ERASEVAR('this.startX') ERASEVAR('this.startY') ERASEVAR('this._directionChain') } OnMouseGestureEx { _action = '' if reference[0] == 0 { case reference[5] { when 'L' { _action = '戻る' } when 'R' { _action = '進む' } when 'D' { _action = '新窓' } when 'DR' { _action = '閉じる' } when 'UD' { _action = '更新' } when 'UDUDRLRLDLUR' { _action = 'エターナルフォースブリザード' } others { _action = '未定義' } } '\0\_q' + reference[5] + ' : ' + _action + '\_q\e' } }
参考にしたもの
ここまで書いて何故か動かなかった。
よく調べてみたらSSPではOnMouseDownの後はOnMouseMoveが通知されないらしい(´・ω・`)
大人しくOnMouseGesture使えってことですね。
SSP/2.01.82でOnMouseMoveが通知されるようになりましたね。
昨日書いたコードに間違いがあったので修正して試したところ、エターナルフォースブリザードが打てるようになりました。
ありがとうございます。
OnMouseGestureを使わない上のコードの使い方
YAYAで書いたものと機能は全く一緒です。
TOLERANCE : 10 event.OnMouseDown : $( if $[ $(.get System.Request.Reference5[0]) == 1 ] $( .setstr this._isMousedown 1; .entry this._startGuesture; ); ) event.OnMouseMove : $( if $[ ${this._isMousedown} == 1 ] $( .entry this._progressGesture; ); ) event.OnMouseUp : $( if $[ ${this._isMousedown} == 1 ] $( .clear this._isMousedown; .entry this._stopGuesture; ); ) this._startGuesture : $( .setstr this._lastX $(.get System.Request.Reference0[0]); .setstr this._lastY $(.get System.Request.Reference1[0]); .clear this._directionChain; .setstr this.startX $(.get System.Request.Reference0[0]); .setstr this.startY $(.get System.Request.Reference1[0]); .setstr this._scope $(.get System.Request.Reference3[0]); .setstr this._collision $(.get System.Request.Reference4[0]); ) this._progressGesture : $( .setstr @x $(.get System.Request.Reference0[0]); .setstr @y $(.get System.Request.Reference1[0]); .setstr @dx $[ ${@x} - ${this._lastX} ]; .setstr @dy $[ ${@y} - ${this._lastY} ]; if $[ ${@dx} < 0 ] $( .setstr @dx $[ ${@dx} * (-1) ]; ); if $[ ${@dy} < 0 ] $( .setstr @dy $[ ${@dy} * (-1) ]; ); if $[ !((${@dx} < ${TOLERANCE}) && (${@dy} < ${TOLERANCE})) ] $( .clear @direction; if $[ ${@dx} > ${@dy} ] $( if $[ ${@x} < ${this._lastX} ] $( .setstr @direction L; ) else $( .setstr @direction R; ); ) else $( if $[ ${@y} < ${this._lastY} ] $( .setstr @direction U; ) else $( .setstr @direction D; ); ); .setstr @lastDirection $(.substr ${this._directionChain} -1 1); if $[ ${@direction} != ${@lastDirection} ] $( .setstr this._directionChain ${this._directionChain}${@direction}; ); .setstr this._lastX ${@x}; .setstr this._lastY ${@y}; ); ) this._stopGuesture : $( if $[ $(.length ${this._directionChain}) > 0 ] $( .echo \![raise,OnMouseGestureEx,${this._scope},${this._lastX}$(.chr 1)${this._lastY},$(.get System.Request.Reference4[0]),${this.startX}$(.chr 1)${this.startY},${this._collision},${this._directionChain}]\e; ); .clear this._scope; .clear this._collision; .clear this._lastX; .clear this._lastY; .clear this.startX; .clear this.startY; .clear this._directionChain; ) event.OnMouseGestureEx : $( .clear @action; if $[ $(.get System.Request.Reference0[0]) == 0 ] $( .setstr @action $(.entry gesture.$(.get System.Request.Reference5[0]) 未定義); ); .echo \0\_q$(.get System.Request.Reference5[0])" ":" "${@action}\_q\e; ) gesture.L : 戻る gesture.R : 進む gesture.D : 新窓 gesture.DR : 閉じる gesture.UD : 更新 gesture.UDUDRLRLDLUR : エターナルフォースブリザード
里々で書く場合はOnMouseMoveで重い処理を行わないように注意が必要です。
イベント通知間隔がOnSecondChangeの比ではないので、ssu.dllなどのSAORI呼び出しも使わないようにしましょう。
YAYAで書いたものと機能は全く一緒です。
ssu.dllを一切使わず高速です。
Mc145-1以降のバージョンの里々で動作します。
@TOLERANCE 10 @OnMouseDown ( 【タブ】when 【タブ】,(R5)==1 【タブ】,( 【タブ】【タブ】set 【タブ】【タブ】,this._isMousedown 【タブ】【タブ】,1 【タブ】)( 【タブ】【タブ】call 【タブ】【タブ】,this._startGuesture 【タブ】) ) *OnMouseMove >this._progressGesture【タブ】(call,this._isMousedown)==1 @OnMouseUp ( 【タブ】when 【タブ】,(call,this._isMousedown)==1 【タブ】,( 【タブ】【タブ】set 【タブ】【タブ】,this._isMousedown 【タブ】【タブ】, 【タブ】)( 【タブ】【タブ】call 【タブ】【タブ】,this._stopGuesture 【タブ】) ) @this._startGuesture (set,this._lastX,(R0))φ (set,this._lastY,(R1))φ (set,this._directionChain,)φ (set,this.startX,(R0))φ (set,this.startY,(R1))φ (set,this._scope,(R3))φ (set,this._collision,(R4)) *this._progressGesture $x【タブ】(R0) $y【タブ】(R1) $dx=(x)-(when,(変数「this._lastX」の存在),(this._lastX),0) $abs_dx=(dx)*(-1) $dx【タブ】(when,(dx)<0,(abs_dx),(dx)) $dy=(y)-(when,(変数「this._lastY」の存在),(this._lastY),0) $abs_dy=(dy)*(-1) $dy【タブ】(when,(dy)<0,(abs_dy),(dy)) $dummy【タブ】(when,(dx)<(TOLERANCE)&&(dy)<(TOLERANCE),,(call,this._progressGestureNext)) @this._progressGestureNext ( 【タブ】when 【タブ】,(dx)>(dy) 【タブ】,( 【タブ】【タブ】when 【タブ】【タブ】,(x)<(this._lastX) 【タブ】【タブ】,(set,direction,L) 【タブ】【タブ】,(set,direction,R) 【タブ】),( 【タブ】【タブ】when 【タブ】【タブ】,(y)<(this._lastY) 【タブ】【タブ】,(set,direction,U) 【タブ】【タブ】,(set,direction,D) 【タブ】) )( 【タブ】when 【タブ】,(direction)!=(call,lastDirection) 【タブ】,(set,this._directionChain,(call,this._directionChain)(direction)) )( 【タブ】set 【タブ】,lastDirection 【タブ】,(direction) )( 【タブ】set 【タブ】,this._lastX 【タブ】,(x) )( 【タブ】set 【タブ】,this._lastY 【タブ】,(y) ) @this._stopGuesture ( 【タブ】when 【タブ】,(変数「this._directionChain」の存在) 【タブ】,(call,sendOnMouseGestureEx)\e )( 【タブ】call 【タブ】,clearMouseGestureParameter ) @sendOnMouseGestureEx \![raise,OnMouseGestureEx,(call,this._scope),(call,this._lastX)(バイト値,1)(call,this._lastY),(R4),(call,this.startX)(バイト値,1)(call,this.startY),(call,this._collision),(call,this._directionChain)] @clearMouseGestureParameter (set,this._scope,)φ (set,this._collision,)φ (set,this._lastX,)φ (set,this._lastY,)φ (set,this.startX,)φ (set,this.startY,)φ (set,this._directionChain,)φ (set,x,)φ (set,y,)φ (set,dx,)φ (set,dy,)φ (set,abs_dx,)φ (set,abs_dy,)φ (set,direction,)φ (set,lastDirection,) @OnMouseGestureEx ( 【タブ】when 【タブ】,(R0)==0 【タブ】,( 【タブ】【タブ】when 【タブ】【タブ】,(単語群「gesture.(R5)」の存在) 【タブ】【タブ】,( 【タブ】【タブ】【タブ】set 【タブ】【タブ】【タブ】,action 【タブ】【タブ】【タブ】,(call,gesture.(R5)) 【タブ】【タブ】),( 【タブ】【タブ】【タブ】set 【タブ】【タブ】【タブ】,action 【タブ】【タブ】【タブ】,未定義 【タブ】【タブ】) 【タブ】)\0\_q(R5) : (action)\_q\e(set,action,) ) @gesture.L 戻る @gesture.R 進む @gesture.D 新窓 @gesture.DR 閉じる @gesture.UD 更新 @gesture.UDUDRLRLDLUR エターナルフォースブリザード
【タブ】は適宜Tabに置き換えて使用してください。
華和梨の集合演算式というものの存在を初めて知ったので
06/01は集合演算記念日
// 和集合演算関数 entry.plus { _entry1 = EVAL(_argv[0]) _entry2 = EVAL(_argv[1]) _ret = _entry1 foreach _entry2; _e { if !(ASEARCH(_e, _ret) >= 0) { _ret ,= _e } } _ret } // 差集合演算関数 entry.minus { _entry1 = EVAL(_argv[0]) _entry2 = EVAL(_argv[1]) _ret = IARRAY() foreach _entry1; _e { if !(ASEARCH(_e, _entry2) >= 0) { _ret ,= _e } } _ret } // 積集合演算関数 entry.product { _entry1 = EVAL(_argv[0]) _entry2 = EVAL(_argv[1]) _ret = IARRAY() foreach _entry1; _e { if ASEARCH(_e, _entry2) >= 0 { _ret ,= _e } } _ret } /** * 和集合を使った例 */ foo { _plus = entry.plus('野菜', '果物') _ret = '' foreach _plus; _p { _ret += _p + ', ' } '\0\_q' + _ret + '\e' // => \0\_qきゅうり, なす, スイカ, トマト, りんご, みかん, なし, \e } 野菜 : array { 'きゅうり' 'なす' 'スイカ' 'トマト' } 果物 : array { 'りんご' 'みかん' 'なし' 'スイカ' 'トマト' }
あまりスマートじゃないですね。
EVALは邪道。
ゴーストの更新を捕捉するRSSが欲しくなったので作ってみました。
ついでなので色々な形式で出力してみました。
RSSはSSPのエクスプローラの一括更新で参照されるRSSと互換性があります。
起動したGHOSTの情報を吸い上げて巡回先リストに追加(既に存在している場合は「上書き更新」)するPLUGINです。
もちろん更新URLを持たないGHOSTは追加できません。
また、巡回先が404だったり、何らかの原因で更新時刻を取得できなかった場合は自動的に巡回リストから削除されます。
探せば20~30個は出てきます。決して大袈裟な数字ではなく。
難易度高そうですが取得できないGHOSTさんがわりといるのでどうにかしたい。
登録完了通知を受けても反映されない場合は多分更新時刻の取得に失敗してリストから削除されたものと思われます。
出力されたものは全て静的なファイルなので高速なのですが。
巡回が一件一件順番に回っているので100件とかになったら多分パンクする気がする。
マルチスレッドで処理できるような方法を探ってみる。
理論上は難しいことではないのですが。
GHOSTに混ぜて出力すると見づらいだろうし、別に出力するほど更新に対応している数は少ないだろうし。
SSPで一括更新とかに利用できるなら便利かもしれない。
バグ潰しに比べて優先順位は落ちると思います。
Lingrのサービス終了に伴い後継の候補と見られるチャットが試験的に運用されているようです。
IRCベースとのことで入室しないことにはROMもできないようですが、リアルタイムでログを外部に出力しているので閲覧は可能のようです。
ただブラウザで常駐するのは厳しいですしLingrRaderのような監視ツールが個人的に欲しいなと思ったのでやっつけ仕事でPLUGINで作ってみました。
例によって自作のPLUGINの使いまわしです。
TL get interval を 1 min に設定しておけばほぼリアルタイムの監視ツールとして代用が利くのではないかと思います。
試験運用中な上、まだこのチャットで正式に決まったわけではない模様です。
PLUGINは09/05/07現在のレイアウトと仕様に合わせて作成していますが明日には使えなくなるかもしれません。
余計な負荷がかかってご迷惑をお掛けすると判断した場合には即座に公開を停止致します。
こちらで正式に確定した模様です。
SofTalkが更新されていたのでRSSセッティングも差し替えました。
一度アンインストールしてからインストールし直し推奨です。
色々試してみましたが自分がつまづいたところなどをまとめておきたいと思います。
SofTalk.exeをダブルクリックするとGUIで起動します。
「オプション」→「環境設定」→「その他」→「引数をファイル名/オプションとして処理する」にチェック。
これを設定しないとそもそも起動・終了・設定変更などが外部から指定できません。
設定オプション・実行オプションについてはreadme.txtに大変詳しく書かれているので参考にしましょう。
そもそもSAORI/1.0に準拠したものではないです。
SAORI-basicとして無理やり使おうとしているので仕方ないですが、Load時に反応が無いのが致命的です。
里々であればタイムアウトが設定されているのでエラーを返して元に戻りますが、他の栞でSAORI "Basic" Proxy DLLなどを経由しようとするとそこでフリーズして終了すらできなくなります。
「RSSセッティング」は里々をSAORIとして呼び出してそれを経由して使っています。
SHIORIがUnloadされたら明示的にcloseで終了させます。
Windowsタスクマネージャで確認できますが、これを忘れると起動しっぱなしになります。
二重起動はできませんので終了させないと次の起動時に使えません。
デバッグ時にcloseを忘れたらWindowsタスクマネージャから直接終了させるしかありません。
里々は素晴らしいですね。
元々はヘッドライン/RSSの選択肢タイムアウトをユーザ側で設定したいという要望に応えて制作したPluginですが、SofTalkによる読み上げ機能を追加してみました。
本体設定の接続(2)の「自動的にチェック」をOFFにしてお使い下さい。
SofTalkの使用にはMicrosoft .NET Framework 2.0以上が必要となります。
デフォルトでOFFなので設定でONにしてください。
その際、里々のタイムアウトエラーが出ますが気にしないで下さい。
ネットワーク更新もできます。
以下のパラメータを変更できるようにしたつもりです。
「つもり」というのは、実は私の環境では速度と音量に変化が無いんですよね(´・ω・`)
そういえばVistaに変えてからdsaudio.dllの音量調整も効かなくなったのです。
OS依存でしょうか…XPでも変化無かった場合は私のミスだと思います。
AquesTalkの音声ライブラリを利用した音声合成読み上げソフト。
これを使ってGHOSTに喋らせる試みを持たれた人がいたので私も挑戦。
特徴をまとめると以下のような感じです。
SAORI-basicとして使えるので里々であればsatori_conf.txtの@SAORIに登録するだけですぐに使えます。
漢字やアルファベットも読めるので、ヘッドライン等の未知の文字列が渡される場合でも対応できそうです。
ただSAORI-basicなので若干遅い印象。
AquesTalkを利用したSAORIは現在AquesTalkSaoriがありますね。
ひらがな以外での用途が必要な時はSofTalkを使ってみるのも面白いかもしれません。