4 #include <X11/extensions/XInput2.h>
19 virtual void render (Display*, Window&, GC&) = 0;
22 class TextRenderable : public Renderable {
25 int color; // text color
26 std::string text; // what to render
27 //bool centered; // render centered // TODO
29 TextRenderable (int posx, int posy, int textcolor, const char * message)
30 : x(posx), y(posy), color(textcolor), text(message) {}
32 virtual void render (Display * dpy, Window & w, GC & gc) {
33 XSetForeground(dpy, gc, color);
34 XDrawString(dpy, w, gc, x, y, text.c_str(), text.length());
42 TextRenderable * textField;
47 Player () : name(), isReady(false), indexToType(0), score(0) {}
51 void associateTextField (TextRenderable * t) {
54 void nameInput (const char * input) {
57 if (strlen(input) == 1) {
58 textField->text.append(input);
59 } else if (strcmp (input, "Return") == 0) {
60 name = textField->text;
62 textField->text.append(" READY");
63 } else if (strcmp (input, "BackSpace") == 0 && name.length() > 0) {
64 textField->text.erase (textField->text.length()-1);
67 // returns if player has just finished the word
68 bool input (const char * input, const std::string & currentWord) {
69 if (strlen(input) == 1 && currentWord[indexToType] == input[0] && !isReady) {
70 assert (textField != NULL);
71 assert (indexToType >= 0);
72 textField->text.push_back(input[0]);
74 if (currentWord.length() == (unsigned int)indexToType) { // done
76 textField->text.erase();
84 textField->text.erase();
87 void addScore (int toAdd) {
97 const char * getName () {
102 void clearScreen (Display *d, Window& window, GC& gc, int color) {
103 XSetForeground (d, gc, color);
104 unsigned int width,height; // TODO: nicht jedes mal die query machen
105 unsigned int dummyu; int dummyi; Window dummyw;
106 XGetGeometry(d, window, &dummyw, &dummyi, &dummyi, &width, &height, &dummyu, &dummyu);
107 XFillRectangle (d, window, gc, 0, 0, width, height);
110 void render (Display *d, Window& window, GC& gc, int bgcolor, std::vector < Renderable* > & toRender) {
111 clearScreen (d, window, gc, bgcolor);
112 for (size_t i=0; i<toRender.size(); i++) {
113 toRender[i]->render(d, window, gc);
118 int getColorExact (Display *d, int r, int g, int b) {
119 int screen = DefaultScreen(d);
120 Colormap cmap = DefaultColormap(d,screen);
122 if (r > 65535) r = 65535;
123 if (g > 65535) g = 65535;
124 if (b > 65535) b = 65535;
127 c.red = r; c.green = g; c.blue = b;
129 if (XAllocColor(d, cmap, &c)) {
130 if (c.red != r || c.green != g || c.blue != b) {
131 fprintf (stderr, "(%d,%d,%d) -> (%d,%d,%d)\n", r, g, b, c.red, c.green, c.blue);
135 fprintf (stderr, "Warning: couldn't allocate color %d %d %d\n", r, g, b);
136 return BlackPixel(d,screen);
140 int getColor (Display *d, int r, int g, int b) {
142 return getColorExact (d, r*257, g*257, b*257);
145 std::string getNextWord (bool * isWord_return) {
147 std::getline (std::cin, ret);
148 *isWord_return = !std::cin.eof();
152 int main (int argc, char** argv) {
153 /* Connect to the X server */
154 Display *dpy = XOpenDisplay(NULL);
156 fprintf (stderr, "XOpenDisplay returned no display to display what is to display. Aborting.\n");
160 /* XInput Extension available? */
161 int opcode, event, error;
162 if (!XQueryExtension(dpy, "XInputExtension", &opcode, &event, &error)) {
163 printf("X Input extension not available.\n");
167 /* Which version of XI2? We support 2.0 */
168 int major = 2, minor = 0;
169 if (XIQueryVersion(dpy, &major, &minor) == BadRequest) {
170 printf("XI2 not available. Server supports %d.%d\n", major, minor);
174 printf ("system is sane.\n");
177 int blackColor = BlackPixel(dpy, DefaultScreen(dpy));
178 int whiteColor = WhitePixel(dpy, DefaultScreen(dpy));
182 TextRenderable playerTextFields [] = {
183 TextRenderable(0, 200, getColor (dpy, 255, 220, 32), ""),
184 TextRenderable(0, 300, getColor (dpy, 32, 128, 255), ""),
185 TextRenderable(0, 400, getColor (dpy, 64, 255, 0), ""),
186 TextRenderable(0, 500, getColor (dpy, 255, 0, 64), "")
190 Window w = XCreateSimpleWindow(dpy, DefaultRootWindow(dpy), 0, 0, 800, 600, 0, blackColor, blackColor);
192 // which events we want?
193 XSelectInput(dpy, w, StructureNotifyMask);
195 // put window on the screen
198 // create graphics context
199 GC gc = XCreateGC(dpy, w, 0, NULL);
201 // wait for MapNotify
205 if (e.type == MapNotify)
209 // Now let's listen to keypress events
210 XIEventMask eventmask;
211 unsigned char mask [1] = { 0 }; // will change
212 eventmask.deviceid = XIAllMasterDevices;
213 eventmask.mask_len = sizeof (mask); // in bytes, for whatever reason...
214 eventmask.mask = mask;
215 XISetMask(mask, XI_KeyPress);
216 XISelectEvents (dpy, w, &eventmask, 1);
217 XSelectInput (dpy, w, ExposureMask);
219 // setup player data structures
220 std::map < int , Player* > kbd2player;
221 std::vector< Player* > players;
223 // setup rendering stuff
224 std::vector< Renderable* > toRender;
225 for (int i = 0; i < maxplayers; i++)
226 toRender.push_back (playerTextFields+i);
227 TextRenderable mainTextField (50, 50, whiteColor, "Please type your name and then hit Return.");
228 toRender.push_back (&mainTextField);
230 bool allReady = false;
232 render(dpy, w, gc, blackColor, toRender);
234 XNextEvent(dpy, &ev);
235 if (ev.xcookie.type == GenericEvent && ev.xcookie.extension == opcode
236 && ev.xcookie.evtype == XI_KeyPress && XGetEventData(dpy, &ev.xcookie)) {
237 XIDeviceEvent *d_ev = (XIDeviceEvent*) ev.xcookie.data;
238 KeyCode keycode = d_ev->detail;
239 int kbdid = d_ev->deviceid;
240 if (!(d_ev->flags & XIKeyRepeat)) {
241 int keysyms_per_keycode;
242 //KeySym *keysym = XGetKeyboardMapping (dpy, keycode, 1, &keysyms_per_keycode);
243 KeySym keysym = XGetKeyboardMapping (dpy, keycode, 1, &keysyms_per_keycode)[0];
244 Player * eventPlayer;
245 if (kbd2player.count(kbdid) == 0) { // add player
246 if (nplayers == maxplayers) {
247 fprintf (stderr, "zu viele Spieler, TODO: gescheites error handling. Bye ;-)\n");
250 eventPlayer = new Player ();
251 eventPlayer->associateTextField (playerTextFields+nplayers);
253 players.push_back(eventPlayer);
254 kbd2player[kbdid] = eventPlayer;
255 } else { // player already there
256 eventPlayer = kbd2player[kbdid];
258 //debug out: mainTextField.text.append (XKeysymToString (keysym[0]));
259 eventPlayer->nameInput (XKeysymToString (keysym));
262 XFreeEventData(dpy, &ev.xcookie);
263 if (keycode == 9) {// Escape Key
264 printf ("you escaped successfully.\n");
267 } else if (ev.type == Expose) {
268 printf ("exposeevent\n");
270 printf ("other event\n");
273 if (!players.empty()) {
275 for (size_t i=0; i<players.size() && allReady; i++) {
276 allReady &= players[i]->getReady();
281 for (size_t i=0; i<players.size() && allReady; i++) {
282 players[i]->clearText();
283 players[i]->unsetReady();
284 } // readyflag will now be used for if they are already done with a word
286 int notreadyplayers = 0;
290 assert (notreadyplayers >= 0);
291 if (notreadyplayers == 0 || (notreadyplayers==1 && players.size()>1)) {
293 theWord = getNextWord(&gotWord);
296 mainTextField.text = theWord;
297 notreadyplayers = players.size();
298 for (size_t i=0; i<players.size() && allReady; i++) {
299 players[i]->unsetReady();
300 players[i]->clearText();
301 printf ("cleared text\n");
304 render(dpy, w, gc, blackColor, toRender);
306 XNextEvent(dpy, &ev);
307 if (ev.xcookie.type == GenericEvent && ev.xcookie.extension == opcode
308 && ev.xcookie.evtype == XI_KeyPress && XGetEventData(dpy, &ev.xcookie)) {
309 XIDeviceEvent *d_ev = (XIDeviceEvent*) ev.xcookie.data;
310 KeyCode keycode = d_ev->detail;
311 int kbdid = d_ev->deviceid;
312 if (!(d_ev->flags & XIKeyRepeat)) {
313 printf ("got key event\n");
314 int keysyms_per_keycode;
315 //KeySym *keysym = XGetKeyboardMapping (dpy, keycode, 1, &keysyms_per_keycode);
316 KeySym keysym = XGetKeyboardMapping (dpy, keycode, 1, &keysyms_per_keycode)[0];
317 Player * eventPlayer;
318 if (kbd2player.count(kbdid) == 0) { // add player
319 printf ("you can't join in a match\n");
321 /*if (nplayers == maxplayers) {
322 fprintf (stderr, "zu viele Spieler, TODO: gescheites error handling. Bye ;-)\n");
325 eventPlayer = new Player ();
326 eventPlayer->associateTextField (playerTextFields+nplayers);
328 players.push_back(eventPlayer);
329 kbd2player[srcid] = eventPlayer; */
330 } else { // player already there
331 eventPlayer = kbd2player[kbdid];
333 //debug out: mainTextField.text.append (XKeysymToString (keysym[0]));
334 bool pfinished = eventPlayer->input (XKeysymToString (keysym), theWord);
337 eventPlayer->addScore (notreadyplayers);
338 printf ("score of %d added\n", notreadyplayers);
342 XFreeEventData(dpy, &ev.xcookie);
343 if (keycode == 9) {// Escape Key
344 printf ("you escaped successfully.\n");
347 } else if (ev.type == Expose) {
348 printf ("exposeevent\n");
350 printf ("other event\n");
355 for (size_t i=0; i<players.size(); i++) {
356 std::stringstream msg;
357 msg << "player " << players[i]->getName() << " has " << players[i]->getScore() << " points." << std::endl;
358 std::cout << msg.str();
359 playerTextFields[i].text = msg.str();
361 render(dpy, w, gc, blackColor, toRender);