「
「クリップボード履歴」メニューのマクロ化
」を編集中
2019年11月1日 (金) 21:49時点における
Sukemaru
(
トーク
|
投稿記録
)
による版
(第3版)
(
差分
)
← 古い版
|
最新版
(
差分
) |
新しい版 →
(
差分
)
ナビゲーションに移動
検索に移動
警告: このページの古い版を編集しています。
公開すると、この版以降になされた変更がすべて失われます。
警告:
ログインしていません。編集を行うと、あなたの IP アドレスが公開されます。
ログイン
または
アカウントを作成
すれば、あなたの編集はその利用者名とともに表示されるほか、さまざまなメリットもあります。
スパム攻撃防止用のチェックです。 決して、ここには、値の入力は
しない
でください!
公式フォーラム[https://www.haijin-boys.com/discussions/4686] にて「[[ヘルプ:ツール#クリップボード履歴|クリップボード履歴]]」メニューの将来的に廃止されることが 予告?検討? されていますが、後継機能としては [[クリップボード履歴|「クリップボード履歴」プラグイン]] の登場により今後も安泰のようですね。 ということで、試験運用中だった自家用マクロを再度リサイクルして「'''クリップボード履歴'''と'''スニペット'''」の統合版ポップアップメニューにしてみました。 :「クリップボード履歴」機能は Mery 2.8.1 以降の『延命措置』の新パラメータ[https://www.haijin-boys.com/discussions/4686#discussion-4729] を利用したもの。 :「スニペット」機能は [[プラグイン:スニペットプラグイン|スニペットプラグイン]] の設定ファイル '''snippets.txt''' を読み書きするというかたちにしています。 <br> <div class="warningbox"> * <b style="color:#c00;">このマクロは Mery 2.8.1 以降でしか利用できません。</b> * あらかじめ「[[includeライブラリ]]」の導入が必要です。 </div> * 外部実行ファイル「[[GetKeyState.exe(キー状態取得実行ファイル)|GetKeyState.exe]] 」で機能を拡張できます。 * 「[[プラグイン:スニペットプラグイン|スニペットプラグイン]]」を導入していないでも「スニペット(定型文)」機能を利用できます。 * 動作確認は Windows XP sp3 (32bit) × Mery ベータ版 2.8.2 - 2.8.3 (ポータブル) でしかしていません。 <br> 一見して '''誰得?''' なマクロですが、「クリップボード履歴」を「スニペット」機能とまとめてツールバーアイコン化できるという素敵なメリットがあります。 : ''cf.'' マクロライブラリには「[[定型文を挿入]]」機能に特化したマクロも別途あります。 == 更新履歴 == • 2019/08/01: 初版 • 2019/08/06: ・「ピン止めアイテムを貼り付け」コードの変数ミスを修正 ・クリップボード履歴内の重複アイテムを削除する設定を追加。 ・ピン止めアイテムが少ないときはメインメニューにアイテムを表示。 ・snippets.txt 内の空行を無視。 ・クリップボード履歴に長大なデータがあるときの動作速度を少しだけ改善。 • 2019/11/01: ・ステータス表示を追加 ・クリップボードにテキストデータがないときのメニュー構成を変更 ・アイテムの行数(改行数+1)をメニュー内に追加表示 ・メニュー内に表示する改行コードの矢印を「↲」(U+21B2) に変更 ・スニペット機能での「ピン止め/貼り付け」のさいの、改行コードやタブコードではない文字列「\n」や「\t」の扱いを再修正 ・snippets.txt がないときのエラーを修正 == ソースコード == ; ダウンロード: 「[[ファイル:クリップボード履歴.zip ]]」(アイコン入り) <source lang="javascript" style="height:60em; overflow:auto;"> #title = "クリップボード履歴..." #tooltip = "クリップボード履歴 と スニペット" #icon = "clipboard_history[1].ico" #include "include/IO.js" /** * -------------------------------------------------- * 「クリップボード履歴 と スニペット」マクロ * sukemaru, 2019/08/01 - 2019/11/01 * -------------------------------------------------- * 「クリップボード履歴」メニューと「スニペット」プラグインと同等の機能を * ひとつのポップアップメニューに統合します。 * * 【このマクロの仕様・制限事項】 * ・ver 2.8.1 以前の Mery では使用できません。 * ・「クリップボード履歴」は Mery 本体のメモリストアのものを使用します。 * ※「クリップボードのすべての履歴を削除」したあとでも、 * Windows OS のクリップボードの最新の履歴にテキストデータが残っているときは * クリップボード履歴メニューに1件だけ表示します。 * * ・「スニペット」プラグインの設定ファイル snippets.txt の読み書きをします。 * ※「include ライブラリ」が必要です(snippets.txt ファイルの読み書きに使用)。 * ※「スニペット」プラグインを導入していない場合でも、 * 「ピン止めアイテム/スニペット」機能を使用できます。 * snippets.txt ファイルの保存場所は Mery\Plugins\Snippets フォルダです * (インストーラ版では %AppData%\Mery\Plugins\Snippets フォルダ)。 * * ・「GetKeyState.exe(キー状態取得実行ファイル) 」で機能を拡張できます。 * → クリップボード履歴のアイテムを Ctrl+クリックした場合、 * アイテムを貼り付けし、貼り終えたアイテムを削除します。 * ※「GetKeyState.exe」は Mery\Macros フォルダに配置してください * (Macros フォルダ以外の場所にあるなら設定項目でパスを指定する)。 */ // ---------- ▼ 設定項目 ▼ ---------- // // ■ クリップボード履歴内の重複アイテムを削除する var delDupEnable = true; // true: 削除する / false: 削除しない // ■ ピン止めアイテムをサブメニュー化するアイテム数の閾値 var snSubMenu = 5; // これよりアイテム数が多いときはサブメニューに表示する // ■ ポップアップメニューを表示する位置 var menuPosMouse = true; // true: マウス位置 / false: キャレット位置 // ■ ポップアップメニューに表示する文字数 var menuWidth = 60; // ■ GetKeyState.exe のフルパスを指定する場合(「\」記号はふたつがさね「\\」で) // ※ 未指定 "" なら、 editor.FullName.replace( /[^\\]+$/, "Macros\\GetKeyState.exe" ); var getKeyStatePath = ""; // ---------- ▲ 設定項目 ▲ ---------- // var start = new Date(); var Fso = new ActiveXObject( "Scripting.FileSystemObject" ); var WshShell = new ActiveXObject( "WScript.Shell" ); // ClipboardData.Get/ClearData() に引数を指定できるのは ver 2.8.1 以降 if ( VersionCheck( "2.8.1" ) ) { var meryPath = editor.FullName; var meryDir = meryPath.replace( /[^\\]+$/, "" ); var isPortable = Fso.FileExists( meryPath.replace( /\.exe$/i, ".ini" ) ); var profileDir = ( isPortable ) ? meryDir : WshShell.SpecialFolders( "APPDATA" ) + "\\Mery\\"; var snPath = profileDir + "Plugins\\Snippets\\Snippets.txt"; var snIsExist = Fso.FileExists( snPath ); var gksPath = getKeyStatePath || meryDir + "Macros\\GetKeyState.exe"; var gksIsExist = Fso.FileExists( gksPath ); var $ctrl = 0; var d = editor.ActiveDocument; var s = d.selection; var st = s.Text; var $status = Status; // ピン止めアイテム (スニペット) var snippets = "", snArray = [], snCount = 0 , sn; if ( snIsExist ) { snippets = IO.LoadFromFile( snPath, "utf-8" ) || ""; snArray = snippets.replace( /^\n/gm, "" ).replace( /\n$/, "" ) .split( "\n" ); snCount = snArray.length; sn = ( snCount > snSubMenu ); } // クリップボード履歴 var cb = ClipboardData; var cbData = cb.GetData(); var cbArray = []; var cbData0 = cb.GetData( 0 ); if ( cbData0 ) { for ( var i = 0, cbItem; ; 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 -- ); } } } // 履歴アイテムを配列に収納する cbArray.push( cbItem ); } } var cbCount = cbArray.length; var width = String( Math.max( snCount, cbCount || 0 ) ).length; // ポップアップメニューの準備 var menu = CreatePopupMenu(); var menuFlags = d.ReadOnly ? meMenuGrayed : 0; var t = ( snSubMenu && snArray[0] ) ? "▼ " : ""; menu.AddPopup( t + "ピン止めアイテム/スニペット (&S) " + t, sm0 = CreatePopupMenu() ); // スニペットのアイテムをメニューに if ( snCount ) { for ( var i = 0, id, label, lines; i < snCount; i ++ ) { id = i + 1; lines = snArray[i].replace( /[^\t]*\t/, "" ).split( "\\n" ).length; label = MenuKey( snArray[i].replace( /\t[\s\S]*/, "" ), id, width, true ) + "\t" + lines + " 行"; if ( label ) { if ( i < snSubMenu ) { menu.Add( label, id + 400, menuFlags ); if ( sn ) { sm0.Add( label, id + 400, menuFlags ); } } else { sm0.Add( label, id + 400, menuFlags ); } } } if ( sn ) { sm0.Add( "", 0, meMenuSeparator ); } } if ( st ) { sm0.Add( "選択範囲を登録 (&P)", 300 ); } if ( snIsExist ) { sm0.Add( "スニペットを編集 (&E) ...", 400 ); } if ( sn || st || snIsExist ) { sm0.Add( "", 0, meMenuSeparator ); sm0.Add( "キャンセル & ", 0 ); } menu.Add( "", 0, meMenuSeparator ); // クリップボード履歴のアイテムをメニューに if ( cbCount ) { menu.AddPopup( "▼ クリップボード履歴の一覧 (&C) ▼", sm1 = CreatePopupMenu() ); var sm2 = CreatePopupMenu(); var sm3 = CreatePopupMenu(); for ( var i = 0, id, label, lines; i < cbCount; i ++ ) { id = i + 1; lines = cbArray[i].split( "\n" ).length; label = MenuKey( cbArray[i], id, width ) + "\t" + lines + " 行"; menu.Add( label, id, menuFlags ); sm2. Add( label, id + 100, menuFlags ); sm3. Add( label, id + 200 ); } menu.Add( "", 0, meMenuSeparator ); menu.Add( "クリップボードのすべての履歴を削除する (&E)", 500 ); sm1.AddPopup( "貼り付けしてからアイテムを削除 (&M)", sm2 ); sm1.AddPopup( "履歴からアイテムを削除 (&D)", sm3 ); sm1.Add( "", 0, meMenuSeparator ); sm1.Add( "すべての履歴を削除 (&E)", 500 ); } else if ( cbData.length ) { menu.Add( "▼ クリップボード ▼", 0, meMenuGrayed ); lines = cbData.split( "\n" ).length; label = MenuKey( cbData, 1, width ) + "\t" + lines + " 行"; menu.Add( label, 17, menuFlags ); } else { menu.Add( "※ クリップボードにテキストデータはありません ※" , 0, meMenuGrayed ); } menu.Add( "", 0, meMenuSeparator ); menu.Add( "キャンセル & ", 0 ); // ステータスバーの表示 if ( menuFlags ) { Status = " ドキュメントは書き換え禁止です。"; } else if ( gksIsExist && cbCount ) { Status = "履歴アイテムの Ctrl+クリック で 「貼り付けしてからアイテムを削除」"; } else { Status = "「クリップボード履歴 と スニペット」マクロ"; } Status += " [ " + ( ( new Date() - start ) / 1000 ).toFixed( 3 ).replace( /\./, ". " ) + " 秒 ]"; // ポップアップメニューを表示 var r = menu.Track( + menuPosMouse ); var confirmStr = "クリップボードのすべての履歴を削除しますか? "; if ( r == 0 ) { Status = $status; } // 1 ~ 17: 貼り付け else if ( r <= 16 ) { d.Write( cbArray[ r -1 ] ); Status = ""; // Ctrl キーを押しながらのときは、貼り付けたアイテムを履歴から削除する if ( gksIsExist ) { $ctrl = WshShell.Run( "\"" + gksPath + "\" c", 0, true ); if ( $ctrl == 1 ) { cb.ClearData( r -1 ); Status = " 履歴からアイテムを削除しました。"; } } } else if ( r == 17 ) { d.Write( cbData ); Status = ""; } // 101 ~ 116: 貼り付けして、そのアイテムをクリップボード履歴から削除する else if ( r > 100 && r < 200 ) { d.Write( cbArray[ r -101 ] ); cb.ClearData( r -101 ); Status = " 履歴からアイテムを削除しました。"; } // 201 ~ 216: アイテムをクリップボード履歴から削除する else if ( r > 200 && r < 300 ) { cb.ClearData( r -201 ); Status = " 履歴からアイテムを削除しました。"; } // 401 ~ 499: ピン止めアイテムを貼り付け else if ( r > 400 && r < 500 ) { var str = snArray[ r -401 ].replace( /^[^\t]*\t/, "" ) .replace( /(^|[^\\])\\t/g, "$1\t" ) .replace( /(^|[^\\])\\r/g, "$1\r" ) .replace( /(^|[^\\])\\n/g, "$1\n" ) .replace( /\\\\/g, "\\" ); d.Write( str ); Status = ""; } // 300: 選択範囲を登録(ピン止め) else if ( r == 300 ) { var snippetsDir = Fso.GetParentFolderName( snPath ); 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( /\\/g, "\\\\" ) .replace( /\t/g, "\\t" ) .replace( /\r?\n/g, "\\n" ); IO.SaveToFile( snPath, str, "utf-8", true ); Status = " 選択範囲をスニペットに登録しました。"; } // 400: ピン止めアイテムを編集(snippets.txt を開く) else if ( r == 400 ) { WshShell.Run( "\"" + editor.FullName + "\" \"" + snPath + "\"" ); Status = " " + snPath; } // 500: クリップボード履歴をすべて削除する else if ( r == 500 && Confirm( confirmStr ) ) { for ( var i = 0; i < cbCount; i ++ ) { cb.ClearData( i ); Status = " 履歴からすべてのアイテムを削除しました。"; } } } // ---------- ▼ 関数 ▼ ---------- // /** * 関数 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, convLF ) * ポップアップメニューに表示するラベルを生成する * ・行頭空白を除去、空白文字を圧縮: →「›」(U+203A) * ・改行記号を可視化: →「↲」(U+21B2) または「⏎」(U+23CE) * ・削られてしまう「&」を補完 * ・「¥」(U+005C) を「∖」に置換: →「∖」(U+2216) * ・ゼロ幅や特殊な空白文字を豆腐に置換: →「⊠」(U+22A0) または「▯」(U+25AF) * ・判別しづらいメタ文字を全角に置換: !"%'(),.:;@[]`{|} * ・「a-z」を全角に置換 * ・行番号を空白でケタ埋め: EN SPACE「 」(U+2002) * ・文字数を切り詰め */ function MenuKey( str, num, width, convLF ) { // 2019/08/05 : slice メソッドを追加 if ( convLF ) { str = str.replace( /(?:\\r)?\\n/g, " ↲ " ); // ⏎ } var reg = /[\u00A0\u1680\u180e\u2000-\u200A\u2028\u2029\u202F\u205F\uFEFF]/g; var menuKey = str.replace( /(?:\t|[ ]{3,}|[ ]{2,})+/g, " › " ) .slice( 0, menuWidth + 1 ) .replace( /\r?\n/g, " ↲ " ) // ⏎ .replace( /[&]/g, "&&" ) .replace( /[\\]/g, "∖" ) // .replace( /([^∖!"',.:;`|\t ])([∖]+)/g, "$1 $2" ) .replace( reg, "▯" ) .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; } </source>
編集内容の要約:
MeryWikiへの投稿はすべて、他の投稿者によって編集、変更、除去される場合があります。 自分が書いたものが他の人に容赦なく編集されるのを望まない場合は、ここに投稿しないでください。
また、投稿するのは、自分で書いたものか、パブリック ドメインまたはそれに類するフリーな資料からの複製であることを約束してください(詳細は
MeryWiki:著作権
を参照)。
著作権保護されている作品は、許諾なしに投稿しないでください!
このページを編集するには、下記の数式を計算してその答えを欄に入力してください (
ヘルプ
):
いちたすには =
キャンセル
編集ヘルプ
(新しいウィンドウで開きます)
スポンサーリンク
ナビゲーション メニュー
個人用ツール
ログインしていません
トーク
投稿記録
アカウント作成
ログイン
名前空間
ページ
議論
日本語
表示
閲覧
編集
履歴表示
その他
検索
スポンサーリンク
スポンサーリンク
案内
メインページ
ヘルプ
よくある質問
マクロリファレンス
マクロライブラリ
プラグインライブラリ
構文ファイル
テーマ
寄付・開発支援
練習用ページ
開発室
開発者のブログ
ツール
スポンサーリンク