「クリップボード履歴」メニューのマクロ化
公式フォーラム[1] にて「クリップボード履歴」メニューの将来的に廃止されることが 予告?検討? されていますが、後継機能としては 「クリップボード履歴」プラグイン の登場により今後も安泰のようですね。
ということで、試験運用中だった自家用マクロを再度リサイクルして「クリップボード履歴とスニペット」の統合版ポップアップメニューにしてみました。
- 「クリップボード履歴」機能は Mery 2.8.1 以降の『延命措置』の新パラメータ[2] を利用したもの。
- 「スニペット」機能は スニペットプラグイン の設定ファイル snippets.txt を読み書きするというかたちにしています。
- あらかじめ「includeライブラリ」の導入が必要です。
- 「スニペットプラグイン」を導入していないでも「スニペット(定型文)」機能を利用できます。
- 外部実行ファイル「GetKeyState.exe 」で機能を拡張できます。
- このマクロは Mery 2.8.1 以降でしか利用できません。
- 動作確認は Windows XP sp3 (32bit) × Mery ベータ版 2.8.2 - 2.8.3 (ポータブル) でしかしていません。
一見して 誰得? なマクロですが、「クリップボード履歴」を「スニペット」機能とまとめてツールバーアイコン化できるという素敵なメリットがあります。
- cf. マクロライブラリには「定型文を挿入」機能に特化したマクロも別途あります。
更新履歴
• 2019/08/01: 初版
• 2019/08/01: ・「ピン止めアイテムを貼り付け」コードの変数ミスを修正 ・クリップボード履歴内の重複アイテムを削除する設定を追加。 ・ピン止めアイテムが少ないときはメインメニューにアイテムを表示。 ・snippets.txt 内の空行を無視。 ・クリップボード履歴に長大なデータがあるときの動作速度を少しだけ改善。
ソースコード
- ダウンロード: 「ファイル:クリップボード履歴.zip」(アイコン入り)
#title = "クリップボード履歴..."
#tooltip = "クリップボード履歴 と スニペット"
#include "include/IO.js"
// #icon = "clipboard_history[1].ico"
/**
* --------------------------------------------------
* 「クリップボード履歴 と スニペット」マクロ
* sukemaru, 2019/08/01 - 2019/08/05
* --------------------------------------------------
* 「クリップボード履歴」メニューと「スニペット」プラグインと同等の機能を
* ひとつのポップアップメニューに統合します。
*
* 【このマクロの仕様・制限事項】
* ・ver 2.8.0 以前の Mery では使用できません。
* ・「クリップボード履歴」は Mery 本体のメモリストアのものを使用します。
* ・「スニペット」プラグインの設定ファイル snippets.txt の読み書きをします。
* ・「include ライブラリ」が必要です(snippets.txt ファイルの読み書きに使用)。
* ・「GetKeyState.exe(キー状態取得実行ファイル) 」で機能を拡張できます。
* → クリップボード履歴のアイテムを Ctrl+クリックした場合、
* アイテムを貼り付けし、貼り終えたアイテムを削除します。
*
* ※「スニペット」プラグインを導入していない場合でも、
* 「ピン止めアイテム/スニペット」機能を使用できます。
* snippets.txt ファイルの保存場所は Mery\Plugins\Snippets フォルダです
* (インストーラ版では %AppData%\Mery\Plugins\Snippets フォルダ)。
*
* ※「GetKeyState.exe」は Mery\Macros フォルダに配置してください
* (Macros フォルダ以外の場所にあるなら設定項目でパスを指定する)。
* ※「GetKeyState.exe」を導入していない場合は、
* 「貼り付けしてからアイテムを削除する」サブメニューを表示します。
*
* (2019/08/05)
* ・「ピン止めアイテムを貼り付け」のコードミスを修正
* ・クリップボード履歴内の重複アイテムを削除する設定を追加。
* ・ピン止めアイテムが少ないときはメインメニューにアイテムを表示。
* ・snippets.txt 内の空行を無視。
* ・クリップボード履歴に長大なデータがあるときの動作速度を少しだけ改善。
*/
// ---------- ▼ 設定項目 ▼ ---------- //
// ■ クリップボード履歴内の重複アイテムを削除する
var delDupEnable = true; // true: 削除する / false: 削除しない
// ■ ピン止めアイテムをサブメニュー化するアイテム数の閾値
var snSubMenu = 5; // これよりアイテム数が多いときはサブメニューで表示する
// ■ ポップアップメニューを表示する位置
var menuPosMouse = true; // true: マウス位置 / false: キャレット位置
// ■ ポップアップメニューに表示する文字数
var menuWidth = 60;
// ■ GetKeyState.exe のフルパスを指定する場合(「\」記号はふたつがさね「\\」で)
var getKeyStatePath = ""; // editor.FullName.replace( /[^\\]+$/, "Macros\\GetKeyState.exe" );
// ---------- ▲ 設定項目 ▲ ---------- //
var Fso = new ActiveXObject( "Scripting.FileSystemObject" );
var WshShell = new ActiveXObject( "WScript.Shell" );
// ClipboardData。Get/ClearData() に引数を指定できるのは ver 2.8.1 以降
if ( ! VersionCheck( "2.8.1" ) ) {
WshShell.SendKeys( "%TC" );
}
else {
var meryPath = editor.FullName;
var mery = Fso.GetBaseName( meryPath );
var meryDir = Fso.GetParentFolderName( meryPath ) + "\\";
var profileDir = meryDir;
var iniPath = meryDir + mery + ".ini";
if ( ! Fso.FileExists( iniPath ) ) {
profileDir = WshShell.SpecialFolders( "APPDATA" ) + "\\Mery\\";
}
var snippetsPath = profileDir + "Plugins\\Snippets\\Snippets.txt";
var snIsExist = Fso.FileExists( snippetsPath );
var getKeyStatePath;
var getKeyState = getKeyStatePath || meryDir + "Macros\\GetKeyState.exe";
var gksIsExist = Fso.FileExists( getKeyState );
var $ctrl = 0;
var d = editor.ActiveDocument;
var s = d.selection;
var st = s.Text;
// ピン止めアイテム (スニペット)
var snippets = "", snCount = 0;
if ( snIsExist ) {
snippets = IO.LoadFromFile( snippetsPath, "utf-8" ) || "";
var snArray = snippets.replace( /^\n/gm, "" ).replace( /\n$/, "" )
.split( "\n" );
snCount = snArray.length;
var sn = ( snCount > snSubMenu );
}
// クリップボード履歴
var cb = ClipboardData;
var cbArray = [];
for ( var i = 0; ; i ++ ) {
cbItem = cb.GetData( i ) || "";
if ( ! cbItem ) { break; }
// 重複するアイテムを履歴から削除する
if ( delDupEnable ) {
for ( var j = i + 1, cbNextItem; ; j ++ ) {
cbNextItem = cb.GetData( j ) || "";
if ( ! cbNextItem ) { break; }
if ( cbItem == cbNextItem ) {
cb.ClearData( j );
j --;
}
}
}
// 履歴アイテムを配列に収納する
cbArray.push( cbItem );
}
var cbCount = cbArray.length;
var width = String( Math.max( snCount, cbCount ) ).length;
// ポップアップメニューの準備
var menu = CreatePopupMenu();
var sm0 = CreatePopupMenu();
var sm1 = CreatePopupMenu();
var sm2 = CreatePopupMenu();
var menuFlags = d.ReadOnly ? meMenuGrayed : 0;
var t = ( sn || snArray[0] == "" ) ? "" : "▼ ";
menu.AddPopup( t + "ピン止めアイテム/スニペット (&P) " + t, sm0 );
// スニペットのアイテムをメニューに
if ( snCount ) {
var snMenu = sn ? sm0 : menu;
for ( var i = 0, id, label; i < snCount; i ++ ) {
id = i + 1;
label = snArray[i].replace( /\t[\s\S]*/, "" );
if ( label ) {
snMenu.Add( MenuKey( label, id, width ), id + 300, menuFlags );
}
}
if ( sn ) {
snMenu.Add( "", 0, meMenuSeparator );
}
}
if ( st ) {
sm0.Add( "選択範囲を登録 (&P)", 300 );
}
if ( snIsExist ) {
sm0.Add( "スニペットを編集 (&E) ...", 400 );
}
sm0.Add( "", 0, meMenuSeparator );
sm0.Add( "キャンセル & ", 0 );
// クリップボード履歴のアイテムをメニューに
if ( cbCount ) {
menu.Add( "", 0, meMenuSeparator );
menu.Add( "▼ クリップボード履歴 ▼", 0, meMenuGrayed );
for ( var i = 0, id, label; i < cbCount; i ++ ) {
id = i + 1;
label = MenuKey( cbArray[i], id, width );
menu.Add( label, id, menuFlags );
sm1.Add( label, id + 100, menuFlags );
sm2.Add( label, id + 200 );
}
menu.Add( "", 0, meMenuSeparator );
if ( ! gksIsExist ) {
menu.AddPopup( "貼り付けしてからアイテムを削除する (&M)", sm1 );
}
menu.AddPopup( "クリップボードの履歴からアイテムを削除する (&D)", sm2 );
// menu.Add( "", 0, meMenuSeparator );
menu.Add( "クリップボードのすべての履歴を削除する (&C)", 500 );
}
menu.Add( "", 0, meMenuSeparator );
menu.Add( "キャンセル & ", 0 );
// ポップアップメニューを表示
var r = menu.Track( + menuPosMouse );
var confirmStr = menu.GetText( r ).replace( /する \(&\w\)$/, "しますか? ");
if ( r == 0 ) {
;
}
// 1 ~ 16: 貼り付け
else if ( r < 100 ) {
d.Write( cbArray[ r -1 ] );
// Ctrl キーを押しながらのときは、貼り付けたアイテムを履歴から削除する
if ( gksIsExist ) {
$ctrl = WshShell.Run( "\"" + getKeyState + "\" c", 0, true );
}
if ( $ctrl == 1 ) {
cb.ClearData( r -1 );
}
}
// 101 ~ 116: 貼り付けして、そのアイテムをクリップボード履歴から削除する
else if ( r > 100 && r < 200 ) {
d.Write( cbArray[ r -101 ] );
cb.ClearData( r -101 );
}
// 201 ~ 216: アイテムをクリップボード履歴から削除する
else if ( r > 200 && r < 300 ) {
cb.ClearData( r -201 );
}
// 301 ~ 399: ピン止めアイテムを貼り付け
else if ( r > 300 && r < 400 ) {
var str = snArray[ r -301 ].replace( /^[^\t]*\t/, "" )
.replace( /(\\r)?\\n/g, "\n" )
.replace( /\\t/g, "\t" )
d.Write( str );
}
// 300: 選択範囲を登録(ピン止め)
else if ( r == 300 ) {
var snippetsDir = Fso.GetParentFolderName( snippetsPath );
var pluginsDir = Fso.GetParentFolderName( snippetsDir );
if ( ! Fso.FolderExists( pluginsDir ) ) {
Fso.CreateFolder( pluginsDir );
}
if ( ! Fso.FolderExists( snippetsDir ) ) {
Fso.CreateFolder( snippetsDir );
}
var str = snippets
+ ( snippets ? "\n" : "" )
+ st.replace( /\t/g, "\\t" )
.replace( /\r?\n/g, "\\n" );
IO.SaveToFile( snippetsPath, str, "utf-8", true );
}
// 400: ピン止めアイテムを編集(snippets.txt を開く)
else if ( r == 400 ) {
WshShell.Run( "\"" + editor.FullName + "\" \"" + snippetsPath + "\"" )
}
// 500: クリップボード履歴をすべて削除する
else if ( r == 500 && Confirm( confirmStr ) ) {
for ( var i = 0; i < cbCount; i ++ ) {
cb.ClearData( i );
}
}
}
// ---------- ▼ 関数 ▼ ---------- //
/**
* 関数 VersionCheck( versionStr )
* Mery 本体が引数で指定したバージョン以上かチェックする( i.e. "2.6.9" )
* 戻り値は、真偽値 true/false
*/
function VersionCheck( versionStr ) {
var Pad2 = function( str ) {
return str.replace( /[0-9]+/g , function( digit ) {
return digit.length < 2 ? "0" + digit : digit
} )
};
var editorVer = + ( Pad2( editor.Version ).replace( /\./g, "" ).slice( 0, 6 ) );
var requirement = + ( Pad2( versionStr ).replace( /\./g, "" ).slice( 0, 6 ) );
return ( editorVer >= requirement );
}
/**
* 関数 MenuKey( str, num, width )
* ポップアップメニューに表示するラベルを生成する
* ・行頭空白を除去、空白文字を圧縮
* ・削られてしまう「&」を補完
* ・「¥」(U+005C) を「∖」に置換:「∖」(U+2216) または「╲」(U+2572) 「﹨」(U+FE68)
* ・判別しづらいメタ文字を全角に置換: !"%'(),.:;@[]`{|}
* ・「a-z」を全角に置換
* ・行番号を空白でケタ埋め: EN SPACE「 」(U+2002)
* ・文字数を切り詰め
*/
function MenuKey( str, num, width ) {
var menuKey = str.replace( /^[\t ]+/gm, " › " )
.replace( /\r?\n/g, "⏎ " )
.replace( /(?:\t|[ ]{3,}|[ ]{2,})+/g, " › " )
.replace( /[&]/g, "&&" )
.slice( 0, menuWidth + 1 ) // (2019/08/05 追加)
.replace( /[\\]/g, "∖" )
.replace( /([^∖!"',.:;`|\t ])([∖]+)/g, "$1 $2" )
.replace( /[!"%'(),.:;@\[\]`a-z{|}]/g,
function( tmp ) {
return String.fromCharCode( tmp.charCodeAt( 0 ) + 0xFEE0 )
} );
num = ( " " + num ).slice( - width ).replace( /\d$/, "&$&" );
menuKey = ( menuKey.length > menuWidth )
? menuKey.slice( 0, menuWidth ) + " ..."
: menuKey;
return num + ": " + menuKey;
}
スポンサーリンク