質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
GLFW

GLFWは、OpenGLを使用してアプリ開発を行うためのフレームワークです。Macにも対応しているマルチプラットフォームであることが特徴。ウィンドウ管理、解像度切り替え、入力管理などの機能を持ちます。

OpenGL

OpenGLは、プラットフォームから独立した、デスクトップやワークステーション、モバイルサービスで使用可能な映像処理用のAPIです。

C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

Q&A

解決済

2回答

3760閲覧

[GLFW] glfwSetKeyCallback()関数を使ってキーが押された瞬間を検出したい。

退会済みユーザー

退会済みユーザー

総合スコア0

GLFW

GLFWは、OpenGLを使用してアプリ開発を行うためのフレームワークです。Macにも対応しているマルチプラットフォームであることが特徴。ウィンドウ管理、解像度切り替え、入力管理などの機能を持ちます。

OpenGL

OpenGLは、プラットフォームから独立した、デスクトップやワークステーション、モバイルサービスで使用可能な映像処理用のAPIです。

C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

0グッド

0クリップ

投稿2020/09/21 13:27

編集2021/04/19 11:30

提示コードの///コメント部内の部のコードですがglfwSetKeyCallback();イベント処理関数を使ってキーが押された瞬間1と返す方法が知りたいです。提示画像ですが提示コードのように実装したのですがなぜか1という値が数フレーム返って来てしまいます。本来押された瞬間であれば1は一回だけで後は2の値が来るはずなのですがログを見ると数フレーム来てしまっています。これは何が原因なのでしょうか?

参考サイト: https://www.glfw.org/docs/latest/group__input.html#ga1caf18159767e761185e49a3be019f8d

イメージ説明

cpp

1//#define GLEW_STATIC //スタティックリンク 2#include <iostream> 3#include <fstream> 4#include <cstdlib> 5#include <vector> 6#include <glew/include/GL/glew.h> 7#include <glfw/include/GLFW/glfw3.h> 8 9 10 11#include "Window.hpp" 12#include "Shape.hpp" 13#include "Shader.hpp" 14 15Object::Vertex rectangleVertex[4] = 16{ 17 {-0.5f,-0.5f}, 18 {0.5f,-0.5f}, 19 {0.5f,0.5f}, 20 {-0.5f,0.5f} 21}; 22 23 24int main() 25{ 26 if (glfwInit() == GL_FALSE) 27 { 28 std::cerr << "glfw初期化失敗。" << std::endl; 29 return -1; 30 } 31 32 33 atexit(glfwTerminate); //プログラム終了時の処理を登録 34 Window window; 35 36 //OpenGL Verison 3.2 Core Profile を選択する 37 glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR,3); 38 glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR,2); 39 glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT,GL_TRUE); 40 glfwWindowHint(GLFW_OPENGL_PROFILE,GLFW_OPENGL_CORE_PROFILE); 41 42 Shape* shape = new Shape(2, 4, rectangleVertex); 43 44 Shader shader("Test.vert","Test.frag"); 45 shader.setBindAttribVertex(0, "Position"); 46 shader.setBindAttribFragment(0, "fragment"); 47 48 49 glClearColor(1.0, 0.0, 0.0, 1.0); //背景色 50 while (window) 51 { 52 glClear(GL_COLOR_BUFFER_BIT); //カラーバッファをクリア 53 shader.Active(); 54 55 56 57 printf(": %d\n", window.getKeyInput(GLFW_KEY_SPACE)); 58 59 60 61 62 63 64 65 window.SwapBuffers(); //ダブルバッファリング 66 } 67 68} 69

cpp

1#include "Window.hpp" 2 3//コンストラクタ 4Window::Window(int width, int height, const char* title) 5 :window(glfwCreateWindow(width, height, title, NULL, NULL)), 6 wheel(0) 7{ 8 std::fill(std::begin(keyStatus),std::end(keyStatus),0); 9 10 if (window == NULL) 11 { 12 std::cerr << "ウインドウ生成失敗" << std::endl; 13 exit(1); 14 } 15 16 glfwMakeContextCurrent(window); //コンテキストを作成 17 18 glewExperimental = GL_TRUE; 19 if (glewInit() != GLEW_OK) 20 { 21 std::cerr << "GLFW 初期化失敗" << std::endl; 22 exit(1); 23 } 24 25 atexit(glfwTerminate); //プログラム終了時の処理を登録 26 glfwSwapInterval(1); //垂直同期 27 28 29 //イベント処理 30 glfwSetWindowUserPointer(window, this); //このインスタンスのthis 31 glfwSetWindowSizeCallback(window, Resize); //ウインドウサイズを変更する時に呼び出す処理 32 glfwSetScrollCallback(window,Wheel); //マウスホイール操作時に呼び出す処理 33////////////////////////////////////////////////////////////////////////////////////////////// 34 glfwSetKeyCallback(window, KeyBoard); //キー入力時に呼び出す処理 35////////////////////////////////////////////////////////////////////////////////////////////// 36 37 38 Resize(window, width, height); 39 40} 41 42//サイズ変更 43void Window::Resize(GLFWwindow* const win, int width, int height) 44{ 45 int fbWidth, fbHeight; 46 glfwGetFramebufferSize(win, &fbWidth, &fbHeight); 47 glViewport(0, 0, fbWidth, fbHeight); 48 49 Window* const instance = (Window*)glfwGetWindowUserPointer(win); 50 51 if (instance != NULL) 52 { 53 instance->size.x = (GLfloat)width; 54 instance->size.y = (GLfloat)height; 55 } 56} 57 58//ウインドウサイズを取得 59const glm::vec2 Window::getSize() const 60{ 61 return size; 62} 63 64 65//キー入力を取得 66const int Window::getKeyInput(int key)const 67{ 68 return keyStatus[key]; 69} 70 71//マウスホイール 72void Window::Wheel(GLFWwindow* win, double x, double y) 73{ 74 Window* const instance = (Window*)glfwGetWindowUserPointer(win); 75 76 if (instance != NULL) 77 { 78 instance->wheel += (GLfloat)y; 79 } 80} 81 82///////////////////////////////////////////////////////////////////////////////////////////////// 83//キー入力 84void Window::KeyBoard(GLFWwindow* win, int key, int scancode, int action, int mods) 85{ 86 Window* const instance = (Window*)glfwGetWindowUserPointer(win); 87 88 if (instance != NULL) 89 { 90 instance->keyStatus[key] = action; 91 } 92} 93//////////////////////////////////////////////////////////////////////////////////////////////// 94 95//bool 演算子 96Window::operator bool() 97{ 98 glfwPollEvents(); //イベントを取り出す 99 100 //ウインドウを閉じる必要があれば false 101 if (glfwWindowShouldClose(window) != 0) 102 { 103 return false; 104 } 105 else { 106 return true; 107 } 108} 109 110//ダブルバッファリング 111void Window::SwapBuffers()const 112{ 113 glfwSwapBuffers(window); 114} 115 116//デストラクタ 117Window::~Window() 118{ 119 glfwDestroyWindow(window); 120} 121

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

退会済みユーザー

退会済みユーザー

2021/04/19 11:38

文章を修正しました。
guest

回答2

0

ベストアンサー

GLFW なら callback を使えばどうでしょう.

glfwSetKeyCallback で設定した callback 関数の引数にイベント情報(押した,離した,etc)が来るから,
それで判定するので十分ならば,自前で押された履歴みたいなのを記憶するよりは楽かも.


編集された件について:

なぜか1という値が数フレーム返って来てしまいます。本来押された瞬間であれば1は一回だけで後は2の値が来るはずなのですがログを見ると数フレーム来てしまっています。これは何が原因なのでしょうか?

1を複数回表示しているのはあなたのメインループです.
callback関数の引数に1が複数回連続で来ているわけではありません.

あなたの言う「数フレーム」の間に,callback関数が何回呼ばれているのかを確認すべきです.
というか,キーを押しっぱなしにした時のcallback関数の呼ばれ具合を最初に確認すべき.
キーリピート(:テキストエディタ上でキーを押しっぱなしにしたときの入力具合)と同様の呼び出しタイミングになるはず.

キーを押した際に callback関数が呼ばれて,値が1になった後(キーを押しっぱなしにしたとして),
次に callback関数が呼ばれて値が2になるまでの間に,「数フレーム」が経過しています.

投稿2020/09/22 00:48

編集2021/04/20 01:35
fana

総合スコア11658

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

退会済みユーザー

退会済みユーザー

2021/04/20 03:36

イベント処理では無理だということなので単純にglfwGetKey();を呼ぶことにしました。
fana

2021/04/20 03:48

> 無理 という結論がどこから来たのかわからないが… callback関数が引数値1で呼ばれた際に,その旨をどこか(キーが押された瞬間を知りたい側)に向けて伝達すればよいだけの話ではないのだろうか? それこそcallbackの仕組みにするとかで.
退会済みユーザー

退会済みユーザー

2021/04/20 04:10

ちょっと自分には難しいのでわからないのでglfwGetKey();で行います。提案ありがとうざいました。
dodox86

2021/04/20 04:17

あなたは一体何を言っているのか。そもそもの質問が「glfwSetKeyCallback()関数を使ってキーが押された瞬間を検出したい」でしょうに。それに則って回答をいただいているのが分かりませんか。
fana

2021/04/20 04:23 編集

質問内容を丸ごと書き換えるからこういうことになる. (根本から書き換えるのをやめろ,という旨の指摘は何度かされたと思うのだが) 元々は,「キーが押された瞬間が知りたい」みたいな話だったハズ. で,callbackを使えば,キーが押されたタイミングである旨が引数でご丁寧に渡されてくる話になっているのだから,それで解決できるのでは?という旨の回答をした. 押されたタイミングで通知が来るというのに,これ以上何を望むというのか?
fana

2021/04/20 04:30 編集

自分で勝手に書いたループ内の処理の進捗単位である「フレーム」と その他の処理が何もせずとも勝手にタイミング同期してくれるなんてことはないわけで. そこの調整くらいは自分で必要十分な形にやろうよ,っていう.
fana

2021/04/20 04:52

余談: glfwGetKey()が実際どういう実装になっているのか知らないけども, もしもそれを使うことで,キーの(物理的な?)状態を「フレーム」の間隔でポーリングする形になるのだとしたら,キー押下時間がポーリング間隔よりも短い場合に入力を取りこぼし得る,ということは知っておくべきかもしれない. (例えば,「フレーム」の処理が過度に重くなると,操作困難になるかもしれない.) (GLFWには,そういうことに対処できる方法として(?) GLFW_STICKY_KEYS なんていうのがあるみたい)
退会済みユーザー

退会済みユーザー

2021/04/20 05:00 編集

この質問者に必要なのは、場当たり的な解決法の提示よりも自分で考えさせる事じゃないかなと思ったり。 他から拾ってきたコードや、他人に提示された提案を自分で理解・検証したりせずそのまま自分のプロジェクトに持ってきて、そこで不具合を起こしても理解出来ないしデバッグもしないから、また質問してデバッグ作業を丸投げするの繰り返し。 過去の質問の傾向がずっとそうです。
fana

2021/04/20 06:19

「ログとしてどうの」とかなんとかいう建て前を盾に取れば, 回答は質問者のみに向けたものというわけではないから,「場当たり的な解決法」を示すことにも一定の意味はあるのではなかろうか. (その意味においては,この質問者の問題が解決しなかろうが,自分で一切考えなかろうが,どうでもいい.) まぁ,現状の質問内容: > これは何が原因なのでしょうか? という話に答えるだけだと,これはこの質問者の現在のコード固有のバグの話にしかならないから,前記の建て前すら成立しないのだけども…
退会済みユーザー

退会済みユーザー

2021/06/21 05:12

今更質問ですがつまりイベント型ではキーが押された瞬間だけ‘1であとは2,3が返ってくるという処理はできないのでしょうか?実現不可能ということでしょうか?
fana

2021/06/21 05:51

> キーが押された瞬間だけ 「瞬間」って何だよっていう. > あとは2,3が返ってくる とかいうけど,それを「返す側」から見たら,あなたが言うところの「(1を返すべき)瞬間」が「過ぎ去ったこと」はどうやってわかるの? 「返す値」をどんなタイミングで 1 から 2だの3だのに切り替えればいいの? っていうところは,「返す側」に判断つく話なのか? 判断が付くのであれば,その判断処理を実装して適切な返せばいいだけ. 判断が付かないのであれば,その仕事は「その判断をすることが可能な別の場所」でやればいいんじゃないですかね. --- っていうか,アカウントをまたいで話続ける形はどうなん?
退会済みユーザー

退会済みユーザー

2021/06/21 06:20

すいませんでした。
guest

0

提示サイトですが「キーが押された1フレームだけ一瞬だけを取得する」関数はあるのでしょうか?自分は押している間ずーっとif文が通るコードしか作れず困っています。モード切り替えの再に一回だけif文の中を実行できるような関数がほしいのですがどうすればいいのでしょうか?

C++ならbool型の変数「key」を作り、キーが押した瞬間にkeyの値を変更すれば良いかと思います。

C++

1bool key = false; 2 3if (glfwGetKey(Window, GLFW_KEY_F1) == GLFW_PRESS) 4{ 5 if (key == false){ 6 key = true; 7 //キーを押した瞬間の処理 8 } 9}else{ 10 key = false; 11}

投稿2020/09/21 23:57

stdio

総合スコア3307

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

退会済みユーザー

退会済みユーザー

2020/09/22 00:36

自分もそれを思いつきましたが。ライブラリがあるだろ?と思ったのですがないものはないので自分作るしかないようですねわかりました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問