トップページ > 記事閲覧
キー入力した後にエンターを押しても再びキー入力できるようにしたい。
名前:マーク42 日時: 2020/06/17 18:43

キー入力した後にエンターを押しても再びキー入力できるようにしたいのですが、入力する画面が描画されなかったり、 入力してエンターキーを押すと入力画面が出なくなってしまったりと困っています。 どうか何が悪いのか教えて頂けないでしょうか。 またこのような問題を解決するときのデバッグの詳しい方法を教えて頂けないでしょうか? 真剣に勉強したいのでどうかお力を貸していただけるとありがたいです。 以下はソースコードです。 #include "DxLib.h" #include "string.h" //strcmp、strncmp関数を使うために必要 int konnnitiwasound = 0; int situreisimasitasound = 0; int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { // 使用する文字コードを UTF-8 に設定 ///SetUseCharCodeFormat(DX_CHARCODEFORMAT_UTF8); char String[256]; int InputHandle; SetGraphMode(700, 780, 32); // ウィンドウの大きさを指定 ChangeWindowMode(TRUE); // 全画面ではなくウインドウを使用 if (DxLib_Init() == -1) return -1; // DXライブラリ初期化処理 SetDrawScreen(DX_SCREEN_BACK); // 裏画面を使用する設定 SetFontSize(64); //サイズを64に変更 // キー入力ハンドルを作る(キャンセルなし全角文字有り数値入力じゃなし) InputHandle = MakeKeyInput(50, FALSE, FALSE, FALSE); // 作成したキー入力ハンドルをアクティブにする SetActiveKeyInput(InputHandle); // キー入力終了待ちループ // (ProcessMessageをループごとに行う) while (ProcessMessage() == 0)//★外に書いたものによってキー入力が終わり エンターをクリックされるたびに繰り返すように0とした、何もしていないのにずっと繰り返しているわけではない。 { // 入力が終了している場合は終了 if (CheckKeyInput(InputHandle) != 0) { // 画面の初期化 ClearDrawScreen(); // 入力モードを描画 DrawKeyInputModeString(640, 480); // 入力途中の文字列を描画 DrawKeyInputString(0, 0, InputHandle); DrawFormatString(500, 500, GetColor(255, 255, 0), "キーBを押して続きから"); // 裏画面の内容を表画面に反映させる ScreenFlip(); } // キー入力ハンドルを作る(キャンセルなし全角文字有り数値入力じゃなし) InputHandle = MakeKeyInput(50, FALSE, FALSE, FALSE); // 作成したキー入力ハンドルをアクティブにする SetActiveKeyInput(InputHandle); DrawFormatString(400, 500, GetColor(255, 255, 0), "キーAを押して続きから"); } // 入力された文字列を取得 GetKeyInputString(String, InputHandle); // 用済みのインプットハンドルを削除する DeleteKeyInput(InputHandle); // 画面の初期化 ClearDrawScreen(); // 入力された文字列を画面に表示する ///DrawString(0, 0, "あなたが入力した文字列は", GetColor(255, 255, 255)); DrawString(0, 0, String, GetColor(255, 255, 255)); //StringはUFT-8方式で作られたので、UFT-8方式で処理されて正常に表示される DrawString(0, 0, String, GetColor(255, 255, 255)); //比較文字列同士の文字コードが異なるのでTRUEが帰ることはない if (strcmp(String, "hello") == 0) { //そもそもここは通れない。 DrawString(100, 500, "hello! my friend!!", GetColor(200, 200, 255)); konnnitiwasound = LoadSoundMem("line-girl1-konnichiha1.mp3"); PlaySoundMem(konnnitiwasound, DX_PLAYTYPE_BACK); } else { situreisimasitasound = LoadSoundMem("line-girl1-moushiwakegozamasen1.mp3"); PlaySoundMem(situreisimasitasound, DX_PLAYTYPE_BACK); } // 裏画面の内容を表画面に反映させる ScreenFlip(); // キー入力待ち WaitKey(); // DXライブラリの使用終了 DxLib_End(); // 終了 return 0; } 以下のサイトを参考にしました。 //dxlib.xsrv.jp/function/dxfunc_input.html#R5N13 //dxlib.xsrv.jp/function/dxfunc_input.htmlのキー入力のための関すんなど。
メンテ

Page: 1 | 2 |

Re: キー入力した後にエンターを押しても再びキー入力できるようにしたい。 ( No.18 )
名前:マーク42 日時:2020/06/18 22:43

「modoruが1」になると「if(modoru == 1)」がmodoruが1としての条件を満たすため処理されるという説明では駄目でしょうか。
メンテ
Re: キー入力した後にエンターを押しても再びキー入力できるようにしたい。 ( No.19 )
名前:yumetodo 日時:2020/06/18 23:21

煮詰まってるようですね。 まずすでに指摘のあるとおり、goto文でも使わない限り、原則として上から順番にプログラムは実行されます (じつはこれは正しくありませんが時間計測のようなことをしない限り即座に問題にはならないのでとりあえず忘れていいです) --- さて、変数modoruの読み出し書き込み操作を列挙してみましょう。 int modoru = 0; // 中略 if (modoru == 0) { while (ProcessMessage() == 0) { // 中略 DrawFormatString(100, 150, GetColor(255, 255, 0), "ProcessMessage()は%d,modoruは%d", ProcessMessage(), modoru); modoru = 1; } } // 中略 if (modoru == 1) { // 中略 } 初めて変数modoruが参照されるのはif (modoru == 0)ですね。 ここでこれ以前に変数modoruは変更されず常に内容は0であることから、この条件文は常に真になることがわかります。 つまり、このif文は無意味な評価ですから単純に削除できます。 また、実は今まさに問題になっている >「modoruが1」になると「if(modoru == 1)」が処理される理屈を説明して頂けますか。 を解決すると、if (modoru == 1)もいらないことがわかり、ついでに変数modoru自体いらないことがわかります。 ここまでくるとそもそも変数modoruって一体何をしたかったのか、もう一度考えす必要がでてきます。 ちなみにこういった変数の読み出し/書き込み操作の列挙はVisual Studio 2017以降とてもわかり易くなりました。IDEのこういう機能を活用するといいですね。 (リンク先の図はC#ですがまあ大体同じです) ttps://docs.microsoft.com/ja-jp/visualstudio/ide/finding-references?view=vs-2019 --- 次にループを見ていきましょう。 while (ProcessMessage() == 0) { // 入力が終了している場合は終了 if (CheckKeyInput(InputHandle) != 0); // 画面の初期化 ClearDrawScreen(); // 入力モードを描画 DrawKeyInputModeString(640, 480); // 入力途中の文字列を描画 DrawKeyInputString(0, 0, InputHandle); DrawFormatString(100, 150, GetColor(255, 255, 0), "ProcessMessage()は%d,modoruは%d", ProcessMessage(), modoru); modoru = 1; // 裏画面の内容を表画面に反映させる ScreenFlip(); } ループを見るときに真っ先に考えるべきはループの停止条件です。今回はなんでしょうか? ProcessMessage() == 0 が満たされなくなったとき、つまり ProcessMessageがエラーを通知したときですね。 それ以外の停止条件は存在していません。 それ以外の停止条件は存在していません。 それ以外の停止条件は存在していません。 大事なことなので3回言いました。ここまでヒントを出したのですからそろそろクロエさんとPさんの指摘を総合してなにが欠けてるか考えてください。
メンテ
Re: キー入力した後にエンターを押しても再びキー入力できるようにしたい。 ( No.20 )
名前:管理人 日時:2020/06/18 23:55

> デバッグで変数modoruが1になっていることを確認できたのですが、if(modoru == 1)に飛びません。 > modoruに関してはif文がそういうものだと認識しているため、modoruの値が1になれば、if(modoru == 1)に向かうと考えていました。 マーク42さんのプログラムが不思議な組まれ方をしている謎が一つ解けました Pさんもご説明されていますが、if文にはそのような機能( modoruの値が1になればif(modoru == 1)に向かうという機能 )はありません F10で1行づつ実行していて、modoru = 1; が実行されても、実行位置が if(modoru == 1) の行に移動しないのが何よりの証拠です 『if文にはそのような機能( modoruの値が1になればif(modoru == 1)に向かうという機能 )は無い』 ということを前提に考えれば、かなり答えに近づけるのではないでしょうか?
メンテ
Re: キー入力した後にエンターを押しても再びキー入力できるようにしたい。 ( No.21 )
名前:かめのこにょこにょこ 日時:2020/06/19 00:51

> マーク42さん マーク42さんの「if 文」「while 文」に対する考え方を、スレッドに参加している人と共有し、 スレッドに参加している人が、マーク42さんに対して、的確なアドバイスをしやすくするために、 マーク42さんが、次の2つの質問に答えていただけませんか。 - - - 質問1. 次に「if 文」に対する考え方を並べます。 コードサンプル1を踏まえて、マーク42さんの「if 文」に対する考え方が、(1), (2)のどちらに近いかを教えてください。 ```cpp:コードサンプル1 int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { int modoru = 0; if (modoru == 1) { // if 文の中の処理 } } ``` (1) 関数 WinMain が実行される時、`if (modoru == 1)` という if条件文によって、 「変数 modoru が 1 に変更された時」に実行される処理として、「if 文の中の処理」が登録される。 よって、どこかで `modoru = 1` のといった変数 modoru を 1 にする処理が実行されたとき、 その処理の直後に、その登録された「if 文の中の処理」が実行される。 なお、「if 文の中の処理」は「変数 modoru が 1 に変更された時」に実行される処理の登録時には行われず、 すぐさまif 文の後に続く処理が実行される。 (2) 関数 WinMain が実行される時、`if (modoru == 1)` という if条件文によって、 その場で「変数 modoru が 1 に等しいかどうか」のチェックが行われる。 「変数 modoru が 1 に等しいかどうか」のチェックにクリアした場合のみ、「if 文の中の処理」が実行される。 なお、「変数 modoru が 1 に等しいかどうか」のチェックと「if 文の中の処理」が終わった後に、if 文の後に続く処理が実行される。 - - - 質問2. 次に「while 文」に対する考え方を並べます。 コードサンプル2を踏まえて、マーク42さんの「while 文」に対する考え方が、(1), (2)のどちらに近いかを教えてください。 ```cpp:コードサンプル2 int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { while (ProcessMessage() == 0) { // while 文の中の処理 } // while 文の後に続く処理 } ``` (1) 関数 WinMain が実行される時、`while (ProcessMessage() == 0) ` という while条件文によって、 「関数 ProcessMessage の実行結果が 0」の間だけ繰り返し行われる処理として、「while 文の中の処理」が登録される。 なお、「while 文の中の処理」は「関数 ProcessMessage の実行結果が 0」の間だけ繰り返し行われる処理として登録されるときには行われず、すぐさま while 文の後に続く処理が実行される。 (2) 関数 WinMain が実行される時、`while (ProcessMessage() == 0) ` という while条件文によって、 その場で「関数 ProcessMessage の実行結果が 0かどうか」のチェックが行われる。 「関数 ProcessMessage の実行結果が 0かどうか」のチェックにクリアした場合のみ、「while 文の中の処理」が実行される。 一度「while 文の中の処理」が終わったら、再び「関数 ProcessMessage の実行結果が 0かどうか」のチェックを行う。 再び「関数 ProcessMessage の実行結果が 0かどうか」のチェックにクリアすると、「while 文の中の処理」が実行される。 この、「関数 ProcessMessage の実行結果が 0かどうか」のチェックと「while 文の中の処理の実行」の繰り返しは、 一度でも「関数 ProcessMessage の実行結果が 0かどうか」のチェックに失敗しないかぎり、続けられる。 なお、「関数 ProcessMessage の実行結果が 0かどうか」のチェックと「while 文の中の処理の実行」の繰り返しが実行されている間は、while 文の後に続く処理は中断される。
メンテ
Re: キー入力した後にエンターを押しても再びキー入力できるようにしたい。 ( No.22 )
名前:かめのこにょこにょこ 日時:2020/06/19 01:04

> 管理人さん、yumetodoさん、クロエさん 次の点を踏まえて、マーク42さんが (1) よりの考え方をしているのではないかという仮説を立ててみました。 (1) なぜか終了処理をコメントアウトしている (>> 4) ```cpp // キー入力待ち // WaitKey(); // DXライブラリの使用終了 // DxLib_End(); // 終了 // return 0; ``` (2) このスレッドのレスポンスより (>> 6, 9) modoruに関してはif文がそういうものだと認識しているため、modoruの値が1になれば、if(modoru == 1)に向かうと考えていました。 また、teratail にも似たような質問をされる方がおりましたので、ここでも同一人物であるという仮定の上で、 両方のスレッドでの返答及びコードを参考にして、この仮説に至りました。 (質問者本人にとっては回答者が両方のスレッドを把握しているかのように錯覚しやすいから、許可された場でマルチポストするならリンクを貼り忘れて欲しくないと思ったり)
メンテ
Re: キー入力した後にエンターを押しても再びキー入力できるようにしたい。 ( No.23 )
名前:クロエ 日時:2020/06/19 10:17

(『if文にはそのような機能( modoruの値が1になればif(modoru == 1)に向かうという機能 )は無い』程度は過去に解説済みなのでそれを明確にしただけでは解決しないですけどね。問題はどうすればそこから脱せるのか)
メンテ
Re: キー入力した後にエンターを押しても再びキー入力できるようにしたい。 ( No.24 )
名前:クロエ 日時:2020/06/19 10:22

>「modoruが1」になると「if(modoru == 1)」がmodoruが1としての条件を満たすため処理されるという説明では駄目でしょうか。 入門書を読んだのですよね? 掲示板で質問も多々していますね。 上記の事はどこから得た情報ですか?
メンテ
Re: キー入力した後にエンターを押しても再びキー入力できるようにしたい。 ( No.25 )
名前:クロエ 日時:2020/06/19 10:36

>かめのこにょこにょこ 実はそんなシンプルな問題ではないのです。 マーク42さんは特定の理論に基づいてコードを書いているのではなく、その都度「こうなっほしい」という期待でコードを書いている印象です。 今はたまたま割り込み処理のように突然if(){}の中身が実行される期待を持っているだけです。 上記で分かる通り彼は「理屈」というものを理解していません。
メンテ
Re: キー入力した後にエンターを押しても再びキー入力できるようにしたい。 ( No.26 )
名前:マーク42 日時:2020/06/19 11:55

返信遅くなりすいません。返信が多いので読んでから返信します。
メンテ
Re: キー入力した後にエンターを押しても再びキー入力できるようにしたい。 ( No.27 )
名前:マーク42 日時:2020/06/19 14:14

terateilの方に載せていた変数modoruで書いたifのプログラムを正しく書けました。 //teratail.com/questions/270866#reply-387308 のサイトに変数modoruを使ったif文の修正前のプログラムが載っています。 //修正後 #include "DxLib.h" int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { char String[256]; int InputHandle; int modoru = 0; int modoruframe = 0; SetGraphMode(700, 780, 32); // ウィンドウの大きさを指定 ChangeWindowMode(TRUE); // 全画面ではなくウインドウを使用 // DXライブラリの初期化 if (DxLib_Init() == -1) return -1; // 描画先を裏にする SetDrawScreen(DX_SCREEN_BACK); // キー入力ハンドルを作る(キャンセルなし全角文字有り数値入力じゃなし) InputHandle = MakeKeyInput(50, FALSE, FALSE, FALSE); // 作成したキー入力ハンドルをアクティブにする SetActiveKeyInput(InputHandle); // キー入力終了待ちループ // (ProcessMessageをループごとに行う) if (modoru == 0) { while (ProcessMessage() == 0) { // 画面の初期化 ClearDrawScreen(); //まずは描画する部分から作る。 // 入力モードを描画 DrawKeyInputModeString(640, 480); // 入力途中の文字列を描画 DrawKeyInputString(0, 0, InputHandle); // 入力が終了している場合は終了 //エンターキーが押されていないとき if (CheckKeyInput(InputHandle) != 0) { // 入力された文字列を取得 GetKeyInputString(String, InputHandle); DrawString(0, 0, String, GetColor(255, 255, 255)); // DrawFormatString(100, 150, GetColor(255, 255, 0), "ProcessMessage()は%d,modoruは%d", ProcessMessage(), modoru); modoru = 1; // 裏画面の内容を表画面に反映させる // 再度インプットハンドルをアクティブにする SetActiveKeyInput(InputHandle); // 入力文字列を初期化する SetKeyInputString("", InputHandle); } // 入力された文字列を画面に表示する //関数ProcessMessage()にエラーがない限りループの外には出ず、ループはずっと続くのでProcessMessage()内にif文を書いた。 if (modoru == 1) { // DrawString(0, 300, "あなたが入力した文字列は", GetColor(255, 255, 255)); DrawString(0, 16, String, GetColor(255, 255, 255)); } //ProcessMessage()は1のままでここに書くことで上のif文の描画関数すべて関わるのでここにScreenFlip()を描けばよい。 ScreenFlip(); } } // 用済みのインプットハンドルを削除する DeleteKeyInput(InputHandle); ClearDrawScreen(); // 裏画面の内容を表画面に反映させる ScreenFlip(); // キー入力待ち // WaitKey(); // DXライブラリの使用終了 DxLib_End(); // 終了 return 0; }
メンテ
Re: キー入力した後にエンターを押しても再びキー入力できるようにしたい。 ( No.28 )
名前:マーク42 日時:2020/06/19 14:18

クロエさん返信ありがとうございます。 理屈がまったく理解できていませんでした。 これでもループの入門書を解いてみたのですが、細かい部分にまで思考が行き届いていないみたいです。 ループ処理がどのような順序で処理を行い、ループが続いた際のイメージが出来ていないようで。 頭の出来がほんとに悪いものでご迷惑をおかけします。
メンテ
Re: キー入力した後にエンターを押しても再びキー入力できるようにしたい。 ( No.29 )
名前:相田 日時:2020/06/19 14:20

これホントに動く? while-loop回らずに終了しない?
メンテ
Re: キー入力した後にエンターを押しても再びキー入力できるようにしたい。 ( No.30 )
名前:相田 日時:2020/06/19 14:23

あぁ、 modoru = 0 から始めるからいいのか。 とはいえ while-loop を if ( modoru == 0 ) で囲む意味がない。
メンテ
Re: キー入力した後にエンターを押しても再びキー入力できるようにしたい。 ( No.31 )
名前:でぃあぶろ 日時:2020/06/19 14:58

>相田さん そうなんですよね…今回でやっとこさif文の動きについて理解してもらえたのかと思ったのですが, それならばif(modoru == 0)なんて書かないんですよね…上でマーク42さんは「ループの入門書を解いてみた」とおっしゃっていますが, これはループの問題ではなくてif文の問題なんですよね…まだまだ問題は山積みのようです.
メンテ
Re: キー入力した後にエンターを押しても再びキー入力できるようにしたい。 ( No.32 )
名前:マーク42(解決) 日時:2020/06/19 16:14

if ( modoru == 0 ) で囲む意味がないのはわかっています。無意味なのですが、書きたいこだわりがありました。
メンテ
Re: キー入力した後にエンターを押しても再びキー入力できるようにしたい。 ( No.33 )
名前:相田 日時:2020/06/19 16:26

さらに、modoru が一旦1になったが最後 0に戻ることは絶対ないから ますますもって"変数"の意味を喪失している。 loopの外に出なくなったのだから(loopの外から中へ)戻る必要もなくなった。 したがって 変数modoru は不要になった(はず)。 > terateilの方に載せていた変数modoruで書いたifのプログラムを正しく書けました。 正しく書いても意味がない。modoruは不要なんだから 正しく動く"だけ"の無駄なコードだ。
メンテ
Re: キー入力した後にエンターを押しても再びキー入力できるようにしたい。 ( No.34 )
名前:マーク42(解決) 日時:2020/06/19 16:52

>>正しく書いても意味がない。modoruは不要なんだから 正しく動く"だけ"の無駄なコードだ。 そうですね。
メンテ
Re: キー入力した後にエンターを押しても再びキー入力できるようにしたい。 ( No.35 )
名前:クロエ 日時:2020/06/19 17:01

できれば理論というものを教えたかったのですがね。 プログラムの間違いを修正してもそれを身に着ける事はありませんので、 しばらくしたらまた同じ事を質問しに来るだけです。 管理人さんの負担らなると思うのですが。
メンテ
Re: キー入力した後にエンターを押しても再びキー入力できるようにしたい。 ( No.36 )
名前:マーク42(解決) 日時:2020/06/19 19:40

期待に沿えず申し訳ありません、
メンテ
Re: キー入力した後にエンターを押しても再びキー入力できるようにしたい。 ( No.37 )
名前:かめのこにょこにょこ 日時:2020/06/19 20:40

>> クロエさん > マーク42さんは特定の理論に基づいてコードを書いているのではなく、その都度「こうなっほしい」という期待でコードを書いている印象です。 > 今はたまたま割り込み処理のように突然if(){}の中身が実行される期待を持っているだけです。 > 上記で分かる通り彼は「理屈」というものを理解していません。 なるほど、マーク42さんが、if(){}自体を割り込み処理であるかのように勘違いしていると、私はそう考えていました。 しかし、マーク42さんは、そのような理屈自体 (勘違いしたものにせよ) に興味がなく、 マーク42さんに if(){} の説明を求めたとき、たまたま割り込み処理だと (帳尻を合わせるように) 答えたに過ぎないのですね。 すなわち、マーク42さんに、if(){}の「理屈」の説明を求めること自体が、ナンセンスな行為であったと理解いたしました。 いずれにせよ、私の質問自体が、単純な選択を求めるものではありますが、 マーク42さんにとっては、それぞれの選択肢の理解が難しかったのでしょう。 マーク42さんは、他の回答者の文章を額面通りに理解し、その文章に額面通りに回答することで精いっぱいでしょうし、 しばし様子を見るだけとさせていただきます。
メンテ

Page: 1 | 2 |

題名
名前
コメント
パスワード (記事メンテ時に使用)

   クッキー保存