顯示具有 hotstring 標籤的文章。 顯示所有文章
顯示具有 hotstring 標籤的文章。 顯示所有文章

2016年3月12日 星期六

Hotstring優化:追求極致速度

AutoHotkey的最大優點就是簡易的語法,方便設定hotstringhotkey。不過畢竟最後是CPU在跑,寫一行程式碼,不一定比三行程式碼還快,要讓程式跑得快,還是要以電腦的角度去思考。例如以最簡單的 ::btw::by the way 為例,trigger之後AutoHotkey會模擬鍵盤傳給Windows的code,Windows再送到active的文字編輯器,文字編輯器被接收到一個鍵會觸發/更新一些內建數值(例如目前是第幾個字元、總共幾個字元、儲存上個狀態以便Ctrl+Z可以復原等等),然後更新文字輸入區的畫面,讓使用者知道程式沒當掉依然有反應。在AutoHotkey的範圍內可做到幾點優化:
  • SetBatchLines -1
    • 預設設定下,AutoHotkey每執行一行程式碼,會短暫休息,再執行下一行,以避免讓CPU太操。但既然用AutoHotkey就是要效率,給他催下去!
  • SendMode, Input
    • 預設的Send是SendEvent模式,但SendInput在大部分的狀況下是Z>B,包括
      • 送字速度快
      • 因為有buffer,如果程式正在send字串時使用者也按下鍵盤,使用者按的鍵會在字串送完時接上,而不會中斷(最多buffer 5000個字元)
  • SetKeyDelay, -1, -1
    • 這個設定也是類似SetBatchLines,為了模擬正常人類按鍵,按下去會有一定duration,兩個按鍵間一定有一些delay,通常是遊戲才會偵測有沒有cheat
    • 雖然這個設定影響的是SendEvent,但有非常少數情況下AutoHotkey會自動從SendInput轉換成SendEvent或SendPlay,所以還是可以設定
  • 複製貼上法
    • 對於較大量的字串,例如某個procedure note的範本,用send會非常慢。比較直覺的方式是用剪貼簿當作媒介來複製、貼上

    • 註解掉的兩行是為了保留原本的剪貼簿內容,但在連續輸入的情況下不太需要
    • 有一說要搭配ClipWait,但日常小量字串應該都能順利運作,所以沒有使用
    • 實測比較SendInput和sendByClipboard,發現大概以7~10個字元為分界,更多的字元後者較快,較少的字元前者較快。
    • sendByClipboard的缺點:
      • 組合鍵(用到Ctrl, Alt, Shift, Win等)無法用(不過通常也不會很大量)
      • 單行定義的Hotstring會依據首字是否大寫/全部大寫,送出相對應的字串(首字大寫/全部大寫),sendByClipboard只能用笨方法來模擬。(注意後兩個搭配c選項)

  • 直接送字法
    • 利用剪貼簿畢竟多了一道程序,可以直接設定輸入框裡要顯示的文字。
    • Standard edit control可以搭配Edit library,測試會比剪貼簿方法還快,但缺點是全部文字整個更新,畫面可能會閃一下,或者捲軸的位置不一樣:

    • Scintilla control是SciTE、NotePad++所使用的,可以搭配Scintilla wrapper以及自己寫的RemoteScintilla,速度和standard edit差不多,優點是很多強大的功能
      • 在自己的gui建立及操作Scintilla control要用Scintilla wrapper,但如果要access或modify其他process中的Scintilla control,則要用RemoteScintilla,利用_RemoteBuf library搭配Scintilla Documentation裡列出的messages(AutoHotkey的ControlGetText和ControlSetText只針對standard edit)。
      • 利用SCI_ADDTEXT,可以在游標處插入字串,而且游標會跳到加入字串的最後面,和Hotstring或是複製貼上的動作是一致的。

    2015年12月18日 星期五

    Dynamic Hotstring實例

    之前在「自己寫武功祕笈:Radiologist的第一個Autohotkey」提到一點dynamic hotstring的使用,這篇再介紹幾個實用範例。

    Prerequisite

    • Regular expression:雖然看起來像火星文但真得很重要(自行覆頌三遍),可參「Regular Expression入門
    • AutoHotkey_L:一般而言用Unicode 32-bit
    • Dynamic hotstring的library:AutoHotkey的論壇上可以找到幾種版本,我用的是比較多選項的這個版本
      • 下載Hotstring.ahk存到AutoHotkey主程式資料夾內的Lib資料夾,或者ahk檔資料夾內的Lib資料夾(詳見說明
      • ahk檔開頭加上#include <Hotstring>
    • 自訂的hotstring是以函數方式執行,所以要放在auto-execute section內,簡單來說就是在第一個return之前的範圍

     範例1:日期

    • 輸入:8個數字,再加上一個分隔字元,例如20151218/
      輸出:2015/12/18


     範例2:檢查部位

    • 輸入:不定部位的字母代號,加上without/with contrast enhancement數字代號,以及一個結尾符號,例如b1=
      輸出:CT of the brain without contrast enhancement shows:

    範例3:lines and tubes for CXR

    • 輸入:數個字母代號,加上結尾符號,例如tgv=
      輸出:Placement of endotracheal tube, nasoenteric tube, central venous catheter(s).

    2015年8月9日 星期日

    Structure of AutoHotkey Script

    開始上工打報告,除了看說明檔學AHK的語法、函數,有些程式撰寫的概念是在說明檔學不到的,身為業餘工程師(?)分享一些用血淚(?)堆出的心得~

    單一檔案


    • 大概是老師輩比較常用的,攜帶方便,一個ahk檔和一個AutoHotkey.exe主檔就可以到處帶著走,不管電腦有沒有安裝AutoHotkey,或是電腦內AutoHotkey版本不一樣,只要把ahk檔拖曳到主檔就好了。
    • 老師輩的AHK大部分是以字母順序排序,而且hotstring以全部大寫設定
      • 優點:管理方便,搜尋快速(人眼搜尋就很快了)
      • 缺點:
        • 只有hotstring字母按順序,送出string沒什麼順序,明明是相似的內容(例如left、right)但彼此距離很遠。
        • 重複的string可能分給不同的hotstring而不自知。
    • CWY老師的script雖然是字母排列,但是兼顧系統分類,例如:
      • 「J」開頭通常是joint →  JGH 是glenohumeral joint
      • 「B」開頭是bone的某個部分 →  BFI 是femoral intertrochanteric region
      • 「Q」開頭指的是某個方位 →  QP 是posterior aspect。

    多個檔案

    • 最近幾屆的學長姐開始區分不同用途的script,通常有一個打plain film,有一個打CT/MR,根據group可能再多一個打特殊檢查例如mammography。
    • 優缺點大致和單一檔案的情形相反:
      • 優點:
        • 各script所用的hotstring可以重複,同樣是「C0」,可以設定為Chest X-ray的normal report,也可以設定為Chest CT的normal template。
        • script內的hotstring較少,效能較好(影響不大),比較不會因為電腦lag出現使string延遲送出
      • 缺點:
        • 需要切換script,當然,通常打報告時會集中打同一種類的檢查,再打另一種類的檢查,並不如想像中要一直切換(除了值班時急診報告?)
        • 管理不易,有些通用hotstring要在每一個script都寫一次,例如 L 是left,R 是right,不論是哪一種報告的script都需要

    樹狀結構

    • 學弟妹接觸AHK較多,開始會用樹狀結構,把某些hotstring寫在main.ahk,再各自有CT.ahk、CXR.ahk之類的,然後include main.ahk,大致也是我用的方法但底下會再細談
    • 優點和上一個類似,新增的優點是有main.ahk可以寫通用的hotstring
    • 缺點就是複雜,如果加上一堆hotkey、function、subroutine,因為AHK先天不嚴格的語言結構,有時候很難找到出錯的地方,debug不易。但如果每個script都是純粹的hotstring/string pairs,樹狀結構其實是最好的。

    Some Tips

    • 我的script架構是樹狀,基本上就像其他程式語言的library一樣,分工合作!
    • 因為hotstring的數量不會太影響效能,所以原則上是能縮寫就縮寫,從word、phrase、sentence到paragraph,只要用縮寫就是會比較快!(當然,要記憶的hotstring較多)
    • 基於歷史因素,因為resident時打最多的是急診CT,main.ahk就包括general term以及CT/MR會用到的片語/句子/範本
      • 在script中以用途/部位分類:
        • history/title:哪幾個部位的CT、有沒有打顯影劑,事實上這部位是以dynamic hotstring去送出字串。
        • 方位:上下左右內外深淺,及搭配「aspect of」
        • 一般字詞:thickening, wall thickening, fat stranding, stenosis, narrowing之類的都有設定hotstring
        • 輔助詞:把finding串接成句子/不完整句的一些輔助詞,例如there is, is suspected, is noted, suggestive of, probably, showing, causing, nature to be determined之類的
        • 各部位:brain, neck, chest, body, MSK, intervention
      • 在各個部分,剛開始以字母排序但後來就隨意了,反正有Hotstring Helper可以查詢,不需要用Ctrl + F找
      • 通常hotstring以「1」結尾代表名詞複數,例如::nd::nodule,則:*:nd1::nodules,加星號表示不用ending character。但在形容詞/動詞則是詞性變化,例如::enl::enlarged, :*:enl1::enlargement;::sig::significant, :*:sig1::significantly。
      • 用數字也可以代表程度,例如brain atrophy、leukoaraiosis的罐頭敘述
      • 基本上hotstring以2個或3個字母為主,因為排列組合後其實很夠用,最最最常用的才是1個字母,不常用的或是template可用到4個字母。為了避免重複,以子音決定所用的hotstring。
      • 其他一些dynamic hotstring也會在main.ahk設定,為了避免dynamic hotstring和一般的hotstring相衝突,dynamic hotstring常以特殊字元結尾當作trigger(例如 =, /)
    • Plain film的ahk以CXR, KUB, MSK plain film為主,然後在最後一行include main.ahk
      • main.ahk裡的auto-execute section無法被執行(函數的定義還會在),所以需要用到的dynamic hotstring需要在plain film重新寫入。
      • 如果有重複的function、subroutine名稱會出錯,考慮加上namespace的概念,例如main_func和plain_func以區分。
      • hotstring是先搶先贏制,所以plain film中的hotstring會優先於最後一行include進來的main.ahk。例如::ll::left lung,則main.ahk的::ll::on the left side就沒作用
      • Hotkey無法重複定義,但如果用dynamic hotkey則可以啟動、停止、覆蓋舊的hotkey
      • 在確認報告(F3)時,會check報告內容(plain film報告不分段)再送出
        • 句首字母大寫
        • 兩個以上的點「..」變成一個點「.」:打報告時以「.」來觸發hotstring(雖然沒有證據證明,但我覺得按空白鍵觸發比較容易在string還沒全部送出前就穿插在句子中間)
        • 「.,」變成「,」:需要補充句子(例如要加上more on the right side.)則以「,」觸發hotstring
        • 如果有三個字母/數字就接著句點,表示hotstring打錯或是沒觸發,出現提醒。
      • 打plain film時,active的視窗是PACS還是可以按F3送出報告。
      • 因為plain film有時候會爆量打不完,所以hotstring要盡量用1-2個字母,就像嘸蝦米輸入法一樣,一碼/兩碼都有對應的字(雖然很多要死背)。
    • 另外還有mammography的ahk
    • 一旦發現有字詞沒有hotstring一定要馬上新增,不能偷懶!
    • 少用到的字母如Z, X, Y, Q等都可以用來當hotstring,例如前面提到的Q當作某個aspect(記法:Quadrant)、Z當作和某個檢查/臨床correlation(記法:coRRelation)的敘述

    2014年7月9日 星期三

    自己寫武功祕笈:Radiologist的第一個Autohotkey

    開發環境

    主程式

    • 官方版autohotkey
    • Autohotkey_L:根據官方版加入更多功能,例如unicode支援、64位元支援、物件導向,而且有提供簡體中文的說明檔
    • 以上都有提供portable版本,免安裝,解壓縮後就可以直接用

    Script File

    •  只有主程式沒用,還需要script才能做事,script的副檔名是ahk,但本質上就是文字檔,可以用任何文字編輯軟體打開撰打
    • 同樣是文字檔會有不同的編碼方式,原PO儲存時都使用UTF-8 (with BOM),對於中文字或是其實特殊文字比較不會變亂碼

    編輯器

    • 工欲善其事,必先利其器,好的編輯器可以讓寫程式更有效率,包括偵測錯誤、函數提示、顏色標示
    • 原PO使用的是SciTE4Autohotkey,一樣有分安裝版和portable版

    寫程式

    前言

    • 所有程式都能做很簡單或是很複雜的事,autohotkey也是,尤其autohotkey特別針對日常使用電腦需要用到的功能,寫起來非常有效率,用最少的程式碼做最多的事
    • 本篇主要介紹血汗國家(地區?)的放射科醫師,靠著autohotkey在夾縫中求生存的一段故事

    模擬鍵盤、滑鼠

    • 基本上打報告的所有動作,包括鍵盤上任何按鍵、滑鼠上任何按鍵和動作,都是可以模擬出來的,所以寫程式的第一步是思考、設計,「我要我的程式做什麼事情」,而且要step by step,分析每一個步驟
    send
    • 官方詳細說明
    • 送出一個按鍵,例如:send blabla
    • 英文字母、數字、特殊符號可以直接送出,例如:send abc123&*?
      • 例外的是 ` ,要在字元前加一個`,也就是 send ``
      • ! # + ^ { } ,這些字元有特殊用途,要用大括號包圍起來,表示送出原本的字元而不是特殊用途,例如 send {!}{#}
    • 功能鍵(會自動和右邊一個按鍵變組合鍵)
      •  ^ 表示ctrl,例如 send ^c 就是按 ctrl + c
      •  ! 表示alt,例如 send !{F4} 就是按 alt + F4
      •  + 表示shift,例如 send ^+{esc} 就是按 ctrl + shift + esc
      •  # 表示視窗鍵(ctrl和alt中間那個),例如 send #e 就是按 win + e
    • 特殊字元
      • { } 包圍起來,族繁不及備載,可參考說明檔,大部分都很直覺,常用如下
      • {enter} {space} {tab}
      • {backspace} 或 {bs}、{delete} 或 {del}
      • {up} {down} {left} {right} {home} {end} {pgup} {pgdn}
      • {F1} ~ {F12}
      • 在數字盤的按鍵都是這個形式:{Numpad___}
    • 滑鼠按鍵
      • {LButton} {RButton} {MButton}
      • {WheelUp} {WheelDown}:滾輪
    • 重複同一個按鍵:send {space 10}會送出10個空白鍵

    Hotstring & Hotkey & Settings


    ::cct::CT of the chest without and with contrast enhancement is read and compared with prior study dated . This CT study shows:{left 22}
    •  送出了這段文字,通常會將游標移到前面填入日期,所以在後面加上{left 22},將游標往左移動22次
    •  或者可以用^{left 5},因為 ctrl + left 會往左移動一個「字」而不是「字元」,但使用後的效果不如前一個方法精準
    SendMode Input
    • 將send mode改成input模式,比較不會發生打報告打太快時,autohotkey送出的模擬按鍵和自己實際按的按鍵交錯送出
    ^!x::suspend
    • 打報告時還是常需要google查資料(&上facebook?),這時可以用suspend指令將這個script的所有hotstring和hotkey停用,繼續打報告時再按同一個快速鍵(也只有這個快速鍵不會被停用)回復
    ^!r::reload
    • 如果script在執行中,修改程式碼後要重新執行,可以直接用reload指令
    ^!e::
    inputbox,addahk
    if addahk!=
        fileappend,% addahk,% A_ScriptFullPath
    reload
    return

    • 跳出一個輸入框,輸入的文字(例如新的hotstring)會加到原本的script最底下,然後reload整個script,就能使用剛加入的hotstring
    ^!q::exitapp
    • exitapp指令可以離開整個script
    ~+enter::
    ~+NumpadEnter::
    send -{space}

    return
    •  bullet是項目符號,每個人用的都不一樣,原PO是用「- 」,設定快速鍵後按 ctrl + enter 可以跳到下一行並輸出項目符號

    Dynamic Hotstring

    • 進階版的hotstring,見AHK論壇
    • 原始的hotstring是一對一的關係,打出一些特定的字跳出一些特定的字,dynamic  hotstring則是多對多的,打出某些pattern的字跳出某些pattern的字
    • 常見在一些列舉項目,例如left/right/bilateral、head/neck/chest/abdomen/pelvis,或是需要輸入某些數字,例如SE3 IM20,都適合用dynamic hotstring,舉一個例子…
    #include hotstring.ahk

    hotstring("([.\W])?(\d+)\.\.(\d+)(\W)","specifyImage",3)
    return

    specifyImage:
    if $.value(1)="."
        send % "(SE" $.value(2) " IM" $.value(3) ")" $.value(4)
    else
        send % $.value(1) "SE" $.value(2) " IM" $.value(3) $.value(4)
    return

    • 下載Hotstring.ahk後放到自己的script的資料夾;自己的script(通常在最前面)要有一行#include hotstring.ahk載入函數
    • hotstring("([.\W])?(\d+)..(\d+)(\W)","specifyImage",3)要放在「第一個return」之前,因為return之後的程式碼不會被直接執行
      • ([.\W])?(\d+)..(\d+)(\W)表示要trigger的pattern
      • specifyImage表示trigger後要執行的段落標籤
      • 3表示pattern是用regular expression
    • 總之最後的效果是
      • 輸入 .3..20 ,輸出 (SE3 IM20) 
      • 輸入 3..20 ,輸出 SE3 IM20 

      2013年11月23日 星期六

      Hotstring Helper

       Tool for Radiology Resident !!

      Background

      • 當resident開始用起VS們的ahk...
        • 看shoulder plain film,一直要打down-sloping and low-lying of the acromion真是累
        • 打開游醫師的cwy.ahk,搜尋看看有沒有對應的hotstring
        • 找到了!以後只要打「shd」就會是down-sloping and low-lying of the acromion
        • 這樣實在太浪費時間了!!

      Hotstring Helper使用說明

      • 把要查詢的ahk(可以多個)全部複製到Hotstring Helper.exe的資料夾 
      • 執行Hotstring Helper.exe
      • 開啟RIS (目前限制在RIS裡才查詢)
      • 打報告打一半想查某個字(eg. acromion)相關的hotstring,則打「;acromion」,也就是一個分號,再接著查詢的單字
      • 如上圖只要當作注音輸入法使用,輸入0~9後就會把剛才的「;acromion」取代成候選句
        • 輸入0是第10個候選句,不是第一個!
      • 其他小技巧及注意事項
        • 如果按空白鍵則自動選擇第一個候選句
        • 至少輸入三個字母以上才會查詢,就上面的例子至少要輸入「;acr」才會出現選單
        • 如果有一頁以上的結果,可用滑鼠滾輪捲動
        • 只要輸入字母以外的按鍵(eg. ESC),或是滑鼠按鍵,就會停止查詢,選單消失
          •  問號(?)和星號(*)為例外,問號表示「任一字元」,星號表示「零或多個字元」
          • 例如「gr?y」會搜尋grey或gray
        • 或者可以先key一串字(片語、句子),選取後按Alt+F搜尋



      2012年11月27日 星期二

      Autohotkey hotstring簡介

      前言

      • 參考Autohotkey說明文件
      • ahk的指令一般是不分大小寫,忽視額外/行末的空白鍵,除非特別說明。


      簡介、 簡單範例

      ::btw::by the way
      • btw是hotstring,兩邊各夾著::,打完hotstring再按ending character(例如空白鍵、標點符號),btw就會替換成by the way
      ::btw::
      Msgbox You typed "btw".
      return
      • hotstring可以搭配ahk的指令,本例為輸入btw後跳出訊息框顯示You typed "btw".


      Ending Characters

      • 除非另外設定(見底下"*"設定),輸入ending character才會觸發hotstring,預設的ending character包含-()[]{}:;'"/\,.?!`n `t,其中`n為斷行(按Enter),`t為tab,`n`t之間有一個空白(空白鍵)。
      #Hotstring EndChars -()[]{}:;'"/\,.?!`n `t
      • Ending characters可更改,但會作用到整個script,不像底下介紹的設定是作用到其後的hotstring。


      常用設定

      #Hotstring c r *0
      • hotstring設定影響到所有其後的hotstring,上面的指令將設定cr兩個選項。
      • *0表示將*這個設定關掉(加一個零在後面)。
      :cr:j@::john@somedomain.com
      • 另一種方式是寫在前兩個冒號之間,這樣的設定只會影響當前的hotstring,後面的hotstring不會影響。
      * (星號)
      • 不需要輸入ending characters便能觸發hotstring。
      ? (問號)
      • hotstring可以在一個單字內部被觸發。
      b0
      • 預設情況hotstring觸發時,會先送出backspace將原hotstring刪除,再輸出替代的字串,b0設定則不送出backspace,保留原hotstring。
      • 例如:*b0:<td>::</td>{left 5},在輸入時(不需要ending character因為有星號*設定),自動輸出以及五個左方向鍵,最後游標停在<td>和</td>之間
      c
      • hotstring為區分大小寫,:c:Btw:::c:btw::是不一樣的hotstring。
      c1
      • 預設情況輸入的hotstring為首字大寫(eg. Btw)時,送出的字串也是首字大寫(eg. By the way);輸入的hotstring全部大寫(eg. BTW),則送出的字串也全部大寫(eg. BY THE WAY);其他的輸入方式,則照原字串輸出。c1設定則不管輸入的大小寫,都照原字串輸出。
      o
      • 預設情況輸入ending character會觸發hotstring,且保留ending character。o設定仍要輸入ending character,但ending character會被刪除。
      • 適用於名詞複數、所有格、動詞過去式的情況。以:o:nd::nodule為例,nd s會輸出nodules
      r
      • 預設情況輸出字串中{enter}是Enter、^c是ctrl+c(詳見Send)。r設定(raw)則忽視特殊字元,字串中是{enter}就輸出{enter}。


      Long Replacements

      ::text1::
      (
      line1, blabla
      line2, blabla
      )
      • 如上面格式時,可以輸出一大段文字。預設使用r設定,視括號內為純文字,除非以r0設定蓋過。


      Context-sensitive Hotstrings

      #IfWinActive 放射線資訊管理系統
      ::scc::suggest clinical correlation
      #IfWinActive
      ::scc::squamous cell carcinoma
      • #IfWinActive所夾住的程式碼,表示在某個視窗active時才會作用,scc會輸出suggest clinical correlation,在其他視窗則是squamous cell carcinoma。也可用#IfWinExist


      AutoCorrect

      • 官網所提供的自動拼字校正ahk,收集4700個常見的英文拼字錯誤。按Win+h可加入新的拼字校正。


      其他

      ::test::
      SendInput %var%
      return
      • 如果要輸出一個變數的值,則要用SendInput指令輸出var的值。
      ::btw::by the way   `
      ::btw:: by the way
      • 在行末加一個accent/backtick ( ` ),則`之前的空白也包含在輸出的字串。此例btw將輸出by the way  
      • 第二行則會輸出 by the way(注意最前面的空白)
      #Hotstring NoMouse
      • 預設情況下滑鼠左右鍵的點擊會重設hotstring,因為滑鼠動作通常表示使用者要改變輸入位置。可用上述設定使滑鼠動作不動設hotstring。
      A_EndChar
        • 內建變數A_EndChar會儲存最後一個ending character,可判斷A_EndChar達到不同的輸出方式。
        ::`t`n``::
        • 在ahk中有些escape character,如果作為hotstring也需要以`來escape,除了逗點 ( , )、百分比符號 ( % )、冒號 ( : )。
        ::texts::
        SendPlay %var%
        return
        • hotstring最多40個字元。在SendInput模式下最多輸出5000個字元,在其他模式最多16383個字元。利用上述SendPlay輸出變數值,則沒有上限。另外參考SendMode,一般建議設定SendMode Input
        ::hs::string1
        ::hs::string2
        • 如果同時有兩個以上的hotstring被觸發,會優先觸發在script中出現的第一個。在此例中hs會觸發string1。

        • Backspace並不會重設hotstring,所以打成btx後按backspace再打w仍是觸發btw;但方向鍵、上一頁、下一頁、Home、End會重設hotstring。
        • 可參考Input以達到更進階用途。


        實用範例

        :*?:``::+^{left}{bs}
        • 在輸入單字途中(?設定)可觸發,不需要ending character(*設定)。
        • hotstring為鍵盤最左上角的`(以`來escape,`` = `),可觸發shift (選取) + ctrl+左方向鍵 (跳到一個單字之前) + backspace (刪除)
        • 總結來說類似backspace,但backspace刪除一個字元,而上述hotstring刪除一個單字。