UWSCのINPUTボックスに補完機能を追加する

ま、完璧じゃないですけどね。
でも、なんとなくは使える。



スクリプト

とりあえず、入力をUWSCのコマンド先頭何文字かとみなすタイプで。

OPTION EXPLICIT

THREAD Complete

DIM code = ""
WHILE code <> EMPTY
	code = INPUT("?")
WEND


PROCEDURE Complete
	DIM base = SPLIT("DIM PUBLIC CONST IF THEN ELSE IFB ELSEIF ENDIF SELECT CASE DEFAULT SELEND FOR NEXT TO STEP WHILE WEND REPEAT UNTIL CALL BREAK CONTINUE EXIT PRINT AND OR XOR MOD PROCEDURE FUNCTION FEND RESULT VAR DEF_DLL OPTION THREAD CLASS ENDCLASS THIS GLOBAL WITH ENDWITH TEXTBLOCK ENDTEXTBLOCK HASHTBL TRY ENDTRY EXCEPT FINALLY GETID CLKITEM CHKBTN CTRLWIN SENDSTR GETSTR GETITEM GETSLCTLST SETSLIDER GETSLIDER SCKEY GETALLWIN STATUS MOUSEORG PEEKCOLOR CHKIMG SAVEIMG MUSCUR POSACC INPUT MSGBOX SLCTBOX POPUPMENU FUKIDASI STOPFORM LOGPRINT MONITOR EXEC SLEEP DOSCMD POWERSHELL SOUND GETTIME POFF KINDOFOS CPUUSERATE GETKEYSTATE SETHOTKEY LOCKHARD EVAL GETCTLHND IDTOHND HNDTOID VARTYPE MMV BTN KBD ACW COPY POS LENGTH CHKNUM VAL REPLACE TRIM FORMAT CHR ASC ISUNICODE STRCONV TOKEN BETWEENSTR COPYB LENGTHB POSB CHRB ASCB RESIZE SETCLEAR SHIFTARRAY CALCARRAY SPLIT JOIN SLICE QSORT FOPEN FGET FPUT FDELLINE FCLOSE GETDIR DROPFILE READINI WRITEINI DELETEINI CREATEOLEOBJ GETACTIVEOLEOBJ GETOLEITEM OLEEVENT COM_ERR_IGN COM_ERR_RET SAFEARRAY SPEAK RECOSTATE DICTATE IEGETDATA IESETDATA IEGETSRC IESETSRC IELINK ENCODE DECODE CREATEFORM GETFORMDATA SETFORMDATA XLOPEN XLCLOSE XLACTIVATE XLSHEET XLGETDATA XLSETDATA RANDOM ABS ZCUT INT CEIL ROUND SQRT POWER EXP LN LOGN SIN COS TAN ARCSIN ARCCOS ARCTAN PARAM_STR[] ALL_WIN_ID[] ALL_ITEM_LIST[] GETDIR_FILES[] ALL_OLE_ITEM[] EVENT_PRM[] GET_WIN_DIR GET_SYS_DIR GET_CUR_DIR GET_APPDATA_DIR GET_UWSC_DIR GET_UWSC_VER GET_UWSC_NAME COM_ERR_FLG G_IMG_X G_IMG_Y G_SCREEN_W G_SCREEN_H G_SCREEN_C G_MOUSE_X G_MOUSE_Y TRY_ERRMSG TRY_ERRLINE HOTKEY_VK HOTKEY_MOD G_TIME_YY G_TIME_MM G_TIME_DD G_TIME_HH G_TIME_NN G_TIME_SS G_TIME_ZZ G_TIME_WW G_TIME_YY2 G_TIME_MM2 G_TIME_DD2 G_TIME_HH2 G_TIME_NN2 G_TIME_SS2 G_TIME_ZZ2 G_TIME_YY4 TRUE FALSE NULL EMPTY NOTHING ERR_VALUE GET_SLIDER GET_MENU_HND GET_SYSMENU_HND ACTIVATE CLOSE CLOSE2 HIDE SHOW MIN MAX NORMAL TOPMOST NOTOPMOST CLICK DOWN UP LEFT RIGHT MIDDLE WHEEL F_READ F_WRITE F_EXISTS F_LINECOUNT F_ALLTEXT CLK_BTN CLK_LIST CLK_TAB CLK_MENU CLK_TREEVIEW CLK_LISTVIEW CLK_TOOLBAR CLK_ACC CLK_SHORT CLK_BACK CLK_MOUSEMOVE CLK_RIGHTCLK CLK_LEFTCLK CLK_DBLCLK CLK_FROMLAST CLK_CONTINUE STR_EDIT STR_STATIC STR_STATUS STR_ACC_EDIT STR_ACC_STATIC BTN_YES BTN_NO BTN_OK BTN_CANCEL BTN_ABORT BTN_RETRY BTN_IGNORE SLCT_BTN SLCT_CHK SLCT_RDO SLCT_CMB SLCT_LST SLCT_STR SLCT_NUM SLCT_1〜31 ITM_BTN ITM_LIST ITM_TAB ITM_MENU ITM_TREEVIEW ITM_LISTVIEW ITM_EDIT ITM_STATIC ITM_STATUSBAR ITM_TOOLBAR ITM_ACCCLK ITM_ACCCLK2 ITM_ACCTXT ITM_BACK ST_TITLE ST_CLASS ST_X ST_Y ST_WIDTH ST_HEIGHT ST_CLX ST_CLY ST_CLWIDTH ST_CLHEIGHT ST_PARENT ST_ICON ST_MAXIMIZED ST_VISIBLE ST_ACTIVE ST_BUSY ST_PATH ST_PROCESS ST_WIN64 ST_MONITOR CUR_APPSTARTING CUR_ARROW CUR_CROSS CUR_HAND CUR_HELP CUR_IBEAM CUR_NO CUR_SIZEALL CUR_SIZENESW CUR_NS CUR_NWSE CUR_WE CUR_UPARROW CUR_WAIT ACC_ACC ACC_API ACC_NAME ACC_VALUE ACC_ROLE ACC_STATE ACC_DESCRIPTION ACC_LOCATION ACC_BACK P_POWEROFF P_LOGOFF P_REBOOT P_SUSPEND P_SUSPEND2 P_MONIPOWER P_MONIPOWER2 P_MONIPOWER3 P_SCREENSAVE P_UWSC_REEXEC P_FORCE TGL_IME TGL_NUMLOCK TGL_CAPSLOCK TGL_SCROLLLOCK GET_ACTIVE_WIN GET_FROMPOINT_WIN GET_FROMPOINT_OBJ GET_THISUWSC_WIN GET_LOGPRINT_WIN GET_FUKIDASI_WIN GET_FORM_WIN GET_SCHEDULE_WIN SC_LOWERCASE SC_UPPERCASE SC_HIRAGANA SC_KATAKANA SC_HALFWIDTH SC_FULLWIDTH FOM_NOICON FOM_MINIMIZE FOM_MAXIMIZE FOM_NOHIDE FOM_NOSUBMIT FOM_NORESIZE FOM_NOLUNA FOM_BROWSER CODE_URL CODE_UTF8 CODE_BYTEARRAY CODE_BYTEARRAYW CALC_ADD CALC_MIN CALC_MAX CALC_AVR IMG_MSK_BGR1〜4 IMG_MSK_B1〜4 IMG_MSK_G1〜4 IMG_MSK_R1〜4 MOD_ALT MOD_CONTROL MOD_SHIFT MOD_WIN SLD_POS SLD_MIN SLD_MAX SLD_PAGE SLD_BAR SLD_X SLD_Y MON_X MON_Y MON_WIDTH MON_HEIGHT COL_RGB COL_R COL_G COL_B MORG_CLIENT MORG_DIRECT MORG_FORE MORG_BACK VK_START VK_WIN VK_ALT VK_CTRL VK_RCTRL VK_ESC VK_BACK // BackSpace VK_TAB VK_CLEAR VK_RETURN // Enter VK_RRETURN // 右Enter VK_SHIFT VK_RSHIFT VK_CONTROL VK_MENU VK_PAUSE VK_CAPITAL // CapsLock VK_KANA VK_FINAL VK_KANJI VK_CONVERT // 変換 VK_NONCONVERT // 無変換 VK_ACCEPT VK_MODECHANGE VK_ESCAPE VK_SPACE VK_PRIOR // PageUp VK_NEXT // PageDown VK_END VK_HOME VK_LEFT // カーソル VK_UP VK_RIGHT VK_DOWN VK_SELECT VK_PRINT VK_EXECUTE VK_SNAPSHOT // PrintScreen VK_INSERT VK_DELETE VK_HELP VK_APPS // コンテキストメニュ VK_MULTIPLY // * VK_ADD // + VK_SEPARATOR VK_SUBTRACT // - VK_DECIMAL VK_DIVIDE // / VK_NUMPAD0〜9 VK_F1〜12 VK_NUMLOCK VK_SCROLL // ScrollLock VK_SLEEP VK_BROWSER_BACK VK_BROWSER_FORWARD VK_BROWSER_REFRESH VK_BROWSER_STOP VK_BROWSER_SEARCH VK_BROWSER_FAVORITES VK_BROWSER_HOME VK_VOLUME_MUTE VK_VOLUME_DOWN VK_VOLUME_UP VK_MEDIA_NEXT_TRACK VK_MEDIA_PREV_TRACK VK_MEDIA_STOP VK_MEDIA_PLAY_PAUSE VK_LAUNCH_MEDIA_SELECT VK_LAUNCH_MAIL VK_LAUNCH_APP1 VK_LAUNCH_APP2 VK_OEM_PLUS VK_OEM_COMMA VK_OEM_MINUS VK_OEM_PERIOD VK_OEM_1〜8 VK_OEM_RESET VK_OEM_JUMP VK_OEM_PA1〜3", " ")
	HASHTBL sels
	DIM wid = GETID("UWSC - " + GET_UWSC_NAME, "TFInpBox.UnicodeClass", -1), code, n
	WHILE wid <> -1
		IFB GETKEYSTATE(VK_TAB) THEN
			SCKEY(wid, VK_SHIFT, VK_TAB)

			code = GETSTR(wid)
			IFB LENGTH(code) THEN
				FOR n = 0 TO LENGTH(base) - 1
					IF POS(code, base[n]) = 1 THEN sels[n] = base[n]
				NEXT
				n = POPUPMENU(sels, STATUS(wid, ST_X), STATUS(wid, ST_Y) + 70)
				IF n >= 0 THEN code = sels[n, HASH_VAL]
				sels = HASH_REMOVEALL
			ENDIF
			SENDSTR(wid, code)

			GETKEYSTATE(VK_TAB)
		ENDIF
		wid = GETID("UWSC - " + GET_UWSC_NAME, "TFInpBox.UnicodeClass")
	WEND
FEND

解説

Complete関数をスレッドで動かしておき、TABキーを監視する。
TABキーが押されたら、Shift+TABしてフォーカスを一旦戻し、入力内容を取得。
それをbase配列と比較して、先頭一致すれば連想配列に格納。
連想配列でPOPUPMENUを出し、選択されれば内容を更新。
といったところ。


TABキーによるフォーカス遷移なんてしてるから、TAB連打に弱い、、、。


base配列はUWSCの予約一覧からコピーしているので、全角スペース区切り。
例えば、「TRY」を「TRY EXCEPT ENDTRY」といった半角スペース区切りにすれば、それが選択できる。
関数はテンプレートに置き換えても良いかもね。(「POS」でなく「POS( 探す文字, 探される文字, [n個目] )」とか)


先頭一致は、「IF POS(code, base[n]) = 1 THEN sels[n] = base[n]」で見ているので、最後の単語を先頭一致とかにしたい場合は、ここを修正する必要がある。


選択肢を辞書順にしたい場合は、「IF POS(code, base[n]) = 1 THEN sels[base[n]] = base[n]」にして、selsをソート指定にすればOK。


選択肢が一つの場合、POPUPMENUを出さないようにしても便利ですね。

雑感

入力補完はやっぱり嬉しい。
この調子で、上下カーソルでコマンド履歴を出すのも良さそうです。


あ、昔作ったインタープリターに入力補完をつけたくなったのです。
UWSCインタープリター - じゅんじゅんのきまぐれ
結構使っているので。