情報科学屋さんを目指す人のメモ(FC2ブログ版)

何かのやり方や、問題の解決方法をどんどんメモするブログ。そんな大学院生の活動「キャッシュ」に誰かがヒットしてくれることを祈って。

ブログ内検索

スポンサーサイト このエントリーを含むはてなブックマーク

上記の広告は1ヶ月以上更新のないブログに表示されています。
新しい記事を書く事で広告が消せます。
スポンサー広告 | 編集

AutoHotkeyで、ちょっと高機能な「行頭へカーソルを移動」を作ってみる このエントリーを含むはてなブックマーク

インデントされている文章を編集しているときに、Homeキーなどで単純に行頭へカーソルを移すと、本当に編集したい"行頭"までTabやスペースの分だけ右に移動しなければなりません。今回は、インデントのTabやスペースを認識して、その手前まで移動するホットキー「行頭へカーソルを移動」を、AutoHotkeyを利用して作成します。また、それを通して、AutoHotkeyを利用するときのコツを紹介します。

文字列の内容を知るためには、コピーするしかない

今回は、Tabや半角スペースの存在をAutoHotkeyScriptが認識しなくてはいけません。このように、カーソル付近の文章を認識するためにはその内容をクリップボードにコピーして、それを読み込む必要があります

このとき、現在のクリップボードの内容を一時的に退避して、作業が終わったら戻す必要があります。実は、この作業には、いくつかの注意すべきポイントがあります。

選択範囲の内容を読み取る方法

行頭へ移動するホットキーを作る前段階として、選択した文字を変数に格納してみます

カーソルの一文字左を読み取るコードは次のようになります。

^j::
	; クリップボードの内容を退避
	clipboard_backup = %ClipboardAll%

	: 選択
	Send +{Left}

	; コピー
	Clipboard = ; クリップボードを空にする
	Send ^c     ; 実際のコピーコマンド
	ClipWait, 1 ; コピー完了まで待機

	; 変数へクリップボードの内容を格納
	selected := Clipboard

	; 表示
	msgbox, %selected%

	; クリップボードの内容を復元
	Clipboard := clipboard_backup

	Return

見ての通り、結構長くなります。ただ、この中に注意すべき点がたくさんあるのです。以下、注意点を一つ一つ説明しておきます。

クリップボードの内容を退避と復元で利用する変数が違う

ClipboardAll変数は、退避のために利用する変数です。このコードのように「ClipboardAll」変数を利用して、バックアップ先の変数に退避してクリップボードを使う作業を終えたら、今度は「Clipboard」変数にその内容を代入します。ここで、ClipboardAllに代入しても無意味です。ClipboardAll変数は、退避専用の変数です

ClipWaitを利用するために、コピーの前にClipboardを空にする

「Send ^c」の前に、「Clipboard =」でClipboard変数の中身を空にしています。これをしないと、次に紹介するClipWaitコマンドが意図した動作をしてくれません。かならずコピーの前にはClipboard変数をクリアしておきましょう。

コピーの完了をClipWaitで確認する

選択範囲のコピーの実際は、単なる「Send ^c」です。つまり、このキー入力を受け取ったアプリケーションがクリップボードに選択範囲の文字列を格納してくれるということを意味します。つまり、「Send ^c」をした直後、すぐクリップボードの内容が更新されているわけではなく、コピーの完了を待たなければならないということです。そこで利用するのが「ClipWait」コマンドです。

「ClipWait, 1」では、最大1秒、クリップボードの更新を待ちます。このとき、実際には、テキストとして読み取れる内容になることを待つので、あらかじめ内容をクリアしておく必要があるわけです。

クリップボードの内容を利用するときはClipboard変数

クリップボードの内容を利用するときは、「ClipboardAll変数」ではなく、「Clipboard変数」を利用してください。ClipboardAllを使って読み出しても、テキストとして利用できません。

行頭へ移動ホットキー(低速版)

では、選択範囲の読み出し方法が分かったところで、実際に目的のホットキーの実装を行います。今回は、とりあえず行頭までジャンプして、右隣がTabか半角スペースだったらひとつ移動するようにしてみます。

実際のコードは次のようになります。

^j::
	; 退避
	clipboard_backup = %ClipboardAll%

	; 先頭へ移動
	Send {Home}

	; カーソル位置の修正用ループ
	Loop {
		; カーソルの一つ右の文字を読み取る
		Send +{Right}
		Clipboard :=
		Send ^c
		ClipWait, 1
		selected := Clipboard

		; インデント文字かどうかで分岐
		If (selected = " " || selected = "`t") {
			Send {Right} ; 次の文字へ
		} Else {
			; 選択を解除して抜ける
			Send {Left}
			Break
		}
	}

	; 復元
	Clipboard := clipboard_backup

	Return

このコードは、とりあえず目的のとおり動きます環境、特にアプリケーション次第でうまくいかないかもしれません。今はとりあえずTeraPadで試しています。ただ、半角スペース8つなどのインデントで試しに実行してみると、まるでスローモーションです。

この原因のひとつは、コピー回数が多いことです。

行頭へ移動ホットキー(中速版)

次に紹介するコードは、コピー回数を減らしたバージョンです。

^j::
	; 退避
	clipboard_backup = %ClipboardAll%

	; 先頭まで選択
	Send +{Home}

	; 選択範囲を読み取る
	Clipboard :=
	Send ^c
	ClipWait, 1
	selected := Clipboard

	; クリップボードの内容を復元
	Clipboard := clipboard_backup

	; 選択範囲一文字ずつに対してループ
         Loop % StrLen(selected) {
		; 左から順番に一文字取り出す
		c := SubStr(selected, A_Index, 1)
		
		; インデント文字かどうかで分岐
		If (c = " " || c = "`t") {
			Send +{Right} ; 選択範囲を狭めて次の文字へ
		} Else {
			Break ; 終了
		}
	}

	; 選択を解除
	Send {Left}
	Return

これでも十分遅いのですが、前のバージョンよりは速くなっています。このように、できるだけClipWaitで待つ時間を小さくした方がよいと思われます。ちなみに、今回のバージョンで最後の「Send {Left}」をコメントアウトすると、「先頭まで選択」ができます。

もっと速くするためには

実は、遅い原因の大部分はカーソル移動時間です。一文字ずつカーソルを移動させる限り、カーソル移動にかかる時間がどうしても削れません。そこで、「Ctrl+→」などを使って移動すればもっと高速化できるのですが、アプリケーションの依存度が高く、アプリケーションごとにどこまで移動するかが変わってしまうため、ちょっと微妙です。参考として、少し動作が変わってしまいますが(メモ帳ですら不適合で、TeraPadでわりと意図したとおり動いたという程度)、その一例を載せておきます。

^j::
	; 退避
	clipboard_backup = %ClipboardAll%

	; 先頭まで選択
	Send +{Home}

	; 選択範囲を読み取る
	Clipboard :=
	Send ^c
	ClipWait, 1
	selected := Clipboard

	; クリップボードの内容を復元
	Clipboard := clipboard_backup

	; 先頭の一文字を取り出す
	c := SubStr(selected, 1, 1)

	; インデント文字かどうかで分岐
	If (c = " " || c = "`t") {
		Send ^+{Right} ; 単語単位の移動を利用して移動
	}

	; 選択を解除
	Send {Left}
	Return

これは、「先頭までを選択」が行いやすいバージョンで、次は、行全体の選択を避けたバージョンです。

^j::
	; 退避
	clipboard_backup = %ClipboardAll%

	; カーソルが先頭になるように、
	; 先頭一文字を選択
	Send {Home}{Right}+{Home}

	; 選択範囲を読み取る
	Clipboard :=
	Send ^c
	ClipWait, 1
	selected := Clipboard

	; クリップボードの内容を復元
	Clipboard := clipboard_backup

	; 先頭の一文字を取得
	c := selected

	; インデント文字かどうかで分岐
	If (c = " " || c = "`t") {
		Send ^{Right} ; 単語単位の移動を利用して移動
	} Else {
		Send {Left}
	}
	Return

まとめ

AutoHotkeyを使うとこんな感じで作業を自動化できますよ、という紹介にはなったと思います。ただ、そんなことより重要なのは、Clipboardの使い方です。いろいろ注意点が多いので、気を付けてください。

スポンサーサイト
AutoHotkey | コメント:0 | トラックバック:0 | 編集

VBScript用エディタ「VbsEdit」というものを今更発見 このエントリーを含むはてなブックマーク

以前、「Microsoft Script Editor の場所」というエントリで、

MicrosoftScriptEditor は、VBScriptを編集するときに利用してます。デバッグ機能とか働かないけど、まぁ使わないし。でも、もっといい環境があればそっちを使いたい…

と、書いていたのですが、それらしきものをたまたま今回見かけたのでメモ。

そのエディタの名前はVbsEdit。有料のようですが、評価版がダウンロードできるようなので、今度使ってみようかと。

そもそも、最近がっつりVBScriptを書くことがなく、修正や、バージョンアップするだけなので、今更エディタを乗り換える必要がないのが残念です。

VBScript | コメント:0 | トラックバック:0 | 編集
 | HOME | 
上記広告は1ヶ月以上更新のないブログに表示されています。新しい記事を書くことで広告を消せます。