Qt 4.8
qbbvirtualkeyboardpps.cpp
Go to the documentation of this file.
1 /****************************************************************************
2 **
3 ** Copyright (C) 2011 - 2012 Research In Motion <blackberry-qt@qnx.com>
4 ** Contact: http://www.qt-project.org/legal
5 **
6 ** This file is part of the QtCore module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and Digia. For licensing terms and
14 ** conditions see http://qt.digia.com/licensing. For further information
15 ** use the contact form at http://qt.digia.com/contact-us.
16 **
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 2.1 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL included in the
21 ** packaging of this file. Please review the following information to
22 ** ensure the GNU Lesser General Public License version 2.1 requirements
23 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
24 **
25 ** In addition, as a special exception, Digia gives you certain additional
26 ** rights. These rights are described in the Digia Qt LGPL Exception
27 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
28 **
29 ** GNU General Public License Usage
30 ** Alternatively, this file may be used under the terms of the GNU
31 ** General Public License version 3.0 as published by the Free Software
32 ** Foundation and appearing in the file LICENSE.GPL included in the
33 ** packaging of this file. Please review the following information to
34 ** ensure the GNU General Public License version 3.0 requirements will be
35 ** met: http://www.gnu.org/copyleft/gpl.html.
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41 
42 //#define QBBVIRTUALKEYBOARD_DEBUG
43 
44 #include "qbbvirtualkeyboardpps.h"
45 
46 #include <QDebug>
47 #include <QSocketNotifier>
48 #include <QtCore/private/qcore_unix_p.h>
49 #include <QtGui/QApplication>
50 #include <QtGui/QPlatformScreen>
51 #include <QtGui/QPlatformWindow>
52 
53 #include <errno.h>
54 #include <fcntl.h>
55 #include <stdlib.h>
56 #include <string.h>
57 #include <sys/iomsg.h>
58 #include <sys/pps.h>
59 #include <sys/stat.h>
60 #include <sys/types.h>
61 #include <unistd.h>
62 
63 
65 
66 const char *QBBVirtualKeyboardPps::sPPSPath = "/pps/services/input/control";
67 const size_t QBBVirtualKeyboardPps::sBufferSize = 2048;
68 
69 // Huge hack for keyboard shadow (see QNX PR 88400). Should be removed ASAP.
70 #define KEYBOARD_SHADOW_HEIGHT 8
71 
73  : mEncoder(0),
74  mDecoder(0),
75  mBuffer(0),
76  mFd(-1),
77  mReadNotifier(0)
78 {
79 }
80 
82 {
83  close();
84 }
85 
87 {
88 #ifdef QBBVIRTUALKEYBOARD_DEBUG
89  qDebug() << "QBB: starting keyboard event processing";
90 #endif
91 
92  if (!connect())
93  return;
94 }
95 
97 {
99 }
100 
102 {
103  delete mReadNotifier;
104  mReadNotifier = 0;
105 
106  if (mFd != -1) {
107  // any reads will fail after we close the fd, which is basically what we want.
108  ::close(mFd);
109  mFd = -1;
110  }
111 
112  if (mDecoder) {
113  pps_decoder_cleanup(mDecoder);
114  delete mDecoder;
115  mDecoder = 0;
116  }
117 
118  if (mEncoder) {
119  pps_encoder_cleanup(mEncoder);
120  delete mEncoder;
121  mEncoder = 0;
122  }
123 
124  delete [] mBuffer;
125  mBuffer = 0;
126 }
127 
129 {
130  close();
131 
132  mEncoder = new pps_encoder_t;
133  mDecoder = new pps_decoder_t;
134 
135  pps_encoder_initialize(mEncoder, false);
136  pps_decoder_initialize(mDecoder, NULL);
137 
138  errno = 0;
140  if (mFd == -1) {
141  qCritical("QBBVirtualKeyboard: Unable to open \"%s\" for keyboard: %s (%d).",
142  sPPSPath, strerror(errno), errno);
143  close();
144  return false;
145  }
146 
147  mBuffer = new char[sBufferSize];
148  if (!mBuffer) {
149  qCritical("QBBVirtualKeyboard: Unable to allocate buffer of %d bytes. Size is unavailable.", sBufferSize);
150  return false;
151  }
152 
153  if (!queryPPSInfo())
154  return false;
155 
157  QObject::connect(mReadNotifier, SIGNAL(activated(int)), this, SLOT(ppsDataReady()));
158 
159  return true;
160 }
161 
163 {
164  // Request info, requires id to regenerate res message.
165  pps_encoder_add_string(mEncoder, "msg", "info");
166  pps_encoder_add_string(mEncoder, "id", "libWebView");
167 
168  if (::write(mFd, pps_encoder_buffer(mEncoder), pps_encoder_length(mEncoder)) == -1) {
169  close();
170  return false;
171  }
172 
173  pps_encoder_reset(mEncoder);
174 
175  return true;
176 }
177 
179 {
180  ssize_t nread = qt_safe_read(mFd, mBuffer, sBufferSize - 1);
181 
182 #ifdef QBBVIRTUALKEYBOARD_DEBUG
183  qDebug() << "QBB: keyboardMessage size: " << nread;
184 #endif
185  if (nread < 0) {
186  connect(); // reconnect
187  return;
188  }
189 
190  // We sometimes get spurious read notifications when no data is available.
191  // Bail out early in this case
192  if (nread == 0)
193  return;
194 
195  // nread is the real space necessary, not the amount read.
196  if (static_cast<size_t>(nread) > sBufferSize - 1) {
197  qCritical("QBBVirtualKeyboard: Keyboard buffer size too short; need %u.", nread + 1);
198  connect(); // reconnect
199  return;
200  }
201 
202  mBuffer[nread] = 0;
203  pps_decoder_parse_pps_str(mDecoder, mBuffer);
204  pps_decoder_push(mDecoder, NULL);
205 #ifdef QBBVIRTUALKEYBOARD_DEBUG
206  pps_decoder_dump_tree(mDecoder, stderr);
207 #endif
208 
209  const char* value;
210  if (pps_decoder_get_string(mDecoder, "error", &value) == PPS_DECODER_OK) {
211  qCritical("QBBVirtualKeyboard: Keyboard PPS decoder error: %s", value ? value : "[null]");
212  return;
213  }
214 
215  if (pps_decoder_get_string(mDecoder, "msg", &value) == PPS_DECODER_OK) {
216  if (strcmp(value, "show") == 0)
217  setVisible(true);
218  else if (strcmp(value, "hide") == 0)
219  setVisible(false);
220  else if (strcmp(value, "info") == 0)
222  else if (strcmp(value, "connect") == 0) { }
223  else
224  qCritical("QBBVirtualKeyboard: Unexpected keyboard PPS msg value: %s", value ? value : "[null]");
225  } else if (pps_decoder_get_string(mDecoder, "res", &value) == PPS_DECODER_OK) {
226  if (strcmp(value, "info") == 0)
228  else
229  qCritical("QBBVirtualKeyboard: Unexpected keyboard PPS res value: %s", value ? value : "[null]");
230  } else {
231  qCritical("QBBVirtualKeyboard: Unexpected keyboard PPS message type");
232  }
233 }
234 
236 {
237  int newHeight = 0;
238  const char* value;
239 
240  if (pps_decoder_push(mDecoder, "dat") != PPS_DECODER_OK) {
241  qCritical("QBBVirtualKeyboard: Keyboard PPS dat object not found");
242  return;
243  }
244  if (pps_decoder_get_int(mDecoder, "size", &newHeight) != PPS_DECODER_OK) {
245  qCritical("QBBVirtualKeyboard: Keyboard PPS size field not found");
246  return;
247  }
248  if (pps_decoder_push(mDecoder, "locale") != PPS_DECODER_OK) {
249  qCritical("QBBVirtualKeyboard: Keyboard PPS locale object not found");
250  return;
251  }
252  if (pps_decoder_get_string(mDecoder, "languageId", &value) != PPS_DECODER_OK) {
253  qCritical("QBBVirtualKeyboard: Keyboard PPS languageId field not found");
254  return;
255  }
257 
258  if (pps_decoder_get_string(mDecoder, "countryId", &value) != PPS_DECODER_OK) {
259  qCritical("QBBVirtualKeyboard: Keyboard PPS size countryId not found");
260  return;
261  }
263 
264  // HUGE hack, should be removed ASAP.
265  newHeight -= KEYBOARD_SHADOW_HEIGHT; // We want to ignore the 8 pixel shadow above the keyboard. (PR 88400)
266  setHeight(newHeight);
267 
268 #ifdef QBBVIRTUALKEYBOARD_DEBUG
269  qDebug() << "QBB: handleKeyboardInfoMessage size=" << getHeight() << "languageId=" << languageId() << " countryId=" << countryId();
270 #endif
271 }
272 
274 {
275 #ifdef QBBVIRTUALKEYBOARD_DEBUG
276  qDebug() << "QBB: showKeyboard()";
277 #endif
278 
279  // Try to connect.
280  if (mFd == -1 && !connect())
281  return false;
282 
283  // NOTE: This must be done everytime the keyboard is shown even if there is no change because
284  // hiding the keyboard wipes the setting.
286 
287  pps_encoder_reset(mEncoder);
288 
289  // Send the show message.
290  pps_encoder_add_string(mEncoder, "msg", "show");
291 
292  if (::write(mFd, pps_encoder_buffer(mEncoder), pps_encoder_length(mEncoder)) == -1) {
293  close();
294  return false;
295  }
296 
297  pps_encoder_reset(mEncoder);
298 
299  // Return true if no error occurs. Sizing response will be triggered when confirmation of
300  // the change arrives.
301  return true;
302 }
303 
305 {
306 #ifdef QBBVIRTUALKEYBOARD_DEBUG
307  qDebug() << "QBB: hideKeyboard()";
308 #endif
309 
310  if (mFd == -1 && !connect())
311  return false;
312 
313  pps_encoder_add_string(mEncoder, "msg", "hide");
314 
315  if (::write(mFd, pps_encoder_buffer(mEncoder), pps_encoder_length(mEncoder)) == -1) {
316  close();
317 
318  //Try again.
319  if (connect()) {
320  if (::write(mFd, pps_encoder_buffer(mEncoder), pps_encoder_length(mEncoder)) == -1) {
321  close();
322  return false;
323  }
324  } else {
325  return false;
326  }
327  }
328 
329  pps_encoder_reset(mEncoder);
330 
331  // Return true if no error occurs. Sizing response will be triggered when confirmation of
332  // the change arrives.
333  return true;
334 }
335 
337 {
338  // Try to connect.
339  if (mFd == -1 && !connect())
340  return;
341 
342  // Send the options message.
343  pps_encoder_add_string(mEncoder, "msg", "options");
344 
345  pps_encoder_start_object(mEncoder, "dat");
346  switch (mode) {
347  case Url:
349  break;
350  case Email:
352  break;
353  case Web:
355  break;
356  case NumPunc:
358  break;
359  case Symbol:
361  break;
362  case Phone:
364  break;
365  case Pin:
367  break;
368  case Default: // fall through
369  default:
371  break;
372  }
373 
374  pps_encoder_end_object(mEncoder);
375 
376  if (::write(mFd, pps_encoder_buffer(mEncoder), pps_encoder_length(mEncoder)) == -1)
377  close();
378 
379  pps_encoder_reset(mEncoder);
380 }
381 
383 {
384  pps_encoder_add_string(mEncoder, "enter", "enter.default");
385  pps_encoder_add_string(mEncoder, "type", "default");
386 }
387 
389 {
390  pps_encoder_add_string(mEncoder, "enter", "enter.default");
391  pps_encoder_add_string(mEncoder, "type", "url");
392 }
393 
395 {
396  pps_encoder_add_string(mEncoder, "enter", "enter.default");
397  pps_encoder_add_string(mEncoder, "type", "email");
398 }
399 
401 {
402  pps_encoder_add_string(mEncoder, "enter", "enter.default");
403  pps_encoder_add_string(mEncoder, "type", "web");
404 }
405 
407 {
408  pps_encoder_add_string(mEncoder, "enter", "enter.default");
409  pps_encoder_add_string(mEncoder, "type", "numPunc");
410 }
411 
413 {
414  pps_encoder_add_string(mEncoder, "enter", "enter.default");
415  pps_encoder_add_string(mEncoder, "type", "phone");
416 }
417 
419 {
420  pps_encoder_add_string(mEncoder, "enter", "enter.default");
421  pps_encoder_add_string(mEncoder, "type", "pin");
422 }
423 
425 {
426  pps_encoder_add_string(mEncoder, "enter", "enter.default");
427  pps_encoder_add_string(mEncoder, "type", "symbol");
428 }
429 
void setLanguage(const QString &language)
#define QT_END_NAMESPACE
This macro expands to.
Definition: qglobal.h:90
void applyKeyboardMode(KeyboardMode mode)
#define SLOT(a)
Definition: qobjectdefs.h:226
void setCountry(const QString &country)
QSocketNotifier * mReadNotifier
The QSocketNotifier class provides support for monitoring activity on a file descriptor.
Q_CORE_EXPORT void qDebug(const char *,...)
#define SIGNAL(a)
Definition: qobjectdefs.h:227
#define QT_BEGIN_NAMESPACE
This macro expands to.
Definition: qglobal.h:89
static bool connect(const QObject *sender, const char *signal, const QObject *receiver, const char *member, Qt::ConnectionType=Qt::AutoConnection)
Creates a connection of the given type from the signal in the sender object to the method in the rece...
Definition: qobject.cpp:2580
void applyKeyboardModeOptions(KeyboardMode mode)
static QString fromLatin1(const char *, int size=-1)
Returns a QString initialized with the first size characters of the Latin-1 string str...
Definition: qstring.cpp:4188
static const char * sPPSPath
static const size_t sBufferSize
#define KEYBOARD_SHADOW_HEIGHT
#define O_RDWR
Q_CORE_EXPORT void qCritical(const char *,...)
int open(const char *, int,...)
static qint64 qt_safe_read(int fd, void *data, qint64 maxlen)
Definition: qcore_unix_p.h:273
int errno