ちょっとNS Basicしない?


気づいた点などをボチボチと...

HPのTOPに戻る
Basic BASIC別館のTOPに戻る

現在の調査内容
<番外編、N700Cのバックボタンのヒ・ミ・ツ>
<ClieのJogダイヤル対応新たなる旅立ち1?>
<メモ帳の内容を読み出す>
<ClieのJogダイヤル対応その4解決編>
<少しでも速く...>
<ドット(点)描画について>
<ハードキーを使ったアプリを作る>
<ClieのJogダイヤル対応その3>
<日付選択を行う>
<時間選択を行う>
<昔懐かしの乱数発生>
<ClieのJOGダイヤルの対応その後>
<ClieのJOGダイヤルの対応>

<番外編、N700Cのバックボタンのヒ・ミ・ツ>ページのTOPへ

PEG-N700Cにはバックボタンというボタンが新たに作られました。
このボタンは便利でアプリからホームに戻ったり、
メモ帳等ではメモを見ている時に押すと、「終了」ボタンを自動的に押してメモ一覧に戻ったりと大活躍な凄いヤツです。

さて、この凄いバックボタンをNS Basicで扱おうとしたのですが、これは上手く行きません。
NS Basicの対応を待つしかないのか...
と思っていた時、あのRonDoを作ったAbbyさんの便利なHackアプリ「Jotsh!」のマニュアルに書いてあった事を思い出しました。

以下、マニュアルの抜粋です(abbyさん勝手に引用してしまってスイマセン)

バックボタンの実際の動作は以下のような優先順で決定されます。

ポップアップリストが表示されている → ポップアップリストをキャンセルします 

                ↓No   

"Cancel"、"キャンセル"(半角)、"Previous"、"取消"、"戻る"ボタンがある → 該当ボタンをタップするのと同じ動作となります 

                ↓No   

"No"、"いいえ"、"閉じる"、"Close"ボタンがある → 該当ボタンをタップするのと同じ動作となります 

                ↓No   

"Done"、"終了"ボタンがある → 該当ボタンをタップするのと同じ動作となります 

                ↓No   

"Yes"、"はい"、"OK"ボタンがある → 該当ボタンをタップするのと同じ動作となります 

                ↓No   

上記いずれにも該当しない → [ホーム]ボタンをタップするのと同じ動作となります 
そうです!
つまりNS Basicでアプリを作成する時は上記の条件に注意してアプリを作成すれば、簡単にバックボタン対応のアプリが作れるわけです。

注意する事は、そのアプリの最初の画面に上記に該当するボタンを押した事になるのでバックボタンを押しても、ホームには戻れなくなります。

これだけです。

abbyさんから、"取消"ボタンに対応しているのは「Jotsh!」のだけで、しろクリのバックボタンは"取消"ボタンには対応していないとの連絡を頂きました。
それからマニュアルからの引用の許可も頂けました。
abbyさん、ありがとうございます

<ClieのJogダイヤル対応新たなる旅立ち1?>ページのTOPへ

ClieのJogDialイベントの流れ(想像図(笑))


上のフローを見てもらえれば判りますがJogPress、JogUp、JogDownイベント以外は
全て、JogPressイベントの次に発生するイベントです。

つまり、JogPressにイベントを配置してしまうと、JogPressRepeat、JogPageUp、JogPageDown、JogReleseが発生する前に
必ず、発生JogPressイベントが発生してしまいます。

その為、ユーザーがJogDialを押し続けてもJogPressイベントが発生し、ユーザーが意図していないイベントが発生してしまいます。

解決する為には、JogPressイベントは「JogDialを押した判定には使わない」という方法があります。
それでは、どこでJogDialを押したという判定をするかというと、JogReleseイベントを使用します。
JogDialを押せば必ず離す動作が必要な訳で、ユーザーには違和感無く感じると思います。

JogPressイベントに処理を入れた時は、JogDialが押された瞬間
 JogReleseイベントに処理を入れた時には、JogDialが離された瞬間にイベントが発生します。

JogReleseイベントにJogDialを押した判定を入れる事で、JogPressRepeat、JogPageUp、JogPageDownイベント判定時に
JogDialが押されただけなのか、それともそれ以外のイベントなのかを気にしなくて良くなります。

※ちなみに、Clieの必須アプリのPowerJOGを利用しているとJogPressイベントのタイミングが遅れるようです。
 具体的にはJogDialを押した時には、JogPressイベントは発生せず、
 JogDialを押していたものを離した時にJogPressJogReleseイベントと順に発生するようです。

 その為、多くのユーザーが使っていると思われるPowerJOGとの親和性を高める事で、
 作者の意図しない動作を防ぐと共にユーザーに優しいアプリになるのではないでしょうか?

ここから先は、多くの推測が混じっています。取り扱いには注意して下さい(笑)

次にJogPageUp、JogPageDownですが、コレは、ユーザーにとっても作者にとっても難しいイベントでは無いでしょうか?
ユーザーはもたもた、押しまわしの操作を行うと、JogPressRepeatイベントが発生してしまいますし...
恐らくJogPressイベントからJogPressRepeatイベントまで1秒ないと思います。
そこで、JogPageUp、JogPageDownイベントの後にすぐにJogPressRepeatイベントが発生した場合に備えて
直前のイベントを覚えておいて、直前のイベントがJogPageUp、JogPageDownならば、JogPressRepeatイベントをキャンセルすればどうでしょう?
上手く行くのかも知れません。

おいらはユーザーに優しいアプリを作成するには押し回しで行う処理を作らないと考えています。
だって、おいらは押し回しが出来ないから...きっと他にもいるよね?
※新型ClieはJogDialが軽くなってもしかしたらやりやすくなっているかも...

この、JogPageUp、JogPageDownについては、又色々検証を行った後書いてみたいと思います。

<メモ帳の内容を読み出す>ページのTOPへ
なかよし掲示板に書いた内容そのままです(笑)

まずStartUpCodeに以下を記述

  Global DBmemo as Database
  Dim Res as Integer

  Res=DbOpen(DBmemo,"MemoDB",0)
  If Res<>0 Then
    Stop
  End If
次にフィールドオブジェクトと、ボタンオブジェクトをフォームに作って
ボタンオブジェクトのイベントに以下を記述

  Dim Res as Integer
  Dim txt as String

  Res=DBReadNext(DBmemo,txt)
  fld1005.text=txt
本当にメモ帳のデータを読むだけのプログラムなので
エラー処理もなにもしてません。あっDBのクローズもしてないですね(笑)

これでボタンを押す度に、メモ帳のデータを頭から読んでいって
フィールドに表示する事が出来ます。
※どうやら、メモ帳のデータを削除していたりするとデータ読み出しでエラーになるようです。
 一度HotSyncすればOKなようですが...

<ClieのJogダイヤル対応その4解決編>ページのTOPへ
なんと、NS Basic/Palm1.09がClieのJogダイヤルに対応しています!!!
やった〜てな感じです。
GetEventType
戻り値
イベントタイプ
1NsbKeyOrButtonキーまたはボタンが押された
2NsbPenDownペンダウンイベント
3NsbPenUpペンアップイベント
4NsbJogDialJogダイヤルイベント

GetKey
戻り値
ジョグダイヤルの操作
0ジョグダイヤルを時計周りに回した
1ジョグダイヤルを反時計回りに回した
2ジョグダイヤルを長押ししている
3ジョグダイヤルを押しながら時計周りに回した
4ジョグダイヤルを押しながら反時計周りに回した
5ジョグダイヤルを押した
6ジョグダイヤルを放した
サンプルプログラム

    Dim theKey as Integer
    
    If GetEventType()=4 Then
        theKey=asc(getkey())
        Select Case thekey
        Case 0
            lbl1007.text="JogUp"
        Case 1
            lbl1007.text="JogDown"
        Case 2
            lbl1007.text="JogPressRepeat"
        Case 3
            lbl1007.text="JogPageUp"
        Case 4
            lbl1007.text="JogPageDown"
        Case 5
            lbl1007.text="JogPress"
        Case 6
            lbl1007.text="JogRelese"
        End Select
    End If
という感じのようです。
ただし、ジョグの押し回しはちょっと考えないといけません
ジョグの押し回しをしている時に発生するイベントは
まず押し回しのイベントであるJogPageUp、JogPageDownのどちらかのイベントが発生します。
さらに、JogPressRepeatのイベントも発生しています。
これを上手く解決してあげる必要があるようです。

※ただし、Clieでは必須のアプリとも言えるPowerJogがJogPressRepeatのイベントの時に起動するので
一般のアプリでは、JogPressRepeatイベントを使わない方がユーザーにやさしいかも知れませんね。
それにJogPageUp、JogPageDownのイベントって使いづらいですよね?
自分は押しまわしって出来ないですし...

<少しでも速く...>ページのTOPへ
まぁ、基本といえば基本なんですが、プログラム中の処理を少しでも速くする方法です。
結論から先に言ってしまうと、なるべくCPUには負荷をかけない方が良い。
本当に当たり前ですね(笑)

そこでこんなサンプルを...
サンプル1サンプル2サンプル3
dim ct as integer
dim dt as integer
dim i  as integer
dim j  as integer
   
j=0
ct=sysinfo(1)
for i=1 to 200
    dt=int(rand()*5)+1
    if str(dt)="1" then
        j=j+1
    end if
    if str(dt)="2" then
        j=j+1
    end if
    if str(dt)="3" then
        j=j+1
    end if
    if str(dt)="4" then
        j=j+1
    end if
    if str(dt)="5" then
        j=j+1
    end if
next
ct=sysinfo(1)-ct
msgbox str(ct)
dim ct as integer
dim dt as integer
dim i as integer
dim j as integer
dim dts as string
    
j=0
ct=sysinfo(1)
for i=1 to 200
    dt=int(rand()*5)+1
    dts=str(dt)
    if dts="1" then
        j=j+1
    end if
    if dts="2" then
        j=j+1
    end if
    if dts="3" then
        j=j+1
    end if
    if dts="4" then
        j=j+1
    end if
    if dts="5" then
        j=j+1
    end if
next
ct=sysinfo(1)-ct
msgbox str(ct)
dim ct as integer
dim dt as string
dim i as integer
dim j as integer
    
j=0
ct=sysinfo(1)
for i=1 to 200
    dt=str(int(rand()*5)+1)
    if dt="1" then
        j=j+1
    end if
    if dt="2" then
        j=j+1
    end if
    if dt="3" then
        j=j+1
    end if
    if dt="4" then
        j=j+1
    end if
    if dt="5" then
        j=j+1
    end if
next
ct=sysinfo(1)-ct
msgbox str(ct)
測定1回目3533Ticks測定1回目1362Ticks測定1回目1305Ticks
測定2回目3500Ticks測定2回目1358Ticks測定2回目1304Ticks
測定3回目3503Ticks測定3回目1358Ticks測定3回目1307Ticks
測定4回目3503Ticks測定4回目1358Ticks測定4回目1307Ticks
測定5回目3503Ticks測定5回目1359Ticks測定5回目1308Ticks
内容はFor〜Next内で乱数を発生させ、その乱数をIF文で判断して行くというものです。
※乱数をStr型にする必要があると仮定します。
わざとIF文をつなげています。

まずサンプル1ですが、乱数を発生させた値をInt型のdt変数に格納します。
その後のIF文の判定の所でStr型に直して判定しています。
この場合、IF文の判定の度にInt型dt変数をStr型に変換する処理が入ってしまい処理スピードが遅くなってしまうようです。
現に、この3つのサンプルの中では一番遅いです。

次にサンプル2ですが、乱数を発生させた後Str型に変換してその後は、Str型の変数dtsを使ってIF文の判定を行っています。
サンプル1に比べてIF文内での変数の型変換が行われない為、かなり速くなりました。
サンプル1では、For〜Nextの1ループ中に変数の型変換が5回行われましたが、
サンプル2では、For〜Nextの1ループ中に変数の型変換が1回しか行われない為です。

最後にサンプル3ですが、乱数を発生させる式の所でdtにStr型で乱数を格納しています。
その為か、3つのサンプルの中では一番速い結果が出ました。

※Ticksについて  マニュアルを見るとクロックが時を刻んだ数となっています。
 ちなみにClieのPOSE上での1秒間の刻み数は100と出ました。(こんなに区切りが良い数で良いのでしょうか?)

<ドット(点)描画について>ページのTOPへ
NS Basic/Palmでは点を打つという命令はありません(よね?)

そこで普通、考えるのは、DrawLine命令を使う方法ですね。
例えば、スクリーンの(10,10)にドットを描画する時は、
DrawLine 10,10,10,10
とコーディングすればスクリーンにドットが描画されますね。

またこんな方法もあります。
1ドットのビットマップを作って、それを描画する方法です。
コーディングは
DrawBitmap 1010,10,10
となります。※1010は表示したいビットマップのIDです。

当然、実行結果は上記のDrawLineと同じです。

まぁ、結果だけみれば同じですし、ビットマップのサイズの分後者の方がサイズも大きくなってしまいますね。
当然、後者の方が不利なんですが、描画スピードはどうなんでしょう?

早速、両方を2000回スクリーンに描画させてみてその結果を調べてみました。
 1回目2回目3回目4回目5回目
DrawLine命令7秒8秒8秒7秒8秒
DrawBitmap命令4秒4秒4秒4秒4秒

この結果を見る限り、ビットマップを表示する方が倍くらい速いって事ですね。
つまり、スピードを重視しない場合(一度描画したら描画し直さない場合等)は
プログラムサイズの為にも、DrawLineでコーディングした方が良い。

ゲームのような、スピードを重視する場合、DrawBitmapを使った方が良い。という結果になるようです。

でも、よく考えたら、ドットを描画する場合ってそんなに無いですよね(笑)

最新のNS Basic2.05で試したらDrawLineで点を描画した方が速かったです。
なんか仕様が変わったのでしょうか?

<ハードキーを使ったアプリを作る>ページのTOPへ
よくゲームなどでハードキーを使ったものがありますね。
でも、NS Basic/PalmでGetkey()でキーの情報を取得してもボタンに登録してある、アプリが起動してしまいます。
その対応策です。
※殆ど内容は<ClieのJOGダイヤルの対応その後>の内容ですが...

とりあえず、スケジュールボタン、アドレスボタン、ToDoボタン、メモ帳ボタンを使った場合のプログラムです。
フォームにコーディングするコードは以下のようになります。
さらに、キー内容を表示する為にラベルを1つ付けています。
01    Dim theKey as integer
    
02    if GetEventType()=1 then
03        theKey=asc(getkey())
04        if theKey>0 and theKey<5 then
05            SetEventHandled
06            select case thekey
07            case 1
08                lbl1007.text="Btn01"
09            case 2
10                lbl1007.text="Btn02"
11            case 3
12                lbl1007.text="Btn03"
13            case 4
14                lbl1007.text="Btn04"
15            end select
16        end if
17    end if

まず、1行目のDim文でキー情報を格納する、変数をInteger型で定義します。
2行目のGetEventTypeでハードキー、又はシルクスクリーン上のボタンが押されたかを判定します。
3行目でGetkeyで所得したキー情報をアスキーコードに変換して、1行目で定義したtheKey変数に格納します。
4行目でtheKeyの内容を判定します。1〜4の場合がそれぞれ、4つのハードボタンを押した時の戻り値になります。
それ以外の時は、そのままキーに設定してある機能が有効になります。
5行目のSetEventHandled命令で決められたハードキーが押された時に、そのキーに割り当てられた機能をキャンセルします。
6行目〜15行目で、4つのハードキーが押された時のそれぞれの処理をコーディングします。

この処理で注意しなければいけないのは、5行目のSetEventHandled命令ですね。
これを、何気なく使ってしまうと大変な事になります(ソフトリセットするしかないとか)
例えば、上記プログラムの2行目と3行目の間にSetEventHandledを書き込むと、
全てのハードキーのイベントがキャンセルされてしまい、プログラムが終了出来ないだけでなく、電源ボタンも効かなくなってしまいます。
使う場所には注意しましょう。

<ClieのJogダイヤル対応その3>ページのTOPへ

サポートの方からメールが来ました。
結果は、現状ではやはり
JOGダイヤルのリターンコードと、通常のキーのリターンコードが、
同じコードで返って来てしまい、それらを見分ける方法が見つからない。
そして早急な対応策は、考えられないという残念な結果でした。

しかし、さらに調査を続けて何か対応策が見つかりしだい、連絡をして頂ける事になりました。

そこで、自分も、もう少し調べてみようかと思っていますので、進展がありましたらまたHP上で報告いたします。

皆さんも、何か判りましたらどんな些細な情報でも結構ですので連絡お願いします。
1.08からのAPIで何か出来ないかと考えていますので、そこら辺から攻めて見ます。
しかし、英文なんですよね...

でも、せめてJOGダイヤルで誤動作が起きないぐらいには出来ないと
Clieでは、JOGダイヤルに触っちゃいけないアプリ(笑)しか出来ないんで頑張ります(頑張りたいです)

<日付選択を行う>ページのTOPへ

dim Res as integer
dim TheDate as date
    
    TheDate=today()
    Res=PopUpDate(TheDate,"日付を選択して下さい")
    if Res=1 then
	Msgbox str(TheDate)
    else
    	msgbox "日付は選択されませんでした"
    end if
上記のようなコーディングで
よく見かける日付を選択する画面を表示出来ます。

TheDateに選択した日付が入ります。

戻り値Resは
1 − 日付がユーザーによって選択された。
0 − 日付が選択されなかった。

気を付ける事は、PopUpDateで画面を呼び出す前に必ず
TheDate変数に日付を入れておかなければいけないようです。

※上記リストではToday()命令を使って現在の日付を入れています。

※マニュアルには、OS3.5が必要とあるのですが、WorkPad30JのROMのエミュレータで動きました?

<時間選択を行う>ページのTOPへ

dim Res as integer
dim StartTime as Time
dim EndTime as time
    
    Res=PopUpTime(StartTime,EndTime,"時間を選択して下さい")
    if Res=1 then
        if str(StartTime)="**:55:00" then
            Msgbox "時間指定なし"
        else
	        Msgbox str(StartTime) + ":" + str(EndTime)
        end if
    else
    	Msgbox "時間は選択されませんでした"
    end if
上記のようなコーディングで
よく見かける時間を選択する画面を表示出来ます。

StartTimeに開始時間が、EndTimeに終了時間がそれぞれ入ります。

戻り値Resは
1 − 時間がユーザーによって選択された。
0 − 時間が選択されなかった。

if str(StartTime)="**:55:00" then
の行はユーザーが指定なしでOKした場合です。
つまり指定なしの場合には、StartTime変数に(EndTime変数もですが)"**:55:00"が入ります。

※マニュアルには、OS3.5が必要とあるのですが、WorkPad30JのROMのエミュレータで動きました?

<昔懐かしの乱数発生>ページのTOPへ
昔、Basicをかじった頃、数当てゲームなんかを作ってました。
こういったものを作る時に必ず必要になるのが、乱数ですね。

マニュアルを見るとありました。
Rand命令がそうですね。
でもあのRandomize命令がマニュアルに載っていません。
昔のBasic(VisualBasicも)は
Randmize Timer とかやってましたよね?
必要ないのかな?と思い昔の記憶を頼りに
lbl1006.text=str(int(rand()*6)+1)
とやって見ました
これでおそらく1〜6のランダムな整数値が求められるハズです。
エミュレータに通して見ると一応OKなようです。
NS Basic/PalmではRandmize命令を使わなくてもきちんとした乱数が発生出来るようです。

<ClieのJOGダイヤルの対応その後>ページのTOPへ
sub Screen1004_events()
    lbl1005.text=str(geteventtype())
    lbl1006.text=str(asc(getkey()))
    seteventhandled
end sub
※上記のプログラムをPalm本体で起動すると、全てのボタンのイベントをキャンセルしてしまうので、
ソフトリセット以外に復旧の方法がありません、注意して下さい。

※そんなに簡単には行きませんでした。

上記プログラムでリターンコードを調べて見ると
JOGダイヤルのリターンコードと、その他標準のハードキー等のリターンコードが同一であるという問題があるようです。
上手くJOGダイヤルからのリターンコードだと判別出来ればseteventhandled命令でキャンセル出来るんですが...
GetKeyのリターンコード
※アスキーコードにしたもの
ハードキー等の機能JOGの機能
0-JOGを時計回りに回した
1予定表ボタンJOGを反時計回りに回した
2アドレス帳ボタンJOGを押し続け
3ToDoボタンJOGを押しながら時計回りに回した
4メモ帳ボタンJOGを押しながら反時計回りに回した
5メニューボタンJOGを押した
6ホームボタンJOGを離した
7検索ボタン-
8Calcボタン-
11上ボタン-
12下ボタン-

<ClieのJOGダイヤルの対応>ページのTOPへ
sub Screen1004_events()
    if GetEventType() = nsbkeyorbutton then
        select case asc(getkey())
        case 0
            lbl1009.text="JoGUp"
        case 1
            lbl1009.text="JoGDown"
        case 2
            lbl1009.text="JogPressRepeat"
        case 3
            lbl1009.text="JogPageUp"
        case 4
            lbl1009.text="JogPageDown"
        case 5
            lbl1009.text="JogPress"
        case 6
            lbl1009.text="JogRelese"
        end select
    end if
end sub
※SONYから提供されているJOGダイヤルのリファイレンスを見て
自分なりに解釈したものなので、内容には自信なしです。(一応動くようですが...)

JOGのイベントは
Graffiti文字を入力したとき、
画面下部のボタンを押したとき、
アイコンエリアのアイコン(『検索』アイコン等)をタップした時
の拡張イベントとして認識されるそうです。
そこで

if GetEventType() = nsbkeyorbutton then

でNS Basic上でイベントを認識します。
その後
Select文でGetkey()関数の戻り値によってジョグの状態を認識します。
GetKey()関数の戻り値をAsc関数でキャラクタコードに変換しています。

戻り値
0-ジョグダイヤルを時計周りに回した。
1-ジョグダイヤルを反時計周りに回した。
2-ジョグダイヤルを長押ししている。
3-ジョグダイヤルを押しながら時計周りに回した。
4-ジョグダイヤルを押しながら反時計周りに回した。
5-ジョグダイヤルを押した。
6-ジョグダイヤルを放した。

という感じのようです。どうでしょう?あってます?(笑)

※PowerJOGについて
とても便利なPowerJOGですが、PowerJOGが有効になっていると
JOGを押したイベントが認識出来ないようです。
多分、PowerJOGがそのイベントを受け取ってしまうからでしょうか?

まぁ、基本はJOGを放したイベントで普通は押した時の処理をするようなので問題無しでしょうか?

- Page End -