Lighthouse3d.com >> GLUT Tutorial >> Input >> Keyboard

GLUT可以让应用程序自动监测键盘输入,包括普通按键和特殊按键,例如F1和向上键.本节我们来讨论怎样监测按键事件和如何响应.

目前为止你应该已经发现,需要GLUT处理对应的事件,必须先告知GLUT把事件绑定到指定函数.之前已经介绍了重绘事件,系统空闲事件和窗体更改大小事件.

同样的,下面来介绍键盘事件.我们要告知GLUT哪个函数是响应按键处理的.

GLUT提供两个函数来为键盘事件注册回调函数.第一个是glutKeyboardFunc,用于告知窗体系统处理普通按键事件.例如字母,数字,和ASCII包含的内码.原型如下:

void glutKeyboardFunc(void (*func) (unsigned char key, int x, int y));

func - 处理普通按键事件的函数.如果传入NULL值则忽略普通按钮

glutKeyboarFunc绑定的函数必须返回三个结果值.第一个是按键对应的ASCII内码,其余两个是按钮触发时鼠标所在的位置.鼠标位置是相对于窗体客户端的左上角.

比较可行的实现方案是,当用户输入esc键的时候退出程序.留意到当看到glutMainLoop函数时,我们会注意到它是在一个死循环中,永远不会返回.跳出死循环的唯一办法是调用系统的exit函数.这就是函数里面需要实现的部分,当用户按esc键的时候,我们要调用系统exit函数来促使程序终止.代码如下:

void processNormalKeys(unsigned char key, int x, int y) {

    if (key == )
exit();
}

接着看特殊键处理.GLUT提供了glutSpecialFunc函数来处理,原型如下:

void glutSpecialFunc(void (*func) (int key, int x, int y));

func - 同glutKeyboardFunc函数.

接下来实现一个功能,用户通过按特殊键来改变三角形的颜色.F1红色,F2绿色,F3蓝色.

void processSpecialKeys(int key, int x, int y) {

    switch(key) {
case GLUT_KEY_F1 :
red = 1.0;
green = 0.0;
blue = 0.0; break;
case GLUT_KEY_F2 :
red = 0.0;
green = 1.0;
blue = 0.0; break;
case GLUT_KEY_F3 :
red = 0.0;
green = 0.0;
blue = 1.0; break;
}
}

常量GLUT_KEY_*是在glut.h头文件中预定义的.该常量的具体定义如下:

GLUT_KEY_F1        F1 function key
GLUT_KEY_F2 F2 function key
GLUT_KEY_F3 F3 function key
GLUT_KEY_F4 F4 function key
GLUT_KEY_F5 F5 function key
GLUT_KEY_F6 F6 function key
GLUT_KEY_F7 F7 function key
GLUT_KEY_F8 F8 function key
GLUT_KEY_F9 F9 function key
GLUT_KEY_F10 F10 function key
GLUT_KEY_F11 F11 function key
GLUT_KEY_F12 F12 function key
GLUT_KEY_LEFT Left function key
GLUT_KEY_RIGHT Right function key
GLUT_KEY_UP Up function key
GLUT_KEY_DOWN Down function key
GLUT_KEY_PAGE_UP Page Up function key
GLUT_KEY_PAGE_DOWN Page Down function key
GLUT_KEY_HOME Home function key
GLUT_KEY_END End function key
GLUT_KEY_INSERT Insert function key

为配合自定义响应函数processSpecialKeys,我们添加红绿蓝变量到代码头部.除此之外,我们要更改renderScene函数来达到渲染效果.

void renderScene(void) {

    // Clear Color and Depth Buffers
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// Reset transformations glLoadIdentity();
// Set the camera
gluLookAt( 0.0f, 0.0f, 10.0f,
0.0f, 0.0f, 0.0f,
0.0f, 1.0f, 0.0f); glRotatef(angle, 0.0f, 1.0f, 0.0f); // the function responsible for setting the color
glColor3f(red,green,blue);
glBegin(GL_TRIANGLES);
glVertex3f(-2.0f,-2.0f, 0.0f);
glVertex3f( 2.0f, 0.0f, 0.0);
glVertex3f( 0.0f, 2.0f, 0.0);
glEnd();
angle+=0.1f; glutSwapBuffers();
}

现在已经定义好glutKeyboardFunc和glutSpecialFunc函数的代码.

要令任何地方都能调用该函数,就必须先更改处理函数中的键盘事件任何时候都能处理.因为这不是一个常用特征.所以我们会把它放在main函数中.下面是加了键盘处理的main函数:

int main(int argc, char **argv) {

    // init GLUT and create window
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DEPTH | GLUT_DOUBLE | GLUT_RGBA);
glutInitWindowPosition(,);
glutInitWindowSize(,);
glutCreateWindow("Lighthouse3D- GLUT Tutorial"); // register callbacks
glutDisplayFunc(renderScene);
glutReshapeFunc(changeSize);
glutIdleFunc(renderScene); // here are the new entries
glutKeyboardFunc(processNormalKeys);
glutSpecialFunc(processSpecialKeys); // enter GLUT event processing cycle
glutMainLoop(); return ;
}

Ctrl, Alt和Shift键

有时我们需要处理编辑键,例如ctrl,alt和shift. GLUT提供一个函数来监测编辑键.但是该函数只能在键盘和鼠标输入事件的绑定函数里面调用.原型如下:

int glutGetModifiers(void);

该函数的返回值是三个可选的常量(包含在glut.h头文件中),用位或组合形式.

GLUT_ACTIVE_SHIFT - 通知shift键被按下,或者大写锁在开启状态.如果两者都是开启状态,就反而是不大写.

GLUT_ACTIVE_CTRL - 通知ctrl键被按下.

GLUT_ACTIVE_ALT - 通知alt键被按下.

接下来扩展我们的processNormalKeys函数以控制编辑键.假定你希望用r键把红色变量归零,用alt键加r键把红色调到最大.实现代码如下:

void processNormalKeys(unsigned char key, int x, int y) {

    if (key == )
exit();
else if (key=='r') {
int mod = glutGetModifiers();
if (mod == GLUT_ACTIVE_ALT)
red = 0.0;
else
red = 1.0;
}
}

最后,我们如果要监测ctrl+alt+F1这样的组合键,如何实现? 我们要同时监测两个编辑键.我们以位或组合起两个需要的常量.例如下面代码是用ctrl+alt+F1组合键来更改为红色.

void processSpecialKeys(int key, int x, int y) {

    int mod;
switch(key) {
case GLUT_KEY_F1 :
mod = glutGetModifiers();
if (mod == (GLUT_ACTIVE_CTRL|GLUT_ACTIVE_ALT)) {
red = 1.0; green = 0.0; blue = 0.0;
}
break;
case GLUT_KEY_F2 :
red = 0.0;
green = 1.0;
blue = 0.0; break;
case GLUT_KEY_F3 :
red = 0.0;
green = 0.0;
blue = 1.0; break;
}
}

完整代码如下:

#include <stdlib.h>

#ifdef __APPLE__
#include <GLUT/glut.h>
#else
#include <GL/glut.h>
#endif // all variables initialized to 1.0, meaning
// the triangle will initially be white
float red=1.0f, blue=1.0f, green=1.0f; // angle for rotating triangle
float angle = 0.0f; void changeSize(int w, int h) { // Prevent a divide by zero, when window is too short
// (you cant make a window of zero width).
if (h == )
h = ;
float ratio = w * 1.0 / h; // Use the Projection Matrix
glMatrixMode(GL_PROJECTION); // Reset Matrix
glLoadIdentity(); // Set the viewport to be the entire window
glViewport(, , w, h); // Set the correct perspective.
gluPerspective(45.0f, ratio, 0.1f, 100.0f); // Get Back to the Modelview
glMatrixMode(GL_MODELVIEW);
} void renderScene(void) { // Clear Color and Depth Buffers
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // Reset transformations
glLoadIdentity(); // Set the camera
gluLookAt( 0.0f, 0.0f, 10.0f,
0.0f, 0.0f, 0.0f,
0.0f, 1.0f, 0.0f); glRotatef(angle, 0.0f, 1.0f, 0.0f); glColor3f(red,green,blue);
glBegin(GL_TRIANGLES);
glVertex3f(-2.0f,-2.0f, 0.0f);
glVertex3f( 2.0f, 0.0f, 0.0);
glVertex3f( 0.0f, 2.0f, 0.0);
glEnd(); angle+=0.1f; glutSwapBuffers();
} void processNormalKeys(unsigned char key, int x, int y) { if (key == )
exit();
} void processSpecialKeys(int key, int x, int y) { switch(key) {
case GLUT_KEY_F1 :
red = 1.0;
green = 0.0;
blue = 0.0; break;
case GLUT_KEY_F2 :
red = 0.0;
green = 1.0;
blue = 0.0; break;
case GLUT_KEY_F3 :
red = 0.0;
green = 0.0;
blue = 1.0; break;
}
} int main(int argc, char **argv) { // init GLUT and create window
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DEPTH | GLUT_DOUBLE | GLUT_RGBA);
glutInitWindowPosition(,);
glutInitWindowSize(,);
glutCreateWindow("Lighthouse3D- GLUT Tutorial"); // register callbacks
glutDisplayFunc(renderScene);
glutReshapeFunc(changeSize);
glutIdleFunc(renderScene); // here are the new entries
glutKeyboardFunc(processNormalKeys);
glutSpecialFunc(processSpecialKeys); // enter GLUT event processing cycle
glutMainLoop(); return ;
}

[译]GLUT教程 - 键盘的更多相关文章

  1. [译]GLUT教程 - 键盘高级特性

    Lighthouse3d.com >> GLUT Tutorial >> Input >> Advanced Keyboard 本节我们会介绍另外4个处理键盘事件的 ...

  2. [译]GLUT教程 - 鼠标

    Lighthouse3d.com >> GLUT Tutorial >> Input >> The Mouse 上一节我们讨论了怎么用GLUT的键盘函数跟OpenG ...

  3. [译]GLUT教程(目录)

    http://www.lighthouse3d.com/tutorials/glut-tutorial/ GLUT是OpenGL Utility Toolkit的意思.作者Mark J. Kilgar ...

  4. [译]GLUT教程 - glutPostRedisplay函数

    Lighthouse3d.com >> GLUT Tutorial >> Avoiding the Idle Func >> glutPostRedisplay 直 ...

  5. [译]GLUT教程 - 渲染到子窗体

    Lighthouse3d.com >> GLUT Tutorial >> Subwindows >> Rendering to Subwindows 先回顾一下之前 ...

  6. [译]GLUT教程 - 游戏模式

    Lighthouse3d.com >> GLUT Tutorial >> Extras >> Game Mode 根据GLUT官网的说明,GLUT的游戏模式是为开启 ...

  7. [译]GLUT教程 - 修改菜单

    Lighthouse3d.com >> GLUT Tutorial >> Pop-up Menus >> Modifying Menus 肯定会有菜单需要被修改的状 ...

  8. [译]GLUT教程 - 弹出菜单基础

    Lighthouse3d.com >> GLUT Tutorial >> Pop-up Menus >> Popup Menus 弹出菜单也是GLUT的一部分.虽然 ...

  9. [译]GLUT教程 - 移动镜头3

    Lighthouse3d.com >> GLUT Tutorial >> Input >> Moving the Camera III 上一节的示例中我们用键盘更改 ...

随机推荐

  1. Python的程序结构[1] -> 方法/Method[4] -> 魔术方法 __call__ / __str__ / __repr__

    __call__ 方法 __call__ 是当对象被调用时会调用的方法,允许一个对象(类的实例等)像函数一样被调用,也可以传入参数. 1 class Foo(): 2 def __init__(sel ...

  2. Spfa【P1813】拯救小tim_NOI导刊2011提高(02)

    Description 小tim在游乐场,有一天终于逃了出来!但是不小心又被游乐场的工作人员发现了„„所以你的任务是安全地把小tim护送回家.但是,A市复杂的交通状况给你出了一大难题. A市一共有n个 ...

  3. viewport 测试以及总结

    这里的总结的主要思想是ppk的文章(文末附有链接),加入了自己的总结,下面的测试用的是iphone5s,android是安卓5.5吋的手机,只是为了直观感受和方便解释拿了空出来的测试机给出的数据.详细 ...

  4. bzoj 1305: [CQOI2009]dance跳舞

    题目链接 bzoj 1305: [CQOI2009]dance跳舞 题解 男,女生拆点A1A2,B1B2,拆成两点间分别连容量为K的边,限制与不喜欢的人跳舞的数量 A1连接源点容量为x,B1连接汇点容 ...

  5. highcharts 图例详解

    highcharts 图例 tooltip: {                                           },                      legend: { ...

  6. jsp笔记3(内置对象)

    jsp脚本中的9个内置对象: 1.application:javax.servlet.ServletContext的实例对象,该实例对象代表jsp所属的web应用本身,可用于在jsp页面或Servle ...

  7. java的一些基本常识

    1.什么是java虚拟机?为什么把java称作是“无关平台的语言”? java虚拟机是一个可以执行Java字节码的虚拟进程.Java源文件被编译成能被Java虚拟机执行的字节码文件. Java 被设计 ...

  8. androd 获得wifi列表

    AndroidManifest.xml <?xml version="1.0" encoding="utf-8"?> <manifest xm ...

  9. 基于Prometheus,Alermanager实现Kubernetes自动伸缩

    到目前为止Kubernetes对基于cpu使用率的水平pod自动伸缩支持比较良好,但根据自定义metrics的HPA支持并不完善,并且使用起来也不方便. 下面介绍一个基于Prometheus和Aler ...

  10. [置顶] kubernetes-kubectl命令说明

    kubectl kubectl controls the K8S cluster manager. Find more information at https://github.com/K8S/K8 ...