2024年11月26日火曜日

PPx 2.00

PPxがメジャーバージョンアップをして、2.00になりました。おめでとうございます。1.00は2008年らしいので、私がPPxを使い始める前ですね。素晴らしいソフトとその作者さんに感謝を!

私とPPx

私は、2000年代初頭にPCを入手してすぐ、ソフトウェアカスタマイズに手を出し始めた。PPxの存在を知ったのは、覚えらんない人の「俺がランチャを捨てたわけ」という記事に、名前があがっていたからだと思う。

当時はソフトウェアカスタマイズブログがたくさんあったが、PPxの情報は比較的少なかった。2chでは、PPxは超高性能だがカスタマイズも超難解という評価で、ファイラースレには挫折した報告や、挫折せずに続ける方法を考察したレスなどがあった。専スレは内容が高度すぎて何を言ってるのかほとんどわからなかった。このような状況下で、ソフトウェアカスタマイズ界隈初心者の私は、PPxをただ仰ぎ見るだけだった。

2009年あたりになって、やっとPPxを使い始める。その時には、PPxについて解説したブログがいくつかあり、それを見ながら外部ソフトを起動する方法を調べたり、キーバインドをいじったりしていた。そのうち、自分でも記事を書くようになったみたいです。

2024年10月28日月曜日

書庫ファイル内の画像をサムネイルに

書庫ファイル内の画像ファイルをサムネイルにする。

準備

以下の二つのファイルをScriptフォルダに保存。

//!*script
// 書庫ファイルから画像を抽出する
// 7zipが必要
// 第一引数:書庫ファイルのパス
//
// 例:*setentryimage %*script(%0Script\getarchiveimage.js,%FCD) -save
// 引数がなければ終了
if (PPx.Arguments.Length < 1){
PPx.SetPopLineMessage("引数が正しくありません。");
PPx.Quit();
}
// 7z.exeのパス
//var exec = "C:\\Program Files\\7-Zip\\7z.exe";
const exec = PPx.Extract('%\'7z\'');
const tempdir = PPx.Extract("%*temp(name,d)");
const sorce_file = PPx.Arguments(0);
const fso = PPx.CreateObject("Scripting.FileSystemObject");
const allowExtensions = /\.(jpg|jpeg|png|gif)$/i; // 拡張子の指定
// 7zipで一時フォルダに解凍
const command = '%OBnsq ' + exec + '' + ' e -y ' + ' -o\"' + tempdir + '\" \"' + sorce_file + '\"';
PPx.Execute(command);
// ファイルパスを取得
const objFolder = fso.GetFolder(tempdir);
const enmFile = PPx.Enumerator(objFolder.Files);
for (; !enmFile.atEnd(); enmFile.moveNext()){
f_name = enmFile.item().Name.toUpperCase();
if (f_name.match(allowExtensions)){
const cover_path = PPx.Extract('%*name(BCD,"'+f_name+'","'+tempdir+'")');
PPx.Result = cover_path;
break;
}
}
//!*script
//
// 書庫ファイルの表紙画像をサムネイルにする
// カレントフォルダのマークファイルかつ書庫ファイルに対して実行
// このスクリプトと同じフォルダにgetarchiveimage.jsを置く必要
// e.g. *script %0Script\setarchiveimage_marked.js
const script_dir = PPx.Extract('%*name(KD,"' + PPx.ScriptName + '")');
const allowExtensions = /\.(zip|rar)$/i; // 拡張子の指定
// マークがない場合の処理
if (!PPx.EntryMarkCount) {
const filepath = PPx.Extract('%1') + "\\" + PPx.EntryName;
if (PPx.EntryName.match(allowExtensions)&& !(PPx.EntryAttributes & 16)){
const img = PPx.Extract('%*script('+script_dir+'\\getarchiveimage.js,"'+filepath+'")');
PPx.Execute("*setentryimage "+img+" -save");
}
} else {
// マークがある場合の処理
PPx.EntryFirstMark;
while(true){
const filepath = PPx.Extract('%1') + "\\" + PPx.EntryName;
if (PPx.EntryName.match(allowExtensions)&&!(PPx.EntryAttributes & 16)){
const img = PPx.Extract('%*script('+script_dir+'\\getarchiveimage.js,"'+filepath+'")');
PPx.Execute("*setentryimage "+img+" -save");
}
if(PPx.EntryNextMark != 1) break;
}
}

やり方

エントリ表示形式を、画像が含まれるものに変更する。とりあえずは、[;]で表示されるメニューから「サムネイル1」を選んでおけばいい。こうしないと、以下の過程で「no image mode」と言われてしまう。

カーソル下の書庫ファイルのサムネイルを変更したい場合は、以下のコマンドを実行する。

*setentryimage %*script(%0Script\getarchiveimage.js,%FCD) -save

複数の書庫ファイルのサムネイルを同時に変更したい場合は、ファイルをマークした後、以下のコマンドを実行する。

*script %0Script\setarchiveimage_marked.js

2024年10月26日土曜日

PPvでEPWING形式の辞書を引く(PPvを分割)

PPvを分割して別のPPvを開いたり閉じたりする動作が気に入ったので、PPv+EBWIN4もこの形式にしてみる。

必要なもの

EBWIN4には、EPWING形式の辞書をあらかじめ登録しておこう。

準備

以下の二つのファイルをScriptフォルダに保存する。dic.luaのEBWIN4のパスは環境に応じて読み替えてください。

--EBWIN4で検索した結果をファイルに出力
--第一変数:検索語
--第二変数:出力ファイルパス
ebwin="D:\\bin\\EBWIN4\\ebwinc.exe /C=1 /E=u"
nyagos.exec(ebwin .. " " .. arg[1] .. " > " .. arg[2])
view raw dic.lua hosted with ❤ by GitHub
//!*script
// PPvのカーソル位置にある文字を返す
// 単語が空白区切りであることが前提
// 例: *linemessage %*script(%0\Script\selectword.js)
var linetext = PPx.Extract('%*selecttext');
var lh = PPx.Extract('%lH');
// var blankpos = linetext.indexOf( ' ' );
// 文字列を左右に分割し、空白前/後を削除
var lstr = linetext.substr( 0, lh ).replace(/.*\s(.*?)$/, '$1');
var rstr = linetext.substr( lh ).replace(/^(.*?)\s.*/, '$1');
// 文字列を再結合
var str = lstr+rstr;
// 句読点等を取り除く
var result = str.replace(/(\.|\,|\"|\'|\!|\?|\;|\:)/g, '');
// ’以前を取り除く。フランス語の単語抽出用
var result = result.replace(/.*’(.*)$/, '$1');
// 文字数が45を超えていれば以降のコマンド実行を中止
if (result.length > 45){
PPx.SetPopLineMessage("文字数が多すぎます");
PPx.Quit(-1);
}
PPx.Result = result;
PPx.Quit();
view raw selectword.js hosted with ❤ by GitHub

以下を編集して取込。

_Command    = {    ; ユーザコマンド・関数
splitppv    = *string i,height0=%*windowrect(,h)
    *string i,height1=%*calc("%*arg(2)*%*windowrect(,h)/100")
    *string i,height2=%*calc("%*windowrect(,h)-%si"height1"")
    *windowsize %N,%*windowrect(,w),%si"height1"
    *ppv -bootid:X -k %%J"%*arg(1)" %%: *fitwindow %N,%%N,4 %%: *windowsize %%N,%*windowrect(,w),%si"height2" %%: *selectppx %n
ebwin2ppv = *string i,ratio=%*arg(1)
    *string i,tempfile=%*temp(name,f)
    %Oi nyagos -f %0Script\dic.lua %*script(%0Script\selectword.js) %si"tempfile"
    *ifmatch 0,0%NVX %: *splitppv %si"tempfile",%si"ratio" %: *mapkey use,K_splitppv %: *stop
    *execute VX,%%J%si"tempfile"
}

K_splitppv    = {
Q    ,*ifmatch !0,0%NVX %: %Oi *windowsize %N,%*windowrect(,w),%si"height0"
    *mapkey delete,K_splitppv
    *closeppx "%n,VX"
ENTER    ,*ifmatch !0,0%NVX %: %Oi *windowsize %N,%*windowrect(,w),%si"height0" %: *closeppx VX %: *stop
    *splitppv %si"tempfile",%si"ratio"
}

やり方

[I]でキャレットモードにしてから、辞書を引きたい単語を範囲選択して、以下のコマンドを実行する。

*ebwin2ppv 50

引数で分割の割合を変更できる。単位は百分率。半分にしたかったら50、四分の一なら75、とすればいい。 僕はマウス中クリックでこのコマンドを起動するようにしている。

MV_click    = {    ; PPv メイン窓
M_SPC    ,*ebwin2ppv 50
}

参考

つかさのほえほえ日記: PPvでEPWING形式の辞書を引く

2024年10月23日水曜日

コメントを検索してマーク

僕はhowm形式でメモを取り、タイトルをコメントで表示している(参考:moe | メモの方法論)。

「TODO」「借りたい本」「日付」みたいに、特定の文字列がタイトルに含まれるエントリをまとめて処理するため、コメントの文字列を検索してマークするスクリプトを作った。

//!*script
// 第一引数で指定した文字列をコメントに含むファイルをマーク
// e.g. *script %0Script\commentmark.js,"^TODO "
// 引数がなければ終了
if (PPx.Arguments.Length < 1){
PPx.SetPopLineMessage("引数が正しくありません。");
PPx.Quit();
}
const re = new RegExp(PPx.Arguments.Item(0), "i");
for (var i = 0; i < PPx.EntryAllCount; i++) {
if (PPx.Entry(i).Comment.match(re)){
PPx.Entry(i).Mark = 1;
}
}
view raw commentmark.js hosted with ❤ by GitHub

コメント行頭が「TODO 」のエントリをマークしたい場合は以下。

*script %0Script\commentmark.js,"^TODO "

コメントが「2024-10-23」といった形式のエントリをマークしたい場合は以下。

*script %0Script\commentmark.js,"^[0-9]{4}-[0-9]{2}-[0-9]{2}$"

2024年10月21日月曜日

リストファイルの表示形式を事前に変更

リストファイルの用途は様々で、その用途に応じて適切な表示形式もかわる。リストファイルにジャンプしたあと、一々[;]で切り替えるのも面倒なので、事前にコマンドで変更できるようにする。

やり方

以下のコマンドを、リストファイルへのジャンプ前に一度実行する。これは一覧1(&L)に切り替える例。

*string o,hoge=一覧1(&L) %: *diroption -listfile cmd:"*viewstyle -listfile %so"hoge" %%: *diroption -listfile cmd:"""

一覧&2なら次のようになる。

*string o,hoge=一覧&2 %: *diroption -listfile cmd:"*viewstyle -listfile %so"hoge" %%: *diroption -listfile cmd:"""

以下は*whereisと組み合わせた例。

*string o,hoge=一覧1(&L) %: *diroption -listfile cmd:"*viewstyle -listfile %so"hoge" %%: *diroption -listfile cmd:""" %: *whereis

解説

*diroption -listfile cmd:"任意のコマンド" により、リストファイル表示時に任意のコマンドを実行することができる。 ここに、

  • 表示形式を変更
  • 自分自身を削除

の2つのコマンドを登録することで、リストファイル表示時に一度だけ、表示形式を変更することができる。FIRSTEVENTを使った以前からあるテクニックの応用ですね(詳しくはヘルプで「FIRSTEVENT を使用する」を検索)。

2024年10月5日土曜日

テキストファイル内の画像パスをPPVで表示

テキストファイル中に画像ファイルのパスを書いておけば、それを別IDのPPVで閲覧できるようにする。これで、テキストファイルのメモでも画像や図を扱いたい!という我々の永遠の課題を解決できるかもしれない?

準備

以下をScriptフォルダに保存。

//!*script
// 特定の拡張子が書かれた行の文字列を取得
// 例: %I%*script(%0Script\getimagepath.js,1)
// 第一引数(省略可能):獲得する行の上限
const num = (PPx.Arguments.length) ? PPx.Arguments(0) : -1; // 獲得する行の上限
const filepath = PPx.Extract("%FCD");
const separator = ","; // 区切り文字
const allowExtensions = /\.(jpg|jpeg|png|gif)$/i; // 拡張子の指定
const fso = PPx.CreateObject('Scripting.FileSystemObject');
const f = fso.OpenTextFile(filepath, 1);
let str = "";
let i = 0;
while(! f.AtEndOfStream){
const line=f.ReadLine();
if (line.match(allowExtensions)) {
str += line+separator;
i += 1;
}
if (i == num){
break;
}
}
f.close();
PPx.result=str.slice(0, -1); // 末尾の区切り文字を削除
view raw getimagepath.js hosted with ❤ by GitHub

以下を編集して取り込み。

_Command    = {    ; ユーザコマンド・関数
openhalfppv    = *windowsize %N,%*windowrect(,w),%*calc("%*windowrect(,h)/2")
    *ppv -bootid:X -k %%J"%*arg(1)" %%: *fitwindow %N,%%N,4 %%: *windowsize %%N,%*windowrect(,w),%*windowrect(,h) %%: *selectppx %n
previewimagepath = *openhalfppv %*script(%0Script\getimagepath.js,1)
    *mapkey use,K_halfppv
    *linecust imgpreview,KV_main:LOADEVENT,*ifmatch %%n,%n %(%: *RotateCustomize _User:imgpath,%*script(%0Script\getimagepath.js) %: *ifmatch !0,0%*getcust(_User:imgpath) %: *execute VX,%%J"%*getcust(_User:imgpath)"%)
    *linecust quitimgview,KV_main:CLOSEEVENT,*ifmatch %%n,%n %%: *linecust imgpreview,KV_main:LOADEVENT, %%: *linecust quitimgview,KV_main:CLOSEEVENT,
}

K_halfppv    = {
Q    ,*ifmatch !0,0%NVX %: %Oi *windowsize %N,%*windowrect(,w),%*calc("%*windowrect(,h)*2")
	*closeppx "%n,VX"
^N    ,*RotateCustomize _User:imgpath,%*script(%0Script\getimagepath.js) %: *execute VX,%%J%*getcust(_User:imgpath)
ENTER    ,*ifmatch !0,0%NVX %: %Oi *windowsize %N,%*windowrect(,w),%*calc("%*windowrect(,h)*2") %: *closeppx VX %: *stop
	*openhalfppv %*script(%0Script\getimagepath.js,1)
}

やり方

画像ファイルパスを書き込んだテキストファイルを用意し、PPVで表示する。

PPV上で以下のコマンドを実行。

*previewimagepath

PPVの大きさが半分になり、空いたスペースにPPV[X]が起動。画像ファイルを表示する。

PPvの表示ファイルが切り替わると、表示画像も切り替わる。以下はPPv中心の連動ビュー(参考:一対一対応 | PPxMemo)と組み合わせたもの。

その他キーバインド

  • [ENTER] 画像表示非表示トグル
  • [Q] 半分になったPPVの大きさをもとに戻してから終了
  • ^[N] テキストファイル内の次の画像ファイルパスを表示

追記 2024-10-14

表示している画像ファイルパスをハイライトする設定は以下。

_Command    = {    ; ユーザコマンド・関数
openhalfppv    = *windowsize %N,%*windowrect(,w),%*calc("%*windowrect(,h)/2")
    *ppv -bootid:X -k %%J"%*arg(1)" %%: *fitwindow %N,%%N,4 %%: *windowsize %%N,%*windowrect(,w),%*windowrect(,h) %%: *selectppx %n
previewimagepath = *openhalfppv %*script(%0Script\getimagepath.js,1)
    *mapkey use,K_halfppv
    *highlight %*script(%0Script\getimagepath.js,1)
    *linecust imgpreview,KV_main:LOADEVENT,*ifmatch %%n,%n %(%: *RotateCustomize _User:imgpath,%*script(%0Script\getimagepath.js) %: *ifmatch !0,0%*getcust(_User:imgpath) %: *execute VX,%%J"%*getcust(_User:imgpath)" %: *highlight %*getcust(_User:imgpath)%)
    *linecust quitimgview,KV_main:CLOSEEVENT,*ifmatch %%n,%n %%: *linecust imgpreview,KV_main:LOADEVENT, %%: *linecust quitimgview,KV_main:CLOSEEVENT,
}

K_halfppv    = {
Q    ,*ifmatch !0,0%NVX %: %Oi *windowsize %N,%*windowrect(,w),%*calc("%*windowrect(,h)*2")
	*closeppx "%n,VX"
^N    ,*RotateCustomize _User:imgpath,%*script(%0Script\getimagepath.js) %: *execute VX,%%J%*getcust(_User:imgpath) %: *highlight %*getcust(_User:imgpath)
ENTER    ,*ifmatch !0,0%NVX %: %Oi *windowsize %N,%*windowrect(,w),%*calc("%*windowrect(,h)*2") %: *closeppx VX %: *stop
	*openhalfppv %*script(%0Script\getimagepath.js,1)
}

2024年9月27日金曜日

wgetで取得した画像をPPvで表示

画像をローカルに保存するのが面倒なときのために。 以下を編集して取込。

_Command = {
wget2file = *string o,hoge=%*temp(name,f)
  %Os wget -O %so"hoge" %*arg(1)
  *return %so"hoge"
}

以下のようにして使う。

*ppv %*wget2file("https://pbs.twimg.com/media/F0vVsgTaYAsUHkA?format=jpg")

2024年9月15日日曜日

ファイル検索ダイアログ完了時にコマンド実行

問題意識

僕はhowm形式でメモを取っている(参考:moe | メモの方法論)。howmファイルの一行目をコメントにするスクリプトを利用して、以下のようにタイトルを表示している。

このメモの中から、^[W]でファイル検索をすることがあるのだが、その結果は次のようになる。

00_INDEX.TXTで紐づけたコメントは、当然ListFileでは反映されない。 タイトルが表示されない分視認性は低いが、そもそもあまり検索することもないし、特に不便だとも思ってなかったので、ずっと放置していた。

X_jinfc

最近気付いたのだが、X_jinfcを使えばこの問題を解決することができる。X_jinfcを使うと、ダイアログ完了時にコマンドを実行することができる。

以下をScriptフォルダに保存。これはhowmファイルからタイトルを取得するスクリプト。

//!*script
// howmファイル一行目2文字~30字を返すスクリプト
// 第一引数:howmファイルのパス
// 例 *linemessage %*script(%0Script\gethowmtitle.js,%R)
// 引数がなければ終了
if (PPx.Arguments.Length < 1){
PPx.SetPopLineMessage("引数が正しくありません。");
PPx.Quit();
}
const file = PPx.Arguments.Item(0);
const fso = PPx.CreateObject("Scripting.FileSystemObject");
const name = PPx.Extract('%*name(C,'+file+')');
const ext = PPx.Extract('%*name(T,'+file+')');
if (ext=="howm") {
const data = fso.OpenTextFile(file, 1);
const str = data.ReadLine().slice( 2,30 );
data.Close();
PPx.result = str;
} else {
PPx.result = name;
}
view raw gethowmtitle.js hosted with ❤ by GitHub

以下を編集して取込。

X_jinfc = {
whereiscompcmd = *ifmatch "/D:\\work\\memo/",%1 %: *comment all extract,%(%*script(%0Script\gethowmtitle.js,%FCD)%)
}

これで、D:\work\memo以下で^[W]による検索をした場合、howmファイルから自動でタイトルを取得し、それをコメントにしてくれる。

一番上の「.」「..」がコメント表示になってなくて気になる場合は、以下をScriptフォルダに追加で保存してから

//!*script
// 「.」「..」にコメントを付ける
for (var i = 0; i < PPx.EntryAllCount; i++) {
if (PPx.Entry(i).Name == "." && PPx.Entry(i).Comment == ""){
PPx.Entry(i).Comment = ".";
} else if (PPx.Entry(i).Name == ".." && PPx.Entry(i).Comment == ""){
PPx.Entry(i).Comment = "..";
}
}
view raw dotcomment.js hosted with ❤ by GitHub

以下を編集して取込すればいい。

X_jinfc = {
whereiscompcmd = *ifmatch "/D:\\work\\memo/",%1 %: *comment all extract,%(%*script(%0Script\gethowmtitle.js,%FCD)%) %: *script %0Script\dotcomment.js
}

2024年9月12日木曜日

EVENTで*stopの代わりに*gotoを使う

EVENTで*stopを使うと、*linecustと相性が悪い場合があるので、代わりに*gotoを使う話です。

問題意識

FIRSTEVENTやLOADEVENTで、*ifmatchと*stopを使って条件分岐をすることは、よくあることだと思う。以下はPPC起動時に、IDが[A]ならhogeを、それ以外ならfugaをメッセージ表示する設定。

KC_main    = {    ; PPcメイン窓
FIRSTEVENT    ,*ifmatch CA,%n %: *linemessage hoge %: *stop
    *linemessage fuga
}

これだと、後で別の設定を*linecustで追加しようとした時、困ったことが起きる。例えば、PPC起動時にメッセージウインドウを表示しようとして、以下のコマンドを実行したとする。

*linecust homu,KC_main:FIRSTEVENT,%%I"hello world"

すると、FIRSTEVENTは以下のようになる。

KC_main    = {    ; PPcメイン窓
FIRSTEVENT    ,*ifmatch CA,%n %: *linemessage hoge %: *stop
    *linemessage fuga
    %mhomu %I"hello world"
}

これでは、想定した通りの動きにならない。起動したPPCのIDが[A]の時、一行目で処理が止まるからだ。手動で処理の順序をいじったりすれば解決するかもしれないが、そういうややこしいことはできればしたくない。

*stopの代わりに*gotoを使う

*stopの代わりに*gotoを使えば、この問題は解決しそうだ。

KC_main    = {    ; PPcメイン窓
FIRSTEVENT    ,*ifmatch CA,%n %: *linemessage hoge %: *goto Last
    *linemessage fuga
    %mLast
}

これなら、*linecustで追加した処理が無事実行されることになる。

KC_main    = {    ; PPcメイン窓
FIRSTEVENT    ,*ifmatch CA,%n %: *linemessage hoge %: *goto Last
    *linemessage fuga
    %mLast
    %mhomu %I"hello world"
}

*linecustが使いやすくなる分だけ、*stopよりも*gotoの方が少しお得。これがホントのgoto EVENTってやつですねw

:y=-( ゚д゚)・∵;; ターン

2024年9月10日火曜日

スクリプトをES6へ移行

PPxで使うスクリプトをES6に移行する方法です。 ほえほえ日記のスクリプトも、今後は基本的にES6で書くつもりです。

WSH Script Moduleのアップデート

WSH Script Module(旧名Script Module)を最新バージョンにする。R21+1でPPx.Enumeratorが使えるようになるので、それ以前のバージョンを使っているならアップデートは必須。PPx本体も最新のものにしておく。

既存のスクリプトを修正

ES6では使えないオブジェクトがいくつかある(参考:WSH JScript で利用できる機能まとめ | なたで日記)。おそらく問題になるのはActiveXObjectとEnumeratorの2つ。以下のように修正する。

JScript

var e = new Enumerator(FileCollection); 
var fso = new ActiveXObject('Scripting.FileSystemObject');

ES6

var e = PPx.Enumerator(FileCollection);
var fso = PPx.CreateObject('Scripting.FileSystemObject');

編集して取込

以下を編集して取込した後、PPxを再起動する。

_Others:usejs9=4

参考

2024年9月1日日曜日

一行編集のキーバインドをスイッチ

僕は、補完候補ファイルに記述したコマンドを、一行編集から呼び出して使っている。これだと「あれ、あのコマンドどのキーに登録したっけ」ということがなくなり、便利なのだ。

今回行うのは、一行編集上での疑似自動補完の切り替え。

準備

以下を編集して取込。補完候補ファイルはPPxフォルダ内のlaunch.txtという想定。

_Command	= {	; ユーザコマンド・関数
ppl2	= *ifmatch 0,0%*getcust(_User:ppx_keymode) %: *setcust _User:ppx_keymode=K_pplnormal
	*string o,name=%*input("" -title:"%*substring(%*getcust(_User:ppx_keymode),5) mode ^Rで実行コマンド切り替え" -mode:h -leavecancel -k:"*completelist -file:%%0launch.txt -match:6 -detail:""hist:h user alias"" %%: *mapkey use,%*getcust(_User:ppx_keymode)")
	*execute,%so"name"
}

-|K_pplnormal=
-|K_pplautocorrect=

K_pplnormal	= {
ENTER	,%K"@ENTER"
^R	,*mapkey delete,K_pplnormal
	*mapkey use,K_pplautocorrect
	*setcust _User:ppx_keymode=K_pplautocorrect
	*setcaption auto correct mode
}

K_pplautocorrect	= {
ENTER	,*ifmatch -1,%*sendmessage(%N-L,392,0,0) %: %K"@DOWN @ENTER" %: *stop
	%K"@ENTER"
^R	,*mapkey delete,K_pplautocorrect
	*mapkey use,K_pplnormal
	*setcust _User:ppx_keymode=K_pplnormal
	*setcaption normal mode
}

やり方

*ppl2を実行すると一行編集が起動する。[^R]で疑似自動補完のオンオフが切り替わる。現在の状態はタイトルバーで確認できる。新規にコマンドを実行したい時はnormalに。既存のコマンドを実行したい時はauto correctにするといいだろう。

参考

2024年8月19日月曜日

PPvで前回開いたパスを開く ~まだ俺達はPPvの真の性能を引き出していない~

概要

PPxにおいて、ビューアであるPPvは何枚でも開くことができる。だが、僕は普段は、PPcと紐づけた形(連動ビュー)でしかPPvを使えていない。この場合、使えるPPvの数はPPcの数に規定されることになる。せいぜい3、4枚といったところだ。 これでは、PPvの真の性能を引き出しているとはいえないんじゃないか。PPvをズラッと何枚も並べ、それぞれに異なるファイルを表示して見比べる活用法があるんじゃないか。このような問題意識を、僕はずっと持っていた。

この問題には、過去にも何度か取り組んだことがあるが、あまり成果は出なかった。ここからは「ファイルパスはどこにどの形式で保存するか」「位置関係は保存すべきか」「保存したとしてどう再現するか」「保存したパスをどのIDのPPVで開くか」等の複雑な課題が生じてくる。これを解決しようとすると、スクリプトなり、リストファイルなりを駆使した、運用が複雑なものが出来上がる。そして結局は、その複雑さゆえに使わなくなる。これが今までのパターンだった。 最近、「PPv終了時にIDごとにパスを保存し、次回起動時にはそのパスを開く」という単純な仕組みで、これらの課題は解決するんじゃないか、と思いついた。

実装について

以下の形で実装する。

  • データの保存には、S_xxxを活用する。例えばPPV[F]のパスはS_ppvpath:Fに、PPV[G]のパスはS_ppvpath:Gに保存する、というように
  • PPV[F]~PPV[W]を今回の用途に使う。PPV[A]~PPV[E]は、通常のPPcと紐づけた運用に。PPV[X}~PPV[Z]は他の特殊な用途にとっておく

準備

以下を編集して取込。

KV_main    = {    ; PPvメイン窓
CLOSEEVENT    ,*ifmatch "o:e,a:d-",%FCD %: *setcust S_ppvpath:%*rightstr("%n", 1)=%FCD %: *stop
    *deletecust S_ppvpath:%*rightstr("%n", 1)
FIRSTEVENT    ,*ifmatch "/[a-ex-z]/",%*rightstr("%n", 1) %: *stop
    *ifmatch !0,0%*getcust(S_ppvpath:%*rightstr("%n", 1)) %: %J%*getcust(S_ppvpath:%*rightstr("%n", 1))
    *mapkey use,K_ppvv
}

K_ppvv    = {    ; 紐づけなしPPv
ESC    ,%J"no such file"
^N    ,*script %0Script\open_plural_ppv.js,2
O    ,*openppcv %FCD
}

K_ppcv    = {    ; 紐づけなしPPvから起動したPPc
ENTER    ,*ifmatch "o:e,a:d+",%FCD %: %K"@ENTER" %: *stop
    %Oi *windowsize %*extract(%%NV%*getcust(_User:syncidppcv)),%*windowrect(,w),%*calc("%*windowrect(,h)*2") %: *closeppx %n %: *stop
Q    ,%Oi *windowsize %*extract(%%NV%*getcust(_User:syncidppcv)),%*windowrect(,w),%*calc("%*windowrect(,h)*2") %: *closeppx %n
}

_Command    = {    ; ユーザコマンド・関数
openppcv    = *setcust _User:syncidppcv=%*rightstr("%n", 1)
    *windowsize %N,%*windowrect(,w),%*calc("%*windowrect(,h)/2")
    *ppc -bootid:%*getcust(_User:syncidppcv) -single -k %%j"%*arg(1)" %%: *mapkey use,K_ppcv %%: *ppvoption sync %*getcust(_User:syncidppcv) %%: *fitwindow %N,%%N,4 %%: *windowsize %%N,%*windowrect(,w),%*windowrect(,h)
}

以下をScriptフォルダにopen_plural_ppv.jsという名前で保存。今まで僕がつくってきたスクリプトとは違い、ES6で書いているので注意。

//!*script
// S_ppvpathに保存したパスをPPvで開く。S_ppvpath:FならPPV[F]で。S_ppvpath:GならPPV[G]で、というように
// 例:*script %0Script\open_plural_ppv.js,1
// 第一引数
// 0:パスを保持したPPvを一斉に起動
// 1:パスを保持したPPvを一斉に起動。一つもなければPPvを一つ開く
// 2:PPvを一つ開く
// 最初のPPVID
// A:65 Z:90
const PPV_ID_START=70;
// PPVIDの範囲
const PPV_MAX=18;
const fs = PPx.CreateObject("Scripting.FileSystemObject");
// 引数がなければ終了
if (PPx.Arguments.Length < 1){
PPx.SetPopLineMessage("引数が正しくありません。");
PPx.Quit(-1);
}
if (PPx.Arguments(0)==0){
openPluralPPv();
} else if (PPx.Arguments(0)==1){
openPluralPPv(1);
} else if (PPx.Arguments(0)==2) {
openNewPPv();
}
// 本体
function openPluralPPv(arg){
const id = [...Array(PPV_MAX)].map((v, i) => String.fromCodePoint(i + PPV_ID_START));
let count = 0;
id.forEach(v => {
const p = PPx.Extract("%*getcust\(S_ppvpath:"+v+"\)").replace(/^"(.*)"$/, '$1'); // 両端の""を取る
if (fs.FileExists(p)) {
PPx.Execute("*ppv -bootid:"+v+" \""+p+"\"");
count ++;
}
});
if (count==0 && arg==1) openPPv();
}
// S_ppvpathにパスが保存されていないPPVを一つ開く
function openPPv(){
const id = [...Array(PPV_MAX)].map((v, i) => String.fromCodePoint(i + PPV_ID_START));
id.some(v => {
const p = PPx.Extract("%*getcust\(S_ppvpath:"+v+"\)").replace(/^"(.*)"$/, '$1');
if (!fs.FileExists(p)) {
PPx.Execute("*ppv -bootid:"+v);
return true
}
});
}
// PPVを新たに一つ開く
function openNewPPv(){
const ppvlist=PPx.Extract("%*ppxlist()").split(",");
const id = [...Array(PPV_MAX)].map((v, i) => String.fromCodePoint(i + PPV_ID_START));
id.some(v => {
if (!ppvlist.includes(`V_${v}`)){
PPx.Execute("*ppv -bootid:"+v);
return true
}
});
}

やり方

以下のコマンドで、S_ppvpathにパスが保存してあるPPVを一斉に開く。一つもなければ、空の状態のPPvを一つ開く。

*script %0Script\open_plural_ppv.js,1

PPvを新たに一つ開きたい場合は、上のコマンドで開いたPPv上で[^N]を押すか、以下のコマンドを任意の場所で実行する。

*script %0Script\open_plural_ppv.js,2

表示ファイルを変えたい場合は、PPV上で[O]を押す。すると、PPCが表示され、PPvが連動ビューの状態になる。目的のファイルを見つけたら、[Enter]か[Q]を押す。 もちろん、単純にドラッグアンドドロップを使うのでもいい。

「もうこのファイルは次回は表示しなくていいや」という場合は、PPV上で[ESC]を押す。すると、存在しないファイルを表示する。この状態で閉じると、保存したパスがリセットされる。

活用案

  • 開きっぱなしにしておきたいテキストを表示する
  • todoを書いたテキストを表示する
  • 見てると落ち着く写真を表示する
  • 見比べたい資料を表示する

といった活用方法がありそう。

2024年8月12日月曜日

PPV単体で書庫内の画像を閲覧

書庫内の画像をPPvで閲覧できるようにする。漫画ビューアでよくあるやつです。 「PPcで書庫に潜ってPPvで連動ビューしたらいいだけじゃん」と言われたらたしかにそうなのだが、PPv単体でできたら便利かもしれないと思いました(小並感)。

準備

以下をgetarchivefiles.jsという名前でスクリプトフォルダに保存。

//!*script
// 書庫内のファイル名をS_xxx1 S_xxx2 S_xxx3 ... と連番で保存。「書庫のパス\S_xxx1の内容」を返す
// PPvを単体で画像ビューアのように扱うためのスクリプト
// 第一引数:書庫のパス
// 第二引数:ファイル名を保存するS_xxx
// 例: *ppv %*script(%0Script\getarchivefiles.js,%FCD,S_archivepages)
// 引数がなければ終了
if (PPx.Arguments.Length < 2){
PPx.SetPopLineMessage("引数が正しくありません。");
PPx.Quit(-1);
}
var source_file = PPx.Arguments(0);
var user_table = PPx.Arguments(1);
var filelist = PPx.Extract("%*run\(tar -tf \""+source_file+"\"\)").split("\r\n");
PPx.Execute("*deletecust \""+user_table+"\""); // S_xxxの初期化
var a = PPx.Extract("%*name\(DCN,"+source_file+"\)"); // 両端の""を取る
for(i = 0; i < filelist.length-1; i++) {
var filepath = PPx.Extract('%*name(KDC,'+a+"\\"+filelist[i]+')'); // パス区切りを「\」に統一
PPx.Execute("*setcust "+user_table+":"+i+"="+filepath);
};
PPx.Result=PPx.Extract("%*getcust\("+user_table+":0\)"); // 「書庫のパス\S_xxx1の内容」を返す

以下を編集して取込。

K_archiveview    = {
RIGHT    ,*ifmatch 0,0%si"pagenum" %: *string i,pagenum=0
    *string i,pagenum=%*calc("%si"pagenum"+1") %: *string o,name=%%*getcust(S_archivepages:%si"pagenum")
    *ifmatch !0,0%sgo"name" %: %J%sgo"name" %: *stop
    *string i,pagenum=%*calc("%si"pagenum"-1")
LEFT    ,*ifmatch 0,0%si"pagenum" %: *string i,pagenum=0 %: *stop
    *if %*calc(%si"pagenum") == 0 %: *stop
    *string i,pagenum=%*calc("%si"pagenum"-1") %: *string o,name=%%*getcust(S_archivepages:%si"pagenum") %: %J%sgo"name"
}

%si"pagenum"は現在見ているページ番号。左右カーソルで1ずつ増減する。

やり方

PPcで書庫ファイルにカーソルをあわせ、以下のコマンドを実行。

*ppv %*script(%0Script\getarchivefiles.js,%FCD,S_archivepages) -k *mapkey use,K_archiveview

最初の画像が表示される。カーソル左右で表示ファイルを切り替える。

2024年7月6日土曜日

アルバムアートをサムネイルに

PPxでは、ファイルだけではなく、フォルダにも任意のサムネイルをつけることができるらしい。 フォルダ内にcover.jpgあるいはfolder.jpgといったアルバムアートがある場合、それをサムネイルにできるようにする。

準備

以下をScriptフォルダに保存。

setalbumart_all.js

//!*script
// フォルダ内のカバーアート(cover.jpg || folder.jpg)をサムネイルにする
// カレントフォルダの各ディレクトリに対して実行
// 例:*script %0Script\setalbumart_all.js
var ALBUM_ART_NAME1="COVER.JPG";
var ALBUM_ART_NAME2="FOLDER.JPG";
var filepath;
var img;
var img_path;
for (var i = 0; i<PPx.EntryAllCount; i++){
PPx.EntryIndex=i;
var name = PPx.EntryName;
if (PPx.EntryAttributes & 16 && name !=('.') && name!=('..')){
filepath = PPx.Extract('%1') + "\\" + name;
img = getcoverart(filepath);
if (img) {
img_path =PPx.Extract('%*name(BCD,'+getcoverart(filepath)+')');
PPx.Execute("*setentryimage "+img_path+" -save");
}
} else {
continue;
}
}
// カバーアート取得用関数
// カーソル下フォルダ内にcover.jpgあるいはfolcer.jpgがあればそれを返す
function getcoverart(dirpath) {
var path = dirpath;
var fso = PPx.CreateObject("Scripting.FileSystemObject");
var thumbnailpath;
var f_name;
// ファイルを取得
var objFolder = fso.GetFolder(path);
var enmFile = PPx.Enumerator(objFolder.Files);
for (; !enmFile.atEnd(); enmFile.moveNext()){
f_name = enmFile.item().Name.toUpperCase();
if (f_name == ALBUM_ART_NAME1 || f_name == ALBUM_ART_NAME2){
thumbnailpath = fso.BuildPath(path, enmFile.item().Name);
break;
}
}
return thumbnailpath;
}

やり方

音楽ファイルをフォルダごとにまとめたフォルダで、以下のコマンドを実行。

*script %0Script\setalbumart_all.js

各フォルダ内にあるcover.jpgあるいはfolder.jpgを取得し、それをサムネイルにする。

2024年7月3日水曜日

epubのカバー画像をサムネイルに

epubのカバー画像をサムネイルにする。Extend convert Susie Plug-in等、やり方は他にも色々ありそうだが、今回は*setentryimageとスクリプトの組み合わせで行う。

準備

以下の二つのスクリプトをScriptフォルダに保存。

getcoverimage.js

//!*script
// epubファイルから表紙画像を抽出する
// 7zipが必要
// 第一引数:epubファイルのパス
//
// 例:*setentryimage %*script(%0Script\getcoverimage.js,%FCD)
// 引数がなければ終了
if (PPx.Arguments.Length < 1){
PPx.SetPopLineMessage("引数が正しくありません。");
PPx.Quit();
}
// 7z.exeのパス
//var exec = "C:\\Program Files\\7-Zip\\7z.exe";
var exec = PPx.Extract('%\'7z\'');
var tempdir = PPx.Extract("%*temp(name,d)");
var sorce_file = PPx.Arguments(0);
var fso = PPx.CreateObject("Scripting.FileSystemObject");
var doc = PPx.CreateObject("MSXML2.DOMDocument");
var container_xml_path = fso.BuildPath(tempdir, "META-INF\\container.xml");
var id_attr;
var cover_path_relative;
var cover_path;
// 7zipで一時フォルダに解凍
var command = '%OBnsq ' + exec + '' + ' x -y ' + ' -o\"' + tempdir + '\" \"' + sorce_file + '\"';
PPx.Execute(command);
// container.xmlからopfファイルのパスを取得
doc.load(container_xml_path);
var opf_path_relative = doc.getElementsByTagName('rootfile')[0].getAttribute('full-path');
var opf_path = PPx.Extract('%*name(KDC,'+ fso.BuildPath(tempdir, opf_path_relative) +')'); // パス区切りを「\」に統一
var opf_dir = PPx.Extract('%*name(D,'+opf_path+')');
// opfファイルからcoverファイルのパスを取得
doc.load(opf_path);
var item_element = doc.getElementsByTagName('item');
for (i = 0;i < item_element.length;i++) {
id_attr = item_element[i].getAttribute('id');
if (id_attr == "cover" || id_attr == "cover-image"){
cover_path_relative = item_element[i].getAttribute('href');
cover_path = PPx.Extract('%*name(KDC,'+fso.BuildPath(opf_dir, cover_path_relative)+')'); // パス区切りを「\」に統一
break;
}
}
for (i = 0;i < item_element.length;i++) {
var props = item_element[i].getAttribute('properties');
if (props == "cover" || props == "cover-image"){
cover_path_relative = item_element[i].getAttribute('href');
cover_path = PPx.Extract('%*name(KDC,'+fso.BuildPath(opf_dir, cover_path_relative)+')'); // パス区切りを「\」に統一
break;
}
}
PPx.Result = cover_path;

setcoverimage_all.js

//!*script
// epubファイルの表紙画像をサムネイルにする
// カレントフォルダのすべてのepubファイルに対して実行
// このスクリプトと同じフォルダにgetcoverimage.jsを置く必要
var script_dir = PPx.Extract('%*name(KD,"' + PPx.ScriptName + '")');
var filepath;
var img;
for (var i = 0; i<PPx.EntryAllCount; i++){
PPx.EntryIndex=i;
// フォルダを除外
if (PPx.EntryAttributes & 16){
continue;
} else if (PPx.EntryName.match(/.epub$/i)){
filepath = PPx.Extract('%1') + "\\" + PPx.EntryName;
img = PPx.Extract('%*script('+script_dir+'\\getcoverimage.js,"'+filepath+'")');
PPx.Execute("*setentryimage "+img+" -save");
}
}

epubの解凍には7zipを利用する。7zipをインストールしていない場合はインストールしておく。また、getcoverimage.jsの7zipに関する箇所を各自の環境にあわせて書き換えておく。

やり方

エントリ表示形式を、画像が含まれるものに変更する。とりあえずは、[;]で表示されるメニューから「サムネイル1」を選んでおけばいい。こうしないと、以下の過程で「no image mode」と言われてしまう。

カーソル下のepubファイルのサムネイルを変更したい場合は、以下のコマンドを実行する。

*setentryimage %*script(%0Script\getcoverimage.js,%FCD)

カレントフォルダのすべてのepubファイルのサムネイルを変更したい場合は、以下を実行する。まあまあ時間がかかるので、大量にファイルがある場合は注意。

*script %0Script\setcoverimage_all.js

追記2024-10-18

マークファイルのサムネイルを変更するスクリプトを作った。ES6で記述。

//!*script
//
// ES6で記述
// epubファイルの表紙画像をサムネイルにする
// カレントフォルダのマークファイルかつepubファイルに対して実行
// このスクリプトと同じフォルダにgetcoverimage.jsを置く必要
// e.g. *script %0Script\setcoverimage_marked.js
const script_dir = PPx.Extract('%*name(KD,"' + PPx.ScriptName + '")');
PPx.EntryFirstMark;
while(true){
const filepath = PPx.Extract('%1') + "\\" + PPx.EntryName;
if (PPx.EntryName.match(/.epub$/i)){
const img = PPx.Extract('%*script('+script_dir+'\\getcoverimage.js,"'+filepath+'")');
PPx.Execute("*setentryimage "+img+" -save");
}
if(PPx.EntryNextMark != 1) break;
}

2024年4月25日木曜日

xyzzyでスクリーンショット

xyzzyで

  • スクリーンショットを撮ってあらかじめ指定したディレクトリに保存
  • 保存したファイルのパスを貼り付け

という処理ができるようにする。winshotを利用。

準備

以下をsite-lispフォルダに保存。winshotのパスや保存フォルダは各自読み替えてください。

; -*- Mode: Lisp -*-
;;
;; winshotで矩形スクリーンショットを撮って保存。そのパスを貼り付ける
;;
;; Installation:
;;
;; ~/.xyzzy または $XYZZY/site-lisp/siteinit.l に以下のコードを追加
;;
;; (require "screenshot")
;winshotの実行ファイルパス
(defvar *winshot-exe* "D:\\bin\\winshot\\winshot.exe")
;スクリーンショット保存フォルダ
(defvar *screenshot-dir* "D:\\work\\SS")
;保存ファイルの書式
(defvar *screenshot-filename* "%Y-%m-%d-%H%M%S.jpg")
;winshotのオプション
(defvar *winshot-option* "-Jpeg -Rectangle -Close -File")
(defun screenshot ()
(interactive)
(let* ((filename (format-date-string *screenshot-filename*))
(dirname *screenshot-dir*)
(filepath (merge-pathnames filename dirname))
(winshotpath *winshot-exe*)
(option *winshot-option*))
(progn (call-process (concat winshotpath " " option " " filepath))
(insert (map-slash-to-backslash filepath)))))
view raw screenshot.l hosted with ❤ by GitHub

.xyzzyに以下を追記

(load-library "screenshot")    

やり方

M-x screenshot

スクリーンショットしたい箇所を矩形選択

スクリーンショットが保存され、かつそのパスが貼り付けられる

2024年4月9日火曜日

一行編集でエイリアスを登録

一行編集を利用し、実行ファイルを容易にエイリアスに登録できるようにする。

準備

まずは、実行ファイルを羅列した補完候補ファイルを用意する。作り方は色々あるが、*whereisを使うのが簡単。

*whereis -mask1:"a:d+;.exe" -path:"D:\bin" -dir:on -subdir:on -listfile:%0data\execpath -name

以下を編集して取込。

_Command    = {    ; ユーザコマンド・関数
setalias    = *string o,strings=%*input("" -title:"実行ファイルを選択してください" -mode:u,e -leavecancel -k:"*completelist -file:%%0data\execpath -match:6 -detail:""user"" %%: *mapkey use,K_exesearch")
 *string o,valuename=%"エイリアス名を登録してください"%{%*name(X,"%so"strings"")%}
 *alias %so"valuename"=%so"strings"
}

以下のコマンドを実行する。

*setalias

2024年4月7日日曜日

テキストファイルで画像ファイルを扱いたい

MV_click    = {    ; PPv メイン窓
LD_SPC    ,*ifmatch 0,0%*selecttext %: %K"@Q %: *stop
    *ifmatch "o:e,a:d-",%*selecttext %: *ppv %*selecttext %: *stop
    %K"@Q
}

今回は、テキストファイルで画像ファイルを扱う方法のアイデア。

画像ファイルのパスを挿入したテキストファイルをPPvで開き、[I]でキャレットモードに。ファイルパスにキャレットをあわせ、ダブルクリックする。

すると、ファイルパスの内容が別のPPvで表示される。

2024年3月17日日曜日

ユーザコマンドでパスによる判別実行

特定のファイル/フォルダをパスで判別し、特定のソフトに投げられるようにする。例えばMusicフォルダ以下のフォルダは音楽再生ソフトに投げ、Pictureフォルダ以下のフォルダは画像再生ソフトに投げる、というように。 かつては、「ポチエス」名称による関連付け専用版や、fenrirの機能を使って皆が実現してたやつですね。

準備

以下を編集して取込。

_Command = {
pathdetect = *ifmatch "/D:\\Data\\Music/",%*arg(1) %: %Ob D:\bin\AIMP5\AIMP.exe  %*arg(1) %: *stop
 *ifmatch "/D:\\Data\\Picture/",%*arg(1) %: %Ob D:\bin\NeeView\NeeView.exe %*arg(1) %: *stop
 %Z %*arg(1)
}

やり方

*pathdetect %FCD

とすれば、パスに応じて違うソフトに投げることができる。今回の例であれば、D:\Data\Music以下のフォルダはAIMP5に。D:\Data\Picture以下のフォルダはNeeViewで開くことになる。

2024年3月9日土曜日

一行編集でfenrirっぽいディレクトリ移動

一行編集で、編集中のディレクトリパスの階層を、上がったり下がったりできるようにする。fenrirの挙動を参考にした。

準備

以下をScriptフォルダに保存する。

//!*script
// 指定ディレクトリ以下のディレクトリ/ファイルを列挙した一時ファイルを作成、パスを返す
//
// 第一引数 : ディレクトリ
//
// 一時ファイルの構成
// 一行目:受け取ったディレクトリパス
// 二行目以下:指定ディレクトリ以下のディレクトリ名+ファイル名
// 引数がなければ終了
if (PPx.Arguments.Length < 1){
PPx.SetPopLineMessage("引数が正しくありません。");
PPx.Quit(-1);
}
var pdir = PPx.Arguments(0);
var tempfile = PPx.Extract("%*temp(name,f)");
var fso = PPx.CreateObject("Scripting.FileSystemObject");
var dir = fso.GetFolder(pdir);
var strLine = pdir + "\r\n";
var stream = PPx.CreateObject("ADODB.Stream");
stream.type = 2; // -1:Binary, 2:Text
stream.charset = 'UTF-8';
stream.lineseparator = 10; // ' -1 CrLf , 10 Lf , 13 Cr
// ディレクトリを取得
var enmFolders = PPx.Enumerator(dir.SubFolders);
for(; !enmFolders.atEnd(); enmFolders.moveNext()){
strLine += enmFolders.item().Name + "\\\r\n";
}
// ファイルを取得
// var enmFile = PPx.Enumerator(dir.Files)
// for (; !enmFile.atEnd(); enmFile.moveNext()){
// strLine += enmFile.item().Name + "\r\n";
// }
// 書き込み
writeFile(tempfile,strLine,"UTF-8");
// 書き込み用関数
function writeFile(fname, text, charset) {
if (charset == undefined) {
charset = "_autodetect_all";
}
var adTypeBinary = 1, adTypeText = 2;
var adSaveCreateNotExist = 1, adSaveCreateOverWrite = 2;
var adWriteLine = 1;
var s = PPx.CreateObject("ADODB.Stream");
s.Type = adTypeText;
s.charset = charset;
s.Open();
s.WriteText(text, adWriteLine);
s.SaveToFile(fname, adSaveCreateOverWrite);
s.Close();
}
PPx.Result = tempfile;
view raw getsubdir.js hosted with ❤ by GitHub

以下を編集して取込。

-|K_listmode=

K_listmode = {
ENTER    ,*ifmatch -1,%*sendmessage(%N-L,392,0,0) %: %K"@DOWN @ENTER" %: *stop
    %K"@ENTER"
LEFT    ,*dirmode %*name(D,%*getcust(_User:dirpath))
RIGHT    ,*ifmatch -1,%*sendmessage(%N-L,392,0,0) %: %K"@DOWN"
    *dirmode %*name(CD,"%*edittext",%*getcust(_User:dirpath))
}

_Command    = {
dirmode	= *setcust _User:dirpath=%*arg(1)
	*completelist -file:"%*script(%0Script\getsubdir.js,%*arg(1))" -history:e
	*replace ""
jump2listpath    = *setcust _User:dirpath=
    *string o,name=%*input("" -title:"jump2pathlist" -mode:e -k:"*completelist -file:%%*arg(1) -match:6  %%: *mapkey use,K_listmode")
    *ifmatch "o:e,a:d","%so"name"" %: *jumppath "%so"name"" %: *stop
    *ifmatch !0,0%*getcust(_User:dirpath) %: *jumppath "%*getcust(_User:dirpath)\%so"name""
}

やり方

ディレクトリパスを羅列した、以下のようなファイルを用意する。手動で作ってもいいし、zoxideやfenrirscanを利用して作ってもいい。

D:\bin
D:\Data
D:\work
C:\Program Files\7-Zip
C:\Program Files\Ablaze Floorp
C:\Program Files\AMD
C:\Program Files\BraveSoftware
C:\Program Files\Calibre2
C:\Program Files\Common Files
C:\Program Files\CrystalDiskInfo
C:\Program Files\EBWin4(x64)
C:\Program Files\Epic Games
C:\Program Files\Git
C:\Program Files\Internet Explorer

作成したファイルのパスを引数にして、*jump2listpathを実行する。

*jump2listpath %0data\path

すると、このファイルを補完候補リストとした一行編集が起動する。

キーバインドは以下の通り。

  • [RIGHT] サブディレクトリ表示
  • [LEFT] 階層を一つ上へ
  • [ENTER] パスをアクティブなPPcで開く

参考

2024年2月26日月曜日

PPvで簡易漫画ビューア

PPvを二つ並べて、簡易漫画ビューアにする。

準備

以下をScriptフォルダに保存。

//!*script
// 一つ下のエントリのフルパスを返す
var fs = PPx.CreateObject("Scripting.FileSystemObject");
var currentDir = PPx.Extract('%1');
var i = PPx.EntryIndex+1;
var name = PPx.Entry(i).Name;
var fullpath = fs.BuildPath(currentDir,name);
PPx.Result = fullpath;

以下を編集して取込。

K_mihirakiview 	= {
UP	,*execute C,*cursor 0, -2 %: *ppv -bootid:R -r %*extract(C"%(%*name(CD,"%R","%1")%)") %: %Oa *ppv -bootid:L -r %*extract(C"%(%*script(%0Script\nextentrypath.js)%)")
DOWN	,*execute C,*cursor 0, 2 %: *ppv -bootid:R -r %*extract(C"%(%*name(CD,"%R","%1")%)") %: %Oa *ppv  -bootid:L -r %*extract(C"%(%*script(%0Script\nextentrypath.js)%)")
LEFT	,*execute C,*cursor 0, -1 %: *ppv -bootid:R -r %*extract(C"%(%*name(CD,"%R","%1")%)") %: %Oa *ppv -bootid:L -r %*extract(C"%(%*script(%0Script\nextentrypath.js)%)")
RIGHT	,*execute C%si"ppcid",*cursor 0, 1 %: *ppv -bootid:R -r %*extract(C"%(%*name(CD,"%R","%1")%)") %: %Oa *ppv  -bootid:L -r %*extract(C"%(%*script(%0Script\nextentrypath.js)%)")
Q	,*closeppx "VL,VR"
ENTER	,*closeppx "VL,VR"
W	,*fitwindow %NVR,%NVL,1
}

やり方

以下のコマンドを実行すると、PPV[R]が開く。

*ppv -bootid:R -r %*name(CD,"%R","%1") -k *mapkey use,K_mihirakiview

PPV[R]上でカーソル移動をすると、PPV[L]も起動。漫画ビューアっぽい動作をする。

キーバインドは以下。

  • [UP] 前のページに戻る
  • [DOWN] 次のページに進む
  • [LEFT] 1ページ戻る
  • [RIGHT] 1ページ進む
  • [W] PPV[R]の左にPPV[L]を移動、高さが同じに
  • [Q] 両方の窓を閉じる
  • [ENTER] 両方の窓を閉じる

2024年1月23日火曜日

ASUS t90chiチャタリング対策

僕がずっと使ってるt90chiには、チャタリングを起こしやすいという欠点がある。色々な対処法を試してきたが、チャタリングを完全に抑えることはできなかった。仕方ないので、チャタリングが起きることを前提にした対策をする。

ccchattttter

ccchattttterをインストール。起動したら、「キーリピート無視」のチェックを外す。これで、チャタリングが起きても、文字がああああああああああというように連打されず、停止した状態になる。

キーボードの再接続

ccchattttterでチャタリングが停止したら、アクションセンターを表示し、Bluetoothの箇所をタッチ。一旦キーボードの接続を切ったあと、再びタッチして再接続する。これでチャタリングが解消される。