torazaemon2016’s blog

手書き文字認識メモ開発

iPhoneのショートカット (その1) iPhoneのアクションボタンを6倍活用する

iPhoneの「ショートカット」は大変便利で、iPhoneの使い勝手を向上させてくれます。

ここでは、近年のiPhoneに追加された「アクションボタン」を「ショートカット」に設定して、その「アクションボタンを『6倍』活用する」方法について、述べていきます。

特に、Obsidianでライフログを書いている人には、タイムスタンプ付きで次々にメモを追加できていくので、使い勝手を格段に向上させることができます。

Keyword: iPhone, action button, shortcut, actions, lifelog, obsidian

6倍活用のポイント

なにがショートカットを6倍にするかというと、ショートカット実行時にiPhoneの「向きを取得」することで、iPhoneの持ち方で実行する内容を切り替えることが可能ということです。

ショートカットの実装

ショートカットのそのものの説明やショートカットのつくり方、アクションボタンにショートカットを割り当てる方法などは、Googleなどでほかの人の詳しいページを参照してください。

ショートカットの名前や、アイコン、色の付け方など、画面のコピーの記載を参考にしてください。

アクションボタン向き振り分け

以下に画面のスクリーンショットを掲載します。

最初

(2つめのifの終わりが画面では切れています)

続き

ショートカットの説明

アクションとして以下の3つです。

  • 向きを取得
  • if文
  • ショートカットを実行

if文の条件の「向き」として

  • 縦向き
  • 縦向き上下逆
  • 横向きの左
  • 横向きの右
  • 印刷面を上に
  • 印刷面を下に
  • 不明

の7つが指定できますが、不明はなかなか無理なので、上6つで「6倍」です。

でも、実際に左手片手でiPhoneを持って、親指でアクションボタンを押すとすると「縦向き上下逆」「横向きの左」は、手首的に厳しいので、実質4つになるかと思います。

(タイトルの6倍活用はちょっと言い過ぎですかね)

他のショートカットへ

if文が成立した時の実行文として、他で定義したショートカットを呼び出しています。 ここにアクションをどんどん書いていってもいいのですが、見通しが悪くなるので分けています。

認証不要?

なぜ、このアクションボタンでのショートカットが最強かというと、 「ショートカットのアクションだけで終わる」場合、認証がなくても進めることができ、ライフログを書き込むことが出来る。 ということです。

実行文として、他のアプリケーションを呼び出すときは、iPhoneの認証が掛かります。 しかし、「ショートカットのアクションだけで終わる」場合、認証がなくても進んでいく。

「縦向き」のように、そのまま顔認証されるような場合は、他のアプリケーションを呼び出してもタイムラグはありませんが、「印刷面を下に」のような場合、顔認証が行われないので「パスコードを入力」の画面で止まっている。 「(その2) 音声で記入」は、画面がなくてもOKなので下向き、「(その3) リストから選択」は結局は画面を押す必要があるので上向きで、 「(その5)ObsidianのDashboard」は縦向きにして、ほとんどタイムラグなしに実行できています。

向きの条件を、認証不要な実行と認証が必要な実行とで合わせて活用してください。

iPhoneのショートカット (その2) ライフログを音声で記入

ライフログを音声で記入

ライフログを音声で記入のショートカットです。

  • テキストを音声入力
  • 変数を設定
  • ショートカットを実行

を用いています。

一度変数Inputに入れていますが、入れずに次のショートカット「obsidian dailyへ書き込み」に「音声入力されたテキスト」を渡すでもいいです。

obsidian dailyへ書き込みへ

iPhoneのショートカット (その4) Obsidian dailyへ書き込み - torazaemon2016’s blog

おわりに

ツイン・ピークス」のクーパー捜査官に憧れていたならば、是非。

iPhoneのショートカット (その3) ライフログをリストから選択

ライフログをリストから選択

ライフログをリストから選択のショートカットです。

  • リスト
  • リストから選択
  • 変数を設定
  • ショートカットを実行
  • if文

を用いています。

「リスト」を使って項目を並べます。

リストの代わりに「メニュー」アクションで作ることで、プログラムをわかりやすくすることもできますが、 リストを用いているのは、項目の「複数選択」を可能にするためです。 リストで複数選択をONにすることで、 「- 12:00 食事 start」「- 12:31 食事 end」のように記録させることができます。

リスト例

リストから選択で複数を選択可能に

選択した文字列を、「obsidian dailyへ書き込み」しています。

iPhoneのショートカット (その4) Obsidian dailyへ書き込み - torazaemon2016’s blog

選択した項目にによっては、さらに他のアクションを実行

if文で、就寝の際には、目覚ましセット(アラームセットと音量セット)や、起床の際には、目覚ましを止めたり、音量を下げたりと、各自の環境に合わせた動きをセットしてみてください。

どんどん拡張してみてください。

iPhoneのショートカット (その4) Obsidian dailyへ書き込み

Obsidian dailyへ書き込み

他のショートカットから、このショートカットを呼び出します。

  • 共有シート
  • 変数を設定
  • テキストを結合
  • Capture to Daily Note
  • 通知

を用いています。

呼び出し元のショートカットから、書き込みたい文字列が渡されてくるのを受け取るために、共有シートを使います。

共有シート

新規ショートカットの際に、 〇i 押して、 「詳細」で「共有シートに表示」 を ONにして、他のアプリやショートカットから、渡されてくるものを受け取るようにします。

Obsidianのアクション

iPhoneのObsidianのバージョンが上がって、ショートカットの項目ができていました。 もし、アクションが見当たらないようなら、iPhoneでのObsidianをUpdateしてください。

(これまでは、ファイル名を自分で作って、ファイルに追記で書き込んでいましたが、Obsidianのアクションが追加されたので、簡単になりました)

「Capture to Daily Note」 を使って、dailyノートに、Appendで最後に追記されていきます。

ObsidianのVaultの場所も指定するのを忘れないで。

時刻

変数 Timeに時刻を設定しています。

日付フォーマットをカスタムとして(- HH:mm)にして、Markdownの箇条書き - と 時:分 となっています。

通知

最後に、書いた文字列を「通知」で画面に表示するようにして、動作確認しています。

実行例

上部に通知として表示されています。

おわりに

通知がたくさんすぎて嫌であれば、通知なしでも。

自分の環境に合わせて書き換えてください。

iPhoneのショートカット (その5) ObsidianのDashboardを開く

ObsidianのDashboardを開く

「Open Bookmark」で、Bookmarkしているページを開きます。

Obsidianのほうで、Bookmarkしておいたページを開くことができます。

ここでは、DashboardとしてTODOやMOCがまとめてあるページを指定しています。

Current TabかNew Tabで開くことを選択できます。

iPhoneのObsidionで追加されたアクション

iPhoneのショートカット (その6) ObsidianのDailyページを開いて最下行へ

ObsidianのDailyページを開いて、かつ最下行へ飛ぶ

いろいろなページで探してみましたが、Obsidianのdailyページを最下行の状態で開く方法が見当たらなかったので、 ややトリッキーな方法ですが、今日のページを最下行の状態で表示する方法を実装しました。

方法は、JavaScriptで書かれたDataviewJSのスクリプトのmdページを開くと、それが今日のページを新しいTabで開いて、 最下行に飛んだのち、 そのスクリプト自身のmdページを閉じることで、結果として今日のページが最終行表示で残っているというものです。

Keyword: Obsidian, Dataview, DataviewJS, JavaScript, daily note, goto bottom, 最下行へ飛ぶ,

コミュニティプラグイン「Dataview」

まず、DataviewJSが動作するようにするため、コミュニティプラグイン「Dataview」を有効にして、 その中のオプション 「DataviewJS」もONになっているか、 確認してください。 特に、inline JavaScript queries がONになっていることも忘れずに。

コミュニティプラグイン「Dataview」

「DataviewJS」をON

ショートカット

「Open Bookmark」で、Bookmarkしているページ(ここでは Open-Today-and-goto-bottom.md)を開きます。

Open-Today-and-goto-bottom.md の内容

以下のような DataviewJS でのスクリプトです。

このページを開いたら、スクリプトが実行されるようになっているものです。

Obsidianのmdファイルにおいて、DataviewJS でスクリプトを書く方法は、バッククオート(@のshift)を3つで上下に囲まれたものです。

以下の右上にコピーボタンもありますので、それを押してコピーして、mdファイルに貼り付けてみてください。

```dataviewjs
//const path = "daily/2026-02-14.md"; // 開きたいノートのパス
//https://www.ey-office.com/blog_archive/2023/04/18/short-code-to-get-todays-date-in-yyyy-mm-dd-format-in-javascript/
// sv-SEロケールはYYYY-MM-DD形式の日付文字列を戻す
//new Date().toLocaleDateString('sv-SE')
const path = "daily/" + new Date().toLocaleDateString('sv-SE') + ".md"; // 開きたいノートのパス
const file = app.vault.getAbstractFileByPath(path);
if (file) {
        const leaf = app.workspace.getLeaf('tab');
        await leaf.openFile(file);

        setTimeout(() => {
            const editor = leaf.view.editor;
            editor.setCursor({ line: 9999, ch: 0 });    // 最下行(9999行)へ
        }, 200);
} else {
    dv.paragraph("ファイルが見つかりません: " + path);
}

//上のNewTabからOpen-Today-and-goto-bottom.md自体に戻る
app.commands.executeCommandById("workspace:previous-tab")
//自身(Open-Today-and-goto-bottom.md)を閉じる
app.commands.executeCommandById("workspace:close")
```

JavaScriptの内容

const path = "daily/" + new Date().toLocaleDateString('sv-SE') + ".md";
const file = app.vault.getAbstractFileByPath(path);

今日のファイル名を生成して(daily/YYYY-MM-DD.md)

const leaf = app.workspace.getLeaf('tab');
await leaf.openFile(file);

「新しいTabページ」でファイルを開き

const editor = leaf.view.editor;
editor.setCursor({ line: 9999, ch: 0 });    // 最下行(9999行)へ

ページの最下行(9999行)へ移動としている。

最後の2行は、

//上のNewTabからOpen-Today-and-goto-bottom.md自体に戻る
app.commands.executeCommandById("workspace:previous-tab")

「このOpen-Today-and-goto-bottom.md」のタブページから上記のように新しいTabページを開いて移動しているので、 その前のページ(Open-Today-and-goto-bottom.mdに戻る)

//自身(Open-Today-and-goto-bottom.md)を閉じる
app.commands.executeCommandById("workspace:close")

で、戻った自身(Open-Today-and-goto-bottom.md)を閉じることで、 結果として、今日のページの最下行が開かれている状態になっている。

おわりに

かなり強引な方法ですが、結果として、Obsidianの今日のdailyページを、最下行に行っている状態で開くことができました。

Windowsであれば、Ctrl+End のキー操作ですぐに最下行にいけましたが、 iPhoneでは面倒だったのが簡単になり、かつ、アクションボタンで一発にもなったので、 大変便利になりました。

AutohotkeyのスクリプトからHotkeyやHotstringsの一覧表示を作成しダブルクリックやEnterキーでエディタ画面の該当行に行けるahkスクリプト (2026/02 Update)

はじめに

2025/12に公開したHotkeyの一覧が表示できるahkスクリプト

torazaemon2016.hatenablog.jp

Hotkey一覧表示例

をUpdateしました。

更新点は、

  • 選択行のダブルクリックだけではなく、Enterキーでも、エディタの編集画面に飛ぶようにしたことです。

ListViewにてEnterキーを押すことでDoubleClickと同じ処理を行う方法として、 Enterキーを捕捉するため、ボタンのオプションを "Default" にした非表示(枠外、サイズ)のデフォルトボタンを設置する ことで実現しています。

Keyword: ahk, V2, Hotkey, Hotstrings, 一覧表示, VScode

スクリプト

利用したい方は、以下の「エディタ指定」と「一覧にしたいファイルの指定」の2か所の修正を行ってください。

エディタ指定

最初にeditor変数にコマンドへのファイルパスを指定してください。 コマンドラインで行番号を指定して起動できるエディタを利用してください。 現在は、ユーザインストールのVScodeになっています。

;;エディタ指定
;editor := "Notepad.exe"    ; メモ帳は行番号ジャンプできない
;;VScode
;editor := "C:\Program Files\Microsoft VS Code\Code.exe"
editor := "C:\Users\" A_UserName "\AppData\Local\Programs\Microsoft VS Code\Code.exe"
;;notepad++
;editor := "C:\Program Files\Notepad++\notepad++.exe"

エディタによって、指定行番号へ飛ぶという処理が違うので、 スクリプトの最後のほうにあるEdit_file()の中で、ifで判断していますので、そちらもご確認ください。

現在は、VS Codeとnotepad++での定義の記載があります。 そのほかのエディタを利用されている方は、各自で拡張してください。

VScodeの場合:

 options := "--goto `"" A_ScriptDir "\" FileName ":" Line "`""   ; VScode

Notepad++の場合:

 options := "`"" A_ScriptDir "\" Filename "`"" " -n" Line        ; notepad++

一覧にしたいahkスクリプトファイルを指定

関数CreateHotkeyMapGui(*)にて、

CreateHotkeyMapGui(*)
{
    target := A_ScriptDir "\*.ahk"              ; Folder + \ + *.ahk
    ;target := A_ScriptDir "\Autohotkey.ahk"    ; only 1 File

としている部分で、一覧表示するahkファイルを指定しています。

上の場合は、ahkスクリプトのあるフォルダ内の拡張子が.ahkのものすべての一覧を作成することになります。

以下 Autohotkey-ListingHotkeys.ahk

以下のスクリプトを右上のコピーボタンを押して、クリップボードにコピーし、適当なエディタに貼り付けて、 Autohotkey-ListingHotkeys.ahk という名前で保存してください。

Autohotkey V2がインストールされていれば、保存したAutohotkey-ListingHotkeys.ahkをダブルクリックすると、起動されます。 起動したら、「Alt + 4」で一覧ウィンドウが表示されます。

表示された行をダブルクリックすると、エディタが起動して、その行のところで表示されているはずです。

; 2025-11-28 
; Autohotkey Listing Hotkeys and Hotstrings + Functions
; by torazemon2016
; https://www.autohotkey.com/docs/v2/lib/ListView.htm

#Requires AutoHotkey 2.0+
#SingleInstance Force

;;エディタ指定
;editor := "Notepad.exe"    ; メモ帳は行番号ジャンプできない
;;VScode
;editor := "C:\Program Files\Microsoft VS Code\Code.exe"
editor := "C:\Users\" A_UserName "\AppData\Local\Programs\Microsoft VS Code\Code.exe"
;;notepad++
;editor := "C:\Program Files\Notepad++\notepad++.exe"

!4::    ; Autohotkey_V2.ahk
{
    CreateHotkeyMapGui()
}

CreateHotkeyMapGui(*)
{
    target := A_ScriptDir "\*.ahk"              ; Folder + \ + *.ahk
    ;target := A_ScriptDir "\Autohotkey.ahk"    ; only 1 File

    title := "AHK Hotkey List"
    MyGui := Gui("+Resize",title)       ; Allow window maximizing
    MyGui.OnEvent("Close", Gui_Close)   ; _ □ X (Close)
    MyGui.OnEvent("Escape", Gui_Close)   ; Press [ESC] key (Close)
    MyGui.OnEvent("Size", Gui_Size)     ; Resize
    MyGui.SetFont("s16")                ; Font Size

    ; ListView
    LV := MyGui.Add("ListView", "+Grid r20 w1400 h600", ["Filename","Line","Type","Key", "Description"])
    ;LV.OnEvent("Click", Edit_File)         ; 
    LV.OnEvent("DoubleClick", Edit_File)    ; Run Editor

    ; Main
    Load_hotkeys(target)                

    ; The column size is not determined until after the data is loaded, so ModifyCol will be executed later.
    LV.ModifyCol()                      ; Auto-size each column to fit its contents.
    LV.ModifyCol(2, "70 Integer")       ; Line Number
    ;LV.ModifyCol(3, 100)               ; Type (Hotkey,Function,etc)
    LV.ModifyCol(4, 400)                ; Key

    ; 2026-02-04 
    ; Enterキーを捕捉するため、ボタンのオプションを "Default" にした非表示(枠外、サイズ)のデフォルトボタンを設置する
    Btn := MyGui.Add("Button", "Default x-10 y-10 w0 h0", "OK")
    Btn.OnEvent("Click", (*) => Edit_File(LV, LV.GetNext(0, "Focused")))

    MyGui.Show("x0 y200 AutoSize")      ; 

    ;----------------------------
    Load_hotkeys(files)
    {
        Loop Files, files
        {
            ;MsgBox(A_LoopFileName)
            Read_file(A_LoopFileName)
        }
    }

    Read_file(filename)
    {
        Loop read, filename ; Read line by line from a file
        {
            line := A_index

            if RegExMatch(A_LoopReadLine, '^(\s)', &m)  ; If the beginning of the line is blank
                continue                                ; next line

            if(InStr(A_LoopReadLine,"#Include") == 1)   ; ==1 If the first character is #Include
                Store_LV(filename, line, "Include", A_LoopReadLine)
            
            if(InStr(A_LoopReadLine,"::") != 0)         ; Hotkeys and Hotstrings found ('!= 0' means found)
            {
                if(InStr(A_LoopReadLine,";") == 1)      ; If the first character is ;
                    Store_LV(filename, line, "commentout", A_LoopReadLine)
                else if(InStr(A_LoopReadLine,":") == 1) ; If the first character is :
                    Store_LV(filename, line, "Hotstrings", A_LoopReadLine)
                else
                    Store_LV(filename, line, "Hotkey", A_LoopReadLine)
            }
            else if RegExMatch(A_LoopReadLine, '^[a-zA-Z].*\(.*\)', &m) ; Function found 
            {
                if(InStr(A_LoopReadLine,":=") == 0)     ; If it is not an assignment expression ('==0' means not found)
                    Store_LV(filename, line, "Function", A_LoopReadLine)
            }
        }
    }

    Store_LV(filename, line, type, str)
    {
        ;MsgBox(filename " " line " " kind " " str)
        parts := StrSplit(str, ";")
        key := ""
        comment := ""
        if(type == "commentout")    ; ex. ;F1:: ; comment1 -> parts[1] == "" ; parts[2] == F1 ; parts[3] == comment1
        {
            key := parts[2]
            if(parts.Length >= 3)
                comment := parts[3]
             else
                comment := ""
        }
        else                        ; ex. F1::  ; comment1 ; comment2 -> parts[1] == F1 ; parts[2] == comment1 ; parts[3] == comment2
        {
            key := parts[1]
            if(parts.length >= 3)
                comment := parts[2] . " " . ";" . " " . parts[3]
            else if(parts.length == 2)
                comment := parts[2]
            else
                comment := ""
        }

        LV.add(, filename, line, type, key, comment)
    }

    ;----------------------------
    Gui_Close(*)
    { 
        MyGui.Destroy()
    }


    Gui_Size(thisGui, MinMax, Width, Height)  
    {
        if(MinMax == -1)  ; The window has been minimized. No action needed.
            return
        else
            LV.Move(,, Width - 20, Height - 20) ; Expand/Shrink ListView
    }

    ;----------------------------
    Edit_File(LV, RowNumber)
    {
        ;RowText := LV.GetText(RowNumber)
        ;MsgBox("選択された行: " RowNumber "`n内容: " RowText)
        if (RowNumber == 0) ; 行が選択されていない場合は何もしない
            return

        FileName := LV.GetText(RowNumber, 1)
        Line := LV.GetText(RowNumber, 2)
        ;MsgBox(editor " " Filename " " Line , 0x40000)
        try
        {
            options := "`"" A_ScriptDir "\" Filename "`""
            if(InStr(editor,"VS Code") != 0)            ; Match ('!= 0' means found)
            {
                options := "--goto `"" A_ScriptDir "\" FileName ":" Line "`""   ; VScode
            }
            else if(InStr(editor,"notepad++") != 0)
            {
                options := "`"" A_ScriptDir "\" Filename "`"" " -n" Line        ; notepad++
            }
            Run(editor " " options)
        }
        catch
            MsgBox("Could not " editor " " options)
    }

}

Enterキーでエディタに行けるので、カーソルキー上下とEnterでアクセスでき、マウスが必要なくなりました。

ご利用いただき、改良などコメントいただけると幸いです。