GLUT позволяет создавать приложения, которые работают с клавиатурой, обрабатывают нажатия клавиш. В этом уроке мы увидим, как определить, какая клавиша была нажата, как нажатие может быть обработано GLUT. Вы уже знаете, что когда вы хотите взять под контроль обработки событий некоторую функцию вы должны сказать GLUT заранее, какие функции будут использованы. До сих пор мы сообщали GLUT, какие функции мы использовали для рисования, когда окно должен был быть перерисовано, какая функция вызывается, когда система простаивает, и какая функция вызывается при изменении размеров окна. Мы должны сделать то же самое для клавиатуры. Мы должны зарегестрировать в GLUT функции, которые будут выполнять необходимую обработку нажатий клавиш. GLUT предоставляет две функции для регистрации обратного вызова для событий клавиатуры. glutKeyboardFunc, используется, чтобы сообщить системе, что мы хотим обработать"нормальные" нажатия клавиш. Под "нормальными" нажатиями клавиш, мы имеем в виду буквы, цифры, все, что имеет ASCII код. Синтаксис этой функции заключается в следующем:
void glutKeyboardFunc(void (*func) (unsigned char key, int x, int y));
Параметры:
*func - имя функции, которая будет обрабатывать "нормальные" события клавиатуры. Передача NULL в качестве аргумента заставляет GLUT игнорировать "нормальные" события(или нажатия).
Функция, используемая в качестве аргумента glutKeyboardFunc должна иметь три аргумента. В первом содержится ASCII код нажатой клавиши, оставшиеся два аргумента обеспечивают положение курсора мыши при нажатии клавиши, относительно верхнего левого угла клиентской области окна. Возможная реализация этой функции - обеспечить выход из приложения, когда пользователь нажимает клавишу Esc. Обратите внимание, что функция glutMainLoop - бесконечный цикл, то есть он никогда не заканчивается. Единственный выход из этого цикла заключается в вызове функции выхода из системы. Так что это именно то, что наша функция будет делать, ползователь захочет выйти из исполняемого приложения в окне (используем stdlib.h в исходном коде). Код функции:
void processNormalKeys(unsigned char key, int x, int y) { if (key == 27) exit(0); }
Обратите внимание, что мы используем точно такую же переменную, указанной в синтаксисе glutKeyboardFunc. Если вы не сделаете это, вы получите ошибку при компиляции!
GLUT предоставляет функцию glutSpecialFunc, так что вы можете зарегистрировать функцию для специальных нажатий клавиш. Синтаксис этой функции заключается в следующем:
void glutSpecialFunc(void (*func) (int key, int x, int y));
Параметры:
*func - имя функции, которая будет обрабатывать специальные нажатия клавиатуры. Передача NULL в качестве аргумента заставляет GLUT игнорировать специальные клавиши.
Мы напишем функцию, которая изменяет цвет нашего треугольника, когда нажаты некоторые специальные клавиши. Эта функция будет красить треугольник в красный увет, если нажать клавишу 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
GLUT_KEY_F2 - функциональная клавиша F2
GLUT_KEY_F3 - функциональная клавиша F3
GLUT_KEY_F4 - функциональная клавиша F4
GLUT_KEY_F5 - функциональная клавиша F5
GLUT_KEY_F6 - функциональная клавиша F6
GLUT_KEY_F7 - функциональная клавиша F7
GLUT_KEY_F8 - функциональная клавиша F8
GLUT_KEY_F9 - функциональная клавиша F9
GLUT_KEY_F10 - функциональная клавиша F10
GLUT_KEY_F11 - функциональная клавиша F11
GLUT_KEY_F12 - функциональная клавиша F12
GLUT_KEY_LEFT - функциональная клавиша стрелка влево
GLUT_KEY_RIGHT - функциональная клавиша стрелка вправо
GLUT_KEY_UP - функциональная клавиша стрелка вверх
GLUT_KEY_DOWN - функциональная клавиша стрелка вниз
GLUT_KEY_PAGE_UP - Page Up функциональная клавиша
GLUT_KEY_PAGE_DOWN - Page Down функциональная клавиша
GLUT_KEY_HOME - функциональная клавиша на главнуб( домой )
GLUT_KEY_END - функциональная клавиша End
GLUT_KEY_INSERT - функциональная клавиша Insert
Для того, чтобы код, определенный выше, заработал с новыми функциями, мы должны добавить объявление красного, зеленого и синего переменных в начале нашего кода. Кроме того, чтобы иметь желаемый эффект мы должны изменить функцию renderScene.
void renderScene(void) { // очистить буфер цвета и глубины. glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // обнулить трансформацию glLoadIdentity(); // установить камеру 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( 0.0f, 2.0f, 0.0); glVertex3f( 2.0f,-2.0f, 0.0); glEnd(); angle+=0.1f; glutSwapBuffers(); }
Регистрируе функции обработки "нормальных" и "специальных" нажатий клавиатуры: glutKeyboardFunc GLUT и glutSpecialFunc. Вызов этих функции может быть выполнен в любом месте, что означает, что мы можем изменить функции обработки клавиатуры для обработки событий в любое время. Итак, наша новая функция main:
int main(int argc, char **argv) { // инициализация glutInit(&argc, argv); glutInitDisplayMode(GLUT_DEPTH | GLUT_DOUBLE | GLUT_RGBA); glutInitWindowPosition(100,100); glutInitWindowSize(320,320); glutCreateWindow("Урок 4"); // регистрация glutDisplayFunc(renderScene); glutReshapeFunc(changeSize); glutIdleFunc(renderScene); // наши новые функции glutKeyboardFunc(processNormalKeys); glutSpecialFunc(processSpecialKeys); // основной цикл glutMainLoop(); return 1; }
CTRL, ALT, SHIFT
Иногда требуется знать, какая клавиша модификатор, т.е. CTRL, ALT или SHIFT нажата. GLUT предоставляет функцию, которая обнаруживает нажатие данных клавиш. Эта функция должна вызываться только внутри обработки процессов клавиатуры или мыши. Синтаксис для этой функции:
int glutGetModifiers(void);
Возвращаемое значение этой функции является либо одним из трех предопределенных констант (в glut.h) или любая их комбинация. Константы:
GLUT_ACTIVE_SHIFT - Нажаты клавиши Shift или Caps Lock. Если они зажаты вместе, то константа не устанавливается.
GLUT_ACTIVE_CTRL - Нажата клавиша CTRL.
GLUT_ACTIVE_ALT - Нажата клавиша Alt.
Предположим, что вы хотите, чтобы переменная red была 0.0, когда пользователь нажимает "r" и 1.0, когда пользователь нажимает Alt + r.
Следующий фрагмент кода будет обрабатывать данную комбинация нажатий:
void processNormalKeys(unsigned char key, int x, int y) { if (key == 27) exit(0); 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> #include <glut.h> // инициализация переменных цвета в 1.0 // треугольник - белый float red=1.0f, blue=1.0f, green=1.0f; // угол поворота float angle = 0.0f; void changeSize(int w, int h) { // предотвращение деления на ноль if (h == 0) h = 1; float ratio = w * 1.0 / h; // используем матрицу проекции glMatrixMode(GL_PROJECTION); // обнуляем матрицу glLoadIdentity(); // установить параметры вьюпорта glViewport(0, 0, w, h); // установить корректную перспективу gluPerspective(45.0f, ratio, 0.1f, 100.0f); // вернуться к матрице проекции glMatrixMode(GL_MODELVIEW); } void renderScene(void) { // очистить буфер цвета и глубины. glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // обнулить трансформацию glLoadIdentity(); // установить камеру 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( 0.0f, 2.0f, 0.0); glVertex3f( 2.0f,-2.0f, 0.0); glEnd(); angle+=0.1f; glutSwapBuffers(); } void processNormalKeys(unsigned char key, int x, int y) { if (key == 27) exit(0); } 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) { // инициализация glutInit(&argc, argv); glutInitDisplayMode(GLUT_DEPTH | GLUT_DOUBLE | GLUT_RGBA); glutInitWindowPosition(100,100); glutInitWindowSize(400,400); glutCreateWindow("Урок 4"); // регистрация glutDisplayFunc(renderScene); glutReshapeFunc(changeSize); glutIdleFunc(renderScene); // наши новые функции glutKeyboardFunc(processNormalKeys); glutSpecialFunc(processSpecialKeys); // основной цикл glutMainLoop(); return 1; }
Результаты работы программы с обработкой клавиш смены цвета.