|
|
2013/12/13(Fri) 15:42:04|NO.58706
現在コマンドプロンプト風のものを作っているのですがなかなかうまくいきません。
onkyeサンプルプログラムにある
onkey *jump
stop
*jump
pos xvalue, 0
mes strf("%c", iparam)
xvalue += ginfo(14)
stop
このプログラムを応用しようとして、いろいろ試行錯誤しましたがBackspaceを用いての文字の消去や打ち込んだ文字列の取得がうまく思いつきません。
テキストボックスなどを使えばそのあたりは簡単なんでしょうが、自分で入力した文字列以外(初期表示されている文字)を消されないようにしたいのでonkey以外の方法で
コマンドプロンプト風のものが作れないでしょうか?
まとめると
・自分で文字列の打ち込みができる
・打ち込まれた文字列を取得できる
・初期表示されている文字列は消すことができない
このようなプログラムにするためにはなにかいい案ありませんでしょうか?
|
|
2013/12/13(Fri) 16:56:12|NO.58708
消したくない文字は別機構で表示し、文字列取得時に連結するのが手っ取り早いです
入力は普通にinputを使ってはどうでしょう?
入力機構を自分で用意するのはとても面倒です(IMEを取得したり、キャレットを移動したり...etc)
|
|
2013/12/13(Fri) 17:49:36|NO.58709
くまねこさんのやりたいことを実現するには、何はともあれ、
「今、何が表示されているのか」という情報を保持する
こと。これが根っこになりますね。mesで表示しっぱなしでは、「以前何を打ったか?。今カーソルはどこか?」
等々、いろんな情報が失われてしまいます。全部保持して、初めて適切な動きができます。
下は、穴ぼこだらけのカスいサンプルですが、エッセンスは詰まっていると思います。
参考になれば幸いです。
*start1 ;初期設定
color_text(0) = 255,255,255
color_back(0) = 0,0,0
BufSize_TEXT_CONSOLE_ORG = 10000 ;コンソール文字列の保持サイズ。デフォで10KB
sdim TEXT_CONSOLE_ORG,BufSize_TEXT_CONSOLE_ORG ;コンソール文字列のオリジナルを保持する変数
STR_CMDPRMPT = dir_cur + ">" ;コマンドプロンプト(文字列)
TEXT_CONSOLE_ORG = STR_CMDPRMPT ;コマンドプロンプト表示
TEXT_CONSOLE = TEXT_CONSOLE_ORG ;「TEXT_CONSOLE_ORG = dir_cur」の影武者。都合に応じて改変が入る。
index_line_cursor = 0 ;カーソルの存在する行インデックス
index_char_TheLine_cursor = strlen(TEXT_CONSOLE) ;カーソルの存在する行(以下、「カーソルカレント行」「CC行」と呼びます。)におけるカーソルの文字インデックス。
interval_blink_cursor = 150 ;カーソルの点滅周期〔ms〕
stat_cursor_blink = 0 ;カーソルの状態(0,1)=(滅,点)
FontName_console = msgothic : FontSize_console = 14 : Param_font = 0 ;フォント設定
pos_start_TEXT_CONSOLE(0) = 0,0 ;文字列の描画開始位置
*start2 ;GUI作成
size_scr(0) = 600,400
screen 0,size_scr(0),size_scr(1),0,2
title dir_cur
onkey gosub *EVENT_KEY
font FontName_console,FontSize_console,Param_font
*start3 ;環境適応
*main
timer_300ms = 0 ;300msカウンタ
repeat
;< カーソルの点滅処理 >
if timer_300ms >= interval_blink_cursor {
gosub *Control_CursorBlink
timer_300ms = 0 ;カウンタリセット
}
timer_300ms += 50 ;時間経過
await 50 ;周期50ヘルツ
loop
stop
*EVENT_KEY ;キー入力対応ルーチン
getkey KEY_ENTER,13
if KEY_ENTER = 1 { ;ENTER処理
gosub *DealCommand
return
}
flg_OnKey_alphabet = 0
repeat 26,'A' ;アルファベット26文字取得
getkey key,cnt
if key = 1 : flg_OnKey_alphabet = 1 : Code_char_Alphabet = cnt : break ;A〜Zどれか押されていたら...
loop
getkey key_SHIFT,16
getkey key_BS,8
getkey key_SPACE,32
flg_Onkey_numeric = 0
repeat 10,48 ;0〜9(メインキーボード)
getkey key,cnt
if key = 1 : flg_Onkey_numeric = 1 : num_char_numeric = cnt-48 : break
loop
repeat 10,96 ;0〜9(テンキー)
getkey key,cnt
if key = 1 : flg_Onkey_numeric = 1 : num_char_numeric = cnt-96 : break
loop
if flg_OnKey_alphabet = 1 { ;アルファベットキー
if key_SHIFT = 1 { ;大文字
poke TEXT_CONSOLE_ORG,strlen(TEXT_CONSOLE_ORG),Code_char_Alphabet
} else { ;小文字
poke TEXT_CONSOLE_ORG,strlen(TEXT_CONSOLE_ORG),Code_char_Alphabet + 32 ;※因みに、小文字のSJISコードは大文字のそれ +32 である。
}
index_char_TheLine_cursor ++ ;カーソルインデックス更新
}
if (key_BS = 1)&(index_char_TheLine_cursor > strlen(STR_CMDPRMPT)) { ;BSキーが押されていて、かつ、文字を消す余裕がある場合
poke TEXT_CONSOLE_ORG,strlen(TEXT_CONSOLE_ORG)-1,0 : index_char_TheLine_cursor -- ;一文字消去
}
if key_SPACE = 1 { ;スペースキー
TEXT_CONSOLE_ORG += " "
index_char_TheLine_cursor ++
}
if flg_Onkey_numeric = 1 { ;0〜9
TEXT_CONSOLE_ORG += str(num_char_numeric)
index_char_TheLine_cursor ++
}
TEXT_CONSOLE = TEXT_CONSOLE_ORG
redraw 0 : gosub *DrawRoutine : redraw 1 ;画面更新
wait 20 ;ちょっと待つ(∵暴走防止)
return
*Control_CursorBlink ;カーソル点滅管理ルーチン
if stat_cursor_blink = 0 { ;「滅」の場合
TEXT_CONSOLE = TEXT_CONSOLE_ORG + "_"
stat_cursor_blink = 1
} else { ;「点」の場合
TEXT_CONSOLE = TEXT_CONSOLE_ORG
stat_cursor_blink = 0
}
redraw 0 : gosub *DrawRoutine : redraw 1 ;画面更新
return
*DrawRoutine ;描画ルーチン
color color_back(0),color_back(1),color_back(2) : boxf
color color_text(0),color_text(1),color_text(2)
pos pos_start_TEXT_CONSOLE(0),pos_start_TEXT_CONSOLE(1) : mes TEXT_CONSOLE
return
*DealCommand ;コマンド処理ルーチン
;< 解釈 >
notesel TEXT_CONSOLE_ORG : noteget TheLine,index_line_cursor ;CC行読み出し
STR_INPUT_USER = strmid(TheLine,-1,strlen(TheLine)-strlen(STR_CMDPRMPT)) ;ユーザー入力取得
repeat 1
if STR_INPUT_USER = "exit" : end
if STR_INPUT_USER = "notepad" : exec STR_INPUT_USER : num_line_responce = 0 : break
TEXT_CONSOLE_ORG += "\n不明なコマンドです。" : num_line_responce = 1
loop
STR_CMDPRMPT = dir_cur + ">"
TEXT_CONSOLE_ORG += "\n\n" + STR_CMDPRMPT
TEXT_CONSOLE = TEXT_CONSOLE_ORG
index_line_cursor += num_line_responce+2 : index_char_TheLine_cursor = strlen(STR_CMDPRMPT) ;カーソルインデックス更新
redraw 0 : gosub *DrawRoutine : redraw 1 ;画面更新
;< 文字のスクロール >
if ginfo_cy > size_scr(1) : pos_start_TEXT_CONSOLE(1) -= ginfo_cy - size_scr(1)
return
| |
|
2013/12/14(Sat) 17:13:58|NO.58733
みなさま回答ありがとうございます。
FunnyMakerさんのプログラム拝見させていただきました。
質問のばかりで申し訳ないのですが、例えばコマンドプロンプトは初期表示の"Microsoft Windows〜"のような
初期表示がありますよね?
そのような初期表示を入れたくFunnyMakerさんのプログラムとにらめっこしていたのですがうまくいきません。
描画ルーチンのところで、coloerやboxfで一旦画面が塗りつぶされてしまっているためその前に記述することはできませんし、
その下に記述すると毎回でできてしまいます。
そこでカウントを入れるように改良もしたのですが、コマンドを入力しEnterを押すと消えてしまいました。
何かいいアイデアないでしょうか?
|
|
2013/12/14(Sat) 21:26:26|NO.58734
起動時のセットアップで組み込めばいいとおもいます。
↓ちょっとだけ改良したやつです。
*start1 ;初期設定
color_text(0) = 255,255,255
color_back(0) = 0,0,0
BufSize_TEXT_CONSOLE_ORG = 10000 ;コンソール文字列の保持サイズ。デフォで10KB
sdim TEXT_CONSOLE_ORG,BufSize_TEXT_CONSOLE_ORG ;コンソール文字列のオリジナルを保持する変数
STR_BootMessage = "Funny Terminal Emulator [Ver 1.1]\nby FunnyMaker" ;起動メッセージ
STR_CMDPRMPT = dir_cur + ">" ;コマンドプロンプト(文字列)
TEXT_CONSOLE_ORG += STR_BootMessage + "\n" + STR_CMDPRMPT ;コンソールの表示内容の初期化
TEXT_CONSOLE = TEXT_CONSOLE_ORG ;「TEXT_CONSOLE_ORG = dir_cur」の影武者。都合に応じて改変が入る。
notesel TEXT_CONSOLE_ORG : index_line_cursor = notemax - 1 ;カーソルの存在する行インデックス
index_char_TheLine_cursor = strlen(TEXT_CONSOLE) ;カーソルの存在する行(以下、「カーソルカレント行」「CC行」と呼びます。)におけるカーソルの文字インデックス。
interval_blink_cursor = 150 ;カーソルの点滅周期〔ms〕
stat_cursor_blink = 0 ;カーソルの状態(0,1)=(滅,点)
FontName_console = msgothic : FontSize_console = 14 : Param_font = 0 ;フォント設定
pos_start_TEXT_CONSOLE(0) = 0,0 ;文字列の描画開始位置
*start2 ;GUI作成
size_scr(0) = 600,400
screen 0,size_scr(0),size_scr(1),0,2
title dir_cur
onkey gosub *EVENT_KEY
font FontName_console,FontSize_console,Param_font
*start3 ;環境適応
*main
timer_300ms = 0 ;300msカウンタ
repeat
;< カーソルの点滅処理 >
if timer_300ms >= interval_blink_cursor {
gosub *Control_CursorBlink
timer_300ms = 0 ;カウンタリセット
}
timer_300ms += 50 ;時間経過
await 50 ;周期50ヘルツ
loop
stop
*EVENT_KEY ;キー入力対応ルーチン
getkey KEY_ENTER,13
if KEY_ENTER = 1 { ;ENTER処理
gosub *DealCommand
return
}
flg_OnKey_alphabet = 0
repeat 26,'A' ;アルファベット26文字取得
getkey key,cnt
if key = 1 : flg_OnKey_alphabet = 1 : Code_char_Alphabet = cnt : break ;A〜Zどれか押されていたら...
loop
getkey key_SHIFT,16
getkey key_BS,8
getkey key_SPACE,32
flg_Onkey_numeric = 0
repeat 10,48 ;0〜9(メインキーボード)
getkey key,cnt
if key = 1 : flg_Onkey_numeric = 1 : num_char_numeric = cnt-48 : break
loop
repeat 10,96 ;0〜9(テンキー)
getkey key,cnt
if key = 1 : flg_Onkey_numeric = 1 : num_char_numeric = cnt-96 : break
loop
if iparam = 46 : flg_Onkey_46 = 1 : else : flg_Onkey_46 = 0 ;「.」キー
if flg_OnKey_alphabet = 1 { ;アルファベットキー
if key_SHIFT = 1 { ;大文字
poke TEXT_CONSOLE_ORG,strlen(TEXT_CONSOLE_ORG),Code_char_Alphabet
} else { ;小文字
poke TEXT_CONSOLE_ORG,strlen(TEXT_CONSOLE_ORG),Code_char_Alphabet + 32 ;※因みに、小文字のSJISコードは大文字のそれ +32 である。
}
index_char_TheLine_cursor ++ ;カーソルインデックス更新
}
if (key_BS = 1)&(index_char_TheLine_cursor > strlen(STR_CMDPRMPT)) { ;BSキーが押されていて、かつ、文字を消す余裕がある場合
poke TEXT_CONSOLE_ORG,strlen(TEXT_CONSOLE_ORG)-1,0 : index_char_TheLine_cursor -- ;一文字消去
}
if key_SPACE = 1 { ;スペースキー
TEXT_CONSOLE_ORG += " "
index_char_TheLine_cursor ++
}
if flg_Onkey_numeric = 1 { ;0〜9
TEXT_CONSOLE_ORG += str(num_char_numeric)
index_char_TheLine_cursor ++
}
if flg_Onkey_46 = 1 { ;「.」キー
if key_SHIFT = 1 {;「>」
TEXT_CONSOLE_ORG += ">"
} else {;「.」
TEXT_CONSOLE_ORG += "."
}
index_char_TheLine_cursor ++
}
TEXT_CONSOLE = TEXT_CONSOLE_ORG
redraw 0 : gosub *DrawRoutine : redraw 1 ;画面更新
wait 20 ;ちょっと待つ(∵暴走防止)
return
*Control_CursorBlink ;カーソル点滅管理ルーチン
if stat_cursor_blink = 0 { ;「滅」の場合
TEXT_CONSOLE = TEXT_CONSOLE_ORG + "_"
stat_cursor_blink = 1
} else { ;「点」の場合
TEXT_CONSOLE = TEXT_CONSOLE_ORG
stat_cursor_blink = 0
}
redraw 0 : gosub *DrawRoutine : redraw 1 ;画面更新
return
*DrawRoutine ;描画ルーチン
color color_back(0),color_back(1),color_back(2) : boxf
color color_text(0),color_text(1),color_text(2)
pos pos_start_TEXT_CONSOLE(0),pos_start_TEXT_CONSOLE(1) : mes TEXT_CONSOLE
return
*DealCommand ;コマンド処理ルーチン
;< 解釈 >
notesel TEXT_CONSOLE_ORG : noteget TheLine,index_line_cursor ;CC行読み出し
STR_INPUT_USER = strmid(TheLine,-1,strlen(TheLine)-strlen(STR_CMDPRMPT)) ;ユーザー入力取得
;「num_line_responce」変数にはレスポンスに費やした行数を保存。
repeat 1
if STR_INPUT_USER = "exit" : end
if STR_INPUT_USER = "cls" { ;CLSコマンド
sdim TEXT_CONSOLE_ORG,BufSize_TEXT_CONSOLE_ORG
index_line_cursor = 0 ;カーソルインデックス更新
pos_start_TEXT_CONSOLE(1) = 0
num_line_responce = 0
break
}
if STR_INPUT_USER = "ver" {
TEXT_CONSOLE_ORG += "\nFunny Terminal Emulator [Ver 1.1]"
num_line_responce = 1
break
}
;< カレントディレクトリ内のアプリケーション起動またはファイルオープンのトライ >
exist STR_INPUT_USER
if strsize ! -1 {
exec STR_INPUT_USER,16
num_line_responce = 0
break
}
;< Windowsシステムディレクトリ内のアプリケーション起動のトライ >
str1 = dir_sys+"/"+getpath(STR_INPUT_USER,1)+".exe"
exist str1
if strsize ! -1 {
exec str1
num_line_responce = 0
break
}
;< ここまで来てしまった場合 >
TEXT_CONSOLE_ORG += "\n不明なコマンドです。" : num_line_responce = 1
loop
STR_CMDPRMPT = dir_cur + ">"
TEXT_CONSOLE_ORG += "\n\n" + STR_CMDPRMPT ;基本的に2回改行。
TEXT_CONSOLE = TEXT_CONSOLE_ORG
index_line_cursor += num_line_responce+2 : index_char_TheLine_cursor = strlen(STR_CMDPRMPT) ;カーソルインデックス更新
redraw 0 : gosub *DrawRoutine : redraw 1 ;画面更新
;< CC行が最下辺まできてしまった際の文字のスクロール >
if ginfo_cy > size_scr(1) : pos_start_TEXT_CONSOLE(1) -= ginfo_cy - size_scr(1)
redraw 0 : gosub *DrawRoutine : redraw 1 ;画面更新
return
いっちょまえのターミナルエミュレータとしては、上のものはまだまだ不十分な箇所が大量にあります。
(’’さんが上で仰るように、IMEを取得して日本語入力にも対応するべきですし、
自動改行、スクロール、マウスカーソルによる文字列の選択&コピー、貼り付け等の各種操作、
各種基本コマンドの実装、コマンドラインアプリケーションとのやりとり、
等々.......
気が遠くなるほど多くの機能のサポートが必要です。
しかしそこがプログラミングの醍醐味とも言えるでしょうから、(※趣味でやるなら)やってみると面白いかもしれませんね。
| |
|
2013/12/14(Sat) 23:05:19|NO.58736
野暮用でテキストエディタを組んでいるので何かしら助力ができるやも・・・。
文字を打つのであればWM_CHAR(0x0102)を捕まえる方が楽に行けるかもしれません。
この場合特に制御することなくIMEによる全角入力が可能です・・・が、
IMEの表示位置の指定をしないと見栄えが非常に悪い。(下記のソースでは悪いまま)
また、全角を入力可能にすると全角2バイトの間にカーソルが行かないような配慮が増えてきます。
WM_CHARとWM_KEYDOWN(onkey)のどちらで動作を指示するべきなのかは適当にテストしてみるといいかと。
以下テストソース(約150行)になります。横長な行があります(どうにかならんのか)。
#define global WM_CHAR 0x0102
#const global FONTSIZE 16
#const global WINDOWSIZEX 640
#const global WINDOWSIZEY 480
#const global LINETEXTPOSY WINDOWSIZEY-FONTSIZE
#define global CONST
#module
dim seekpos // #cmpopt varinit 1 対策と使用変数の宣言。なくて問題ない。
#defcfunc InvalidCursorPos int cpos,CONST var string
// 第一パラメータ(cpos):シークポイント(バイト単位)
// 第二パラメータ(string):シーク検査する文字列
//
// 関数はstringの、cposバイト目にカーソルが挿入不能であればTRUEが返る。
// 具体的に挿入不能であるとは、マルチバイト文字の間である状態を指す。
//
// cposが負の値の場合や、
// cposがstrlen(string)を超えている場合、正しい挙動をしない上に後者はエラーになりうる。
seekpos = 0
repeat
if cpos <= seekpos : break
strcode = peek(string,seekpos)
if ( strcode >= 0x81 && strcode <= 0x9F ) : seekpos ++
if ( strcode >= 0xE0 && strcode <= 0xFC ) : seekpos ++
seekpos ++
loop
return cpos < seekpos
#global
cls 4
oncmd gosub *typechar,WM_CHAR
onkey gosub *hitkey
// font msgothic,FONTSIZE
font "MS Pゴシック",FONTSIZE
gosub *init
nowstring = "*** LineText Test ***"
gosub *putstring
gosub *resettext
repeat
redraw 0
gosub *draw
redraw 1
wait 1
loop
*init
// デフォルト文字列の指定
defaultstring = "test>"
defaultstringlen = strlen(defaultstring)
// 表示を行送りで流用しているための苦肉のフラグ。
cursordrawflag = 1
return
*resettext
// デフォルトの文字を入れてカーソル位置をデフォルト文字の末端に設定する
nowstring = defaultstring
cursorpos = defaultstringlen
return
*seekleft
// カーソル位置(cursorpos)を左に一文字ずらす
if ( cursorpos <= defaultstringlen ) : return
cursorpos --
if ( InvalidCursorPos(cursorpos,nowstring) ){
cursorpos --
}
return
*seekright
// カーソル位置(cursorpos)を右に一文字ずらす
if ( cursorpos >= strlen(nowstring) ) : return
cursorpos ++
if InvalidCursorPos(cursorpos,nowstring){
cursorpos ++
}
return
*typechar
// 文字入力処理。
// logmes strf("CHAR: %X",wparam)
if wparam == 0x7F || wparam == 0x08 {
// バックスペースの処理
cursorpostemp = cursorpos
gosub *seekleft
nowstring = strmid(nowstring,0,cursorpos)+strmid(nowstring,cursorpostemp,strlen(nowstring))
}else : if wparam == 0x0D {
// RETURNの処理
gosub *putstring
gosub *operate
gosub *resettext
}else : if wparam >= 0x20 {
// それ以外の非コントロール文字は挿入する
nowstring = strmid(nowstring,0,cursorpos)+strf("%c",wparam)+strmid(nowstring,cursorpos,strlen(nowstring))
cursorpos ++
}
return
*hitkey
// 文字以外の入力キー処理
// logmes strf("KEY : %X",wparam)
// DEL , LEFT , RIGHT の処理
if wparam == 0x25 {
// [←]
gosub *seekleft
}else : if wparam == 0x27 {
// [→]
gosub *seekright
}else : if wparam == 0x2E {
// DELETEキー
cursorpostemp = cursorpos
gosub *seekright
nowstring = strmid(nowstring,0,cursorpostemp)+strmid(nowstring,cursorpos,strlen(nowstring))
cursorpos = cursorpostemp
}
return
*draw
color
boxf ,LINETEXTPOSY
color 255,255,255
if ( gettime(7)<500 )&&( cursordrawflag ){
pos 0,LINETEXTPOSY
mes strmid(nowstring,0,cursorpos)
line ginfo_mesx,LINETEXTPOSY+1,ginfo_mesx,WINDOWSIZEY-2
}
pos 0,LINETEXTPOSY
mes nowstring
return
*putstring
// nowstringに入っているものを描画し行を送る
cursordrawflag = 0
gosub *draw
cursordrawflag = 1
pos 0,0
gcopy 0,0,FONTSIZE,WINDOWSIZEX,WINDOWSIZEY
return
*operate
//実際の処理?
// 文字列はnowstringに入っているが、デフォルト文字列を伴って入っている。
// operateの動作前に、打った文字はputstringによって描画確定している。
// 必要によってnowstringの値を書き換えputstringを呼べば何かしらの文字を出力できる。
stringtemp = strmid(nowstring,defaultstringlen,strlen(nowstring))
nowstring = strf({"You typed "%s"."},stringtemp)
gosub *putstring
nowstring = ""
gosub *putstring
defaultstring = stringtemp+">"
defaultstringlen = strlen(defaultstring)
return
自己流の適当コーディングなので読みづらい部分が多いかと思いますが参考になれば幸いです。
見栄えがFunnyMakerさんと全然違う・・・。
FunnyMakerさんのコメントはこちらにも言えて不十分な部分は多いですねえ。
| |
|