2 vkeyb - camera motion detection virtual keyboard
3 Copyright (C) 2012 Eleni Maria Stea <elene.mst@gmail.com>
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation, either version 3 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
31 #include <opencv2/opencv.hpp>
39 int create_window(int xsz, int ysz);
41 void show_frame(float frm_width);
42 int handle_event(XEvent *xev);
43 void reshape(int w, int h);
44 void keyb(int key, int pressed);
45 void send_key(KeySym key);
46 void motion(int x, int y);
47 void cam_motion(double orient);
48 void button(int x, int y, int bn, int state);
49 void activate(int enter);
51 Display *dpy; /* X11 display structure (x server connection) */
52 Window win; /* X window */
53 GLXContext ctx; /* OpenGL context */
63 static double orient = 0.0;
66 int main (int argc, char** argv)
68 glutInit(&argc, argv);
75 glEnable(GL_CULL_FACE);
82 //retreive the X server socket
83 int xsock = ConnectionNumber(dpy);
84 FD_SET(xsock, &fdset);
85 FD_SET(pipefd[0], &fdset);
87 int maxfd = (xsock > pipefd[0] ? xsock : pipefd[0]) + 1;
88 select(maxfd, &fdset, 0, 0, 0);
90 if(FD_ISSET(pipefd[0], &fdset)) {
91 // process all pending events ...
92 while(XPending(dpy)) {
94 XNextEvent(dpy, &xev);
99 if(FD_ISSET(pipefd[0], &fdset)) {
100 if(read(pipefd[0], &orient, sizeof orient) < (int)sizeof orient) {
101 fprintf(stderr, "read from pipe failed\n");
104 glBindTexture(GL_TEXTURE_2D, frm_tex);
106 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, frm.cols, frm.rows, 0, GL_BGR, GL_UNSIGNED_BYTE, frm.data);
110 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, frm.cols, frm.rows, GL_BGR, GL_UNSIGNED_BYTE, frm.data);
118 // ... and then do a single redisplay if needed
134 if(!(dpy = XOpenDisplay(0))) {
135 fprintf(stderr, "failed to connect to the X server\n");
138 scr = ScreenOfDisplay(dpy, DefaultScreen(dpy));
140 width = WidthOfScreen(scr);
143 if(create_window(width, height) == -1) {
147 XMoveWindow(dpy, win, 0, HeightOfScreen(scr) - height);
153 fprintf(stderr, "failed to initialize virtual keyboard\n");
157 // register a passive grab
158 Window root = RootWindow(dpy, DefaultScreen(dpy));
159 XGrabKey(dpy, XKeysymToKeycode(dpy, 'e'), ControlMask, root, False, GrabModeAsync, GrabModeAsync);
162 glGenTextures(1, &frm_tex);
163 glBindTexture(GL_TEXTURE_2D, frm_tex);
164 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
165 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
166 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
167 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
169 // start the capturing thread
178 glXMakeCurrent(dpy, None, 0);
179 glXDestroyContext(dpy, ctx);
180 XDestroyWindow(dpy, win);
184 int create_window(int xsz, int ysz)
188 XSetWindowAttributes xattr;
190 unsigned int attr_valid;
203 scr = DefaultScreen(dpy);
204 root = RootWindow(dpy, scr);
206 if(!(vis = glXChooseVisual(dpy, scr, glattr))) {
207 fprintf(stderr, "failed to find a suitable visual\n");
211 if(!(ctx = glXCreateContext(dpy, vis, 0, True))) {
212 fprintf(stderr, "failed to create OpenGL context\n");
217 xattr.background_pixel = xattr.border_pixel = BlackPixel(dpy, scr);
218 xattr.colormap = XCreateColormap(dpy, root, vis->visual, AllocNone);
219 xattr.override_redirect = True;
220 attr_valid = CWColormap | CWBackPixel | CWBorderPixel | CWOverrideRedirect;
222 if(!(win = XCreateWindow(dpy, root, 0, 0, xsz, ysz, 0, vis->depth, InputOutput,
223 vis->visual, attr_valid, &xattr))) {
224 fprintf(stderr, "failed to create X window\n");
225 glXDestroyContext(dpy, ctx);
231 evmask = StructureNotifyMask | VisibilityChangeMask | KeyPressMask | PointerMotionMask |
232 ButtonPressMask | ButtonReleaseMask | ExposureMask | EnterWindowMask | LeaveWindowMask;
233 XSelectInput(dpy, win, evmask);
235 XMapWindow(dpy, win);
237 glXMakeCurrent(dpy, win, ctx);
244 glClearColor(1, 0, 0, 0);
245 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
246 glMatrixMode(GL_MODELVIEW);
252 glRasterPos2i(-1, -1);
255 snprintf(buf, sizeof buf, "%f %s", orient, orient > 0 ? "->" : orient < 0 ? "<-" : " ");
258 glutBitmapCharacter(GLUT_BITMAP_HELVETICA_18, *ptr++);
261 glXSwapBuffers(dpy, win);
264 assert(glGetError() == GL_NO_ERROR);
267 void show_frame(float frm_width)
271 glEnable(GL_TEXTURE_2D);
272 glBindTexture(GL_TEXTURE_2D, frm_tex);
275 glColor3f(1.0, 1.0, 1.0);
276 glTexCoord2f(0, 1); glVertex2f(-1, -1);
277 glTexCoord2f(1, 1); glVertex2f(frm_width - 1, -1);
278 glTexCoord2f(1, 0); glVertex2f(frm_width - 1, 1);
279 glTexCoord2f(0, 0); glVertex2f(-1, 1);
282 glDisable(GL_TEXTURE_2D);
286 int handle_event(XEvent *xev)
292 case ConfigureNotify:
293 reshape(xev->xconfigure.width, xev->xconfigure.height);
304 if(mapped && xev->xexpose.count == 0) {
310 sym = XLookupKeysym(&xev->xkey, 0);
315 motion(xev->xmotion.x, xev->xmotion.y);
319 button(xev->xbutton.x, xev->xbutton.y, xev->xbutton.button, 1);
322 button(xev->xbutton.x, xev->xbutton.y, xev->xbutton.button, 0);
340 void reshape(int w, int h)
342 glViewport(0, 0, w, h);
345 void keyb(int key, int pressed)
356 printf("sending key: %c\n", (char)vkeyb->active_key());
357 send_key(vkeyb->active_key());
363 void send_key(KeySym key)
369 XGetInputFocus(dpy, &win, &junk);
371 memset(&ev, 0, sizeof ev);
373 ev.xkey.window = win;
374 ev.xkey.keycode = XKeysymToKeycode(dpy, key);
376 ev.xkey.time = CurrentTime;
378 XSendEvent(dpy, InputFocus, False, NoEventMask, &ev);
381 static int prev_x = -1;
383 void motion(int x, int y)
389 vkeyb->move((x - prev_x) / 25.0);
395 void cam_motion(double orient)
408 void button(int x, int y, int bn, int state)
410 if(bn == 3 && state) {
416 void activate(int enter)