allow passing words file as argument
[multypo.git] / qt / multypo.cpp
1 #include "multypo.h"
2
3 #include <QX11Info>
4 #include <QDebug>
5 #include <QVBoxLayout>
6 #include <QLabel>
7 #include <QMap>
8
9 #include <X11/Xlib.h>
10 #include <X11/extensions/XInput2.h>
11 #include <X11/Xutil.h>
12
13 MultypoWindow::MultypoWindow(QWidget *parent) :
14         QWidget(parent),
15         xiInited(false),
16         gameStarted(false)
17 {
18         /* Prepare colors */
19         setStyleSheet("background-color: black; color: green; font-size: 45pt");
20
21         /* Prepare conents */
22         setLayout(new QVBoxLayout(this));
23
24         mainLabel = new QLabel("Namen eingeben, dann Return", this);
25         layout()->addWidget(mainLabel);
26
27         /* Fullscreen, no cursor */
28         setWindowState(Qt::WindowFullScreen);
29         setCursor(QCursor(Qt::BlankCursor));
30
31         words.open(stdin,QIODevice::ReadOnly);
32
33         typingPlayers = 0;
34 }
35
36 MultypoWindow::~MultypoWindow()
37 {
38 }
39
40 void MultypoWindow::resetPlayerText() {
41         for (QMap<int, Player*>::Iterator it = players.begin(); it != players.end(); ++it) {
42                 it.value()->resetText();
43         }
44 }
45
46 void MultypoWindow::nextWord() {
47         QByteArray tmp = words.readLine().trimmed();
48         QString word = QString::fromUtf8(tmp);
49         qDebug() << "New word" << word;
50         if (word.isEmpty()) { // game over
51                 mainLabel->setText("GAME OVER");
52                 for (QMap<int, Player*>::Iterator it = players.begin(); it != players.end(); ++it) {
53                         QString tmp = QString ("Spieler %1 hat %2 Punkte.").arg(it.value()->getName()).arg(it.value()->score);
54                         it.value()->setWaiting(tmp);
55                 }
56         } else {
57                 resetPlayerText();
58                 mainLabel->setText(word);
59                 typingPlayers = players.size();
60         }
61 }
62
63 void MultypoWindow::handleKeyPress(int device, QString string)
64 {
65         qDebug() << "Device" << device << "String" << string;
66
67         if (string == "Escape") {
68                 close();
69                 return;
70         }
71
72         if (!players.contains(device)) {
73                 if (gameStarted)
74                         return;
75                 players[device] = new Player(this);
76         }
77         bool newChar = players[device]->handleKey(string);
78
79         if (gameStarted) { // ingame
80                 qDebug() << "current player line" << players[device]->getCurrentLine();
81                 qDebug() << "current word" << mainLabel->text();
82                 if (newChar && players[device]->getCurrentLine() == mainLabel->text()) {
83                         players[device]->score += typingPlayers;
84                         QString readyString = QString("READY: %1 points").arg(typingPlayers);
85                         players[device]->setWaiting(readyString);
86                         qDebug() << "typingPlayers " << typingPlayers;
87                         typingPlayers--;
88                         qDebug() << "typingPlayers " << typingPlayers;
89                         if (typingPlayers <= 0) {
90                                 nextWord();
91                         }
92                 }
93         } else { // name entering phase
94                 qDebug() << "checking for game started";
95                 bool allHaveNames = true;
96                 for (QMap<int, Player*>::Iterator it = players.begin(); it != players.end(); ++it) {
97                         if (! it.value()->hasName()) {
98                                 allHaveNames = false;
99                                 break;
100                         }
101                 }
102                 qDebug() << "Players empty?" << players.empty() << "All have names?" << allHaveNames;
103                 if (!players.empty() && allHaveNames) {
104                         gameStarted = true;
105                         nextWord();
106                 }
107         }
108 }
109
110 bool MultypoWindow::handleX11Event(XEvent *event)
111 {
112         Display *dpy = x11Info().display();
113         /* Handle the first map event: We are finally visible! */
114         if (!xiInited && event->type == MapNotify) {
115                 /* XInput Extension available? */
116                 int eventID, errorID;
117                 if (!XQueryExtension(dpy, "XInputExtension", &xiOpcode, &eventID, &errorID)) {
118                    qCritical() << "X Input extension not available";
119                 }
120
121                 /* Which version of XI2? We support 2.0 */
122                 int major = 2, minor = 1;
123                 if (XIQueryVersion(dpy, &major, &minor) == BadRequest) {
124                         qCritical() << "XI2 not available. Server supports" << major << "." <<
125                                                 minor;
126                 }
127
128                 qDebug() << "System supports XI2";
129
130
131                 // Now let's listen to keypress events
132                 XIEventMask eventmask;
133                 unsigned char mask [1] = { 0 }; // will change
134                 eventmask.deviceid = XIAllMasterDevices;
135                 eventmask.mask_len = sizeof (mask); // in bytes, for whatever reason...
136                 eventmask.mask = mask;
137                 XISetMask(mask, XI_KeyPress);
138                 XISelectEvents (dpy, winId(), &eventmask, 1);
139
140                 // finally, grab all focuses
141                 int ndevices;
142                 XIDeviceInfo* devices = XIQueryDevice(dpy, XIAllMasterDevices, &ndevices);
143                 for (int i = 0; i < ndevices; ++i) {
144                         if (devices[i].use != XIMasterKeyboard) continue;
145                         qDebug() << "Found master keyboard with ID" << devices[i].deviceid;
146                         XISetFocus(dpy, devices[i].deviceid, winId(), CurrentTime);
147                 }
148                 XIFreeDeviceInfo(devices);
149
150                 xiInited = true;
151
152                 return false;
153         }
154         else if (xiInited && event->type == GenericEvent
155                 && event->xcookie.type == GenericEvent && event->xcookie.extension == xiOpcode
156                 && event->xcookie.evtype == XI_KeyPress) { 
157                 
158                 if (XGetEventData(dpy, &event->xcookie) != True) {
159                         qCritical() << "Error getting event data";
160                         // FIXME return true;
161                 }
162                 
163                 /* Handle XI event */
164                 XIDeviceEvent *d_ev = (XIDeviceEvent*) event->xcookie.data;
165             KeyCode keycode = d_ev->detail;
166             int kbdid = d_ev->deviceid;
167
168                 if (!(d_ev->flags & XIKeyRepeat)) {
169                         int keysyms_per_keycode;
170                         KeySym keysym = XGetKeyboardMapping (dpy, keycode, 1, &keysyms_per_keycode)[0];
171                         handleKeyPress(kbdid, XKeysymToString(keysym));
172                 }
173
174                 XFreeEventData(dpy, &event->xcookie);
175
176                 return true;
177         }
178         else {
179                 return false;
180         }
181 }