1 #include "keyboard.h"
2 #include <QPushButton>
3 #include <QSignalMapper>
4 #include <QHBoxLayout>
5 #include <QVBoxLayout>
6 #include <QGridLayout>
7 #include<QCoreApplication>
8 #include <QMap>
9 #include <QKeyEvent>
10 #include <QPainter>
11 #include <QLineEdit>
12 #include <QDebug>
13 #include <QApplication>
14 #include <QTimer>
15 #include <QDebug>
16 #include <QLineEdit>
17 #include <QLabel>
18 #include <QListView>
19 #include "pinyindecoderservice.h"
20 #include "pinyinime.h"
21 #include "keybutton.h"
22 #include "pinyinbar.h"
23 #include <QLoggingCategory>
24 #include <QMouseEvent>
25 Q_LOGGING_CATEGORY(flapp, "app.keyboard")
26 using namespace ime_pinyin;
27 using namespace QtVirtualKeyboard;
28
Keyboard(QWidget * parent)29 Keyboard::Keyboard(QWidget *parent) :
30 QWidget(parent),
31 m_inputWidget(Q_NULLPTR),
32 m_candidates(0),
33 m_number(0),
34 m_type(0),
35 m_shift(false),
36 m_upper(false)
37 {
38 qApp->setStyle("Fusion");
39 ;
40 setAttribute(Qt::WA_AlwaysStackOnTop);
41 setWindowFlags(Qt::WindowDoesNotAcceptFocus);
42 this->setWindowFlags(Qt::Tool);
43
44 //设置背景颜色.
45 this->setAutoFillBackground(true);
46 QPalette palette = this->palette();
47 palette.setBrush(QPalette::Background, QColor(242, 242, 242));
48 this->setPalette(palette);
49
50 QFont f;
51 f.setPixelSize(18);
52 this->setFont(f);
53
54 createKeys();
55
56 resetKey();
57
58 PinyinDecoderService::getInstance()->resetSearch();
59
60 QApplication *a = dynamic_cast<QApplication*>(QCoreApplication::instance());
61 a->installEventFilter(this);
62 connect(a, &QApplication::focusChanged, this, &Keyboard::foucsChange);
63 }
64
~Keyboard()65 Keyboard::~Keyboard()
66 {
67
68 }
69
createKeys()70 void Keyboard::createKeys()
71 {
72 m_type = 0;
73 m_shift= 0;
74
75 QVBoxLayout *pVLayout = new QVBoxLayout(this);
76 pVLayout->setContentsMargins(10, 0, 10, 0);
77 pVLayout->setSpacing(0);
78 auto createButtons =[=](QVBoxLayout*pVLayout, int n){
79 QHBoxLayout *pHLayout = new QHBoxLayout;
80 pHLayout->setSpacing(0);
81 for(int i=0; i<n; i++){
82 KeyButton *button = new KeyButton;
83 connect(button, &KeyButton::clicked, this, &Keyboard::handleKey);
84 pHLayout->addWidget(button);
85 m_buttons << button;
86 }
87 pVLayout->addLayout(pHLayout);
88 };
89
90 QHBoxLayout *pHLayout = new QHBoxLayout;
91 pHLayout->setContentsMargins(10, 0, 10,0);
92 m_bar = new PinyinBar;
93 connect(m_bar, &PinyinBar::textChose, this, &Keyboard::textChose);
94 pHLayout->addWidget(m_bar);
95 pVLayout->addLayout(pHLayout);
96
97 createButtons(pVLayout, 14);//第一行.
98 createButtons(pVLayout, 14); //第二行.
99 createButtons(pVLayout, 13);//第三行.
100 createButtons(pVLayout, 13);//第四行.
101 }
102
resetKey()103 void Keyboard::resetKey()
104 { //正常键盘显示.
105 static Qt::Key key[2][54] ={Qt::Key_QuoteLeft, Qt::Key_1, Qt::Key_2,Qt::Key_3,Qt::Key_4,Qt::Key_5,Qt::Key_6,Qt::Key_7,Qt::Key_8,Qt::Key_9, Qt::Key_0,
106 Qt::Key_Underscore, Qt::Key_Equal, Qt::Key_Backspace,//14 //第一行.
107
108 Qt::Key_Q, Qt::Key_W,Qt::Key_E,Qt::Key_R,Qt::Key_T,Qt::Key_Y,Qt::Key_U,Qt::Key_I,Qt::Key_O, Qt::Key_P,
109 Qt::Key_BracketLeft, Qt::Key_BracketRight, Qt::Key_Return,Qt::Key_Tab,//14 第二行.
110
111 Qt::Key_CapsLock, Qt::Key_A, Qt::Key_S,Qt::Key_D,Qt::Key_F,Qt::Key_G,Qt::Key_H,Qt::Key_J,Qt::Key_K,Qt::Key_L, Qt::Key_Semicolon,
112 Qt::Key_Apostrophe, Qt::Key_QuoteDbl,//13第三行.
113
114 Qt::Key_Shift, Qt::Key_Z, Qt::Key_X,Qt::Key_C,Qt::Key_V,Qt::Key_B,Qt::Key_Space, Qt::Key_N,Qt::Key_M, Qt::Key_Comma ,Qt::Key_Period, Qt::Key_Slash,
115 Qt::Key_Multi_key,//12第四行.
116
117 //shift 按键切换显示.
118 Qt::Key_AsciiTilde, Qt::Key_Exclam, Qt::Key_At, Qt::Key_NumberSign,Qt::Key_Dollar,Qt::Key_Percent,Qt::Key_AsciiCircum,Qt::Key_Ampersand,
119 Qt::Key_Asterisk,Qt::Key_ParenLeft, Qt::Key_ParenRight,
120 Qt::Key_Minus, Qt::Key_Plus, Qt::Key_Backspace, //14第一行.
121
122 Qt::Key_Q, Qt::Key_W,Qt::Key_E,Qt::Key_R,Qt::Key_T,Qt::Key_Y,Qt::Key_U,Qt::Key_I,Qt::Key_O, Qt::Key_P,
123 Qt::Key_BraceLeft, Qt::Key_BraceRight, Qt::Key_Return,Qt::Key_Tab, //14第二行.
124
125 Qt::Key_CapsLock, Qt::Key_A, Qt::Key_S,Qt::Key_D,Qt::Key_F,Qt::Key_G,Qt::Key_H,Qt::Key_J,Qt::Key_K,Qt::Key_L, Qt::Key_Colon,
126 Qt::Key_QuoteDbl, Qt::Key_Bar, //13第三行.
127
128 Qt::Key_Shift, Qt::Key_Z, Qt::Key_X,Qt::Key_C,Qt::Key_V,Qt::Key_B, Qt::Key_Space, Qt::Key_N,Qt::Key_M,Qt::Key_Less,Qt::Key_Greater, Qt::Key_Question,
129 Qt::Key_Multi_key}; //13第四行.
130
131
132 for(int i=0; i<54 && i<m_buttons.size(); i++)
133 {
134 Qt::Key k = key[m_shift][i];
135 m_buttons[i]->setKey(k);
136
137 QString value = getKey(k);
138 m_upper ? value =value.toUpper() :value =value.toLower();
139
140 m_buttons[i]->setValue(value);
141
142 //特殊按键替换处理.
143 switch (k) {
144 case Qt::Key_Return:
145 m_buttons[i]->setValue("↵");
146 break;
147
148 case Qt::Key_Space:
149 m_buttons[i]->setMinimumWidth(60);
150 break;
151
152 case Qt::Key_Backspace:
153 m_buttons[i]->setValue("←");
154 m_buttons[i]->setAutoRepeat(true);
155 break;
156
157 case Qt::Key_Tab:
158 m_buttons[i]->setValue("Hide");
159 break;
160
161 case Qt::Key_CapsLock:
162 m_buttons[i]->setValue("caps");
163 break;
164
165 case Qt::Key_Shift:
166 m_buttons[i]->setValue("↑");
167 break;
168
169 case Qt::Key_Multi_key:
170 m_type== 1? m_buttons[i]->setValue("中"): m_buttons[i]->setValue("en");
171 break;
172 default:
173 break;
174 }
175 }
176 }
177
getKey(Qt::Key key)178 QString Keyboard::getKey(Qt::Key key)
179 {
180 struct KeyData{
181 QString value[2]; //value[0] 英文字符 value[1] 中文字符.
182 Qt::Key k;
183 };
184 static struct KeyData data[73]={
185 "~", "~", Qt::Key_AsciiTilde,
186 "!", "!", Qt::Key_Exclam,
187 "@", "@", Qt::Key_At,
188 "#", "#", Qt::Key_NumberSign,
189 "$", "¥", Qt::Key_Dollar,
190 "%", "%", Qt::Key_Percent,
191 "^", "……", Qt::Key_AsciiCircum,
192 "&", "&", Qt::Key_Ampersand,
193 "*", "*", Qt::Key_Asterisk,
194 "(", "(", Qt::Key_ParenLeft,
195 ")", ")", Qt::Key_ParenRight,
196 "_", "——", Qt::Key_Underscore,
197 "+", "+", Qt::Key_Plus,
198 "}", "】", Qt::Key_BraceRight,
199 "{", "【", Qt::Key_BraceLeft,
200 "\"", "、", Qt::Key_QuoteDbl,
201 "|", "|", Qt::Key_Bar,
202 "?", "?", Qt::Key_Question,
203 ">", "》", Qt::Key_Greater,
204 "<", "《", Qt::Key_Less,
205 "-", "-", Qt::Key_Minus,
206 "=", "=", Qt::Key_Equal,
207 "[", "『", Qt::Key_BracketLeft,
208 "]", "』", Qt::Key_BracketRight,
209 "\\", "、", Qt::Key_Backslash,
210 "'", "‘", Qt::Key_Apostrophe,
211 ";", ";", Qt::Key_Semicolon,
212 "/", "/", Qt::Key_Slash,
213 ".", "。", Qt::Key_Period,
214 ",", ",", Qt::Key_Comma,
215 "\r","\r", Qt::Key_Return,
216 "\b", "\b",Qt::Key_Backspace,
217 " "," ", Qt::Key_Space,
218 "`", "·", Qt::Key_QuoteLeft,
219 ":" ,":" ,Qt::Key_Colon,
220 "P", "P", Qt::Key_P,
221 "O", "O", Qt::Key_O,
222 "I", "I", Qt::Key_I,
223 "U", "U", Qt::Key_U,
224 "Y", "Y", Qt::Key_Y,
225 "T", "T", Qt::Key_T,
226 "R", "R", Qt::Key_R,
227 "E", "E", Qt::Key_E,
228 "W", "W", Qt::Key_W,
229 "Q", "Q", Qt::Key_Q,
230 "A", "A", Qt::Key_A,
231 "S", "S", Qt::Key_S,
232 "D", "D", Qt::Key_D,
233 "F", "F", Qt::Key_F,
234 "G", "G", Qt::Key_G,
235 "H", "H", Qt::Key_H,
236 "J", "J", Qt::Key_J,
237 "K", "K", Qt::Key_K,
238 "L", "L", Qt::Key_L,
239 "M", "M", Qt::Key_M,
240 "N", "N", Qt::Key_N,
241 "B", "B", Qt::Key_B,
242 "V", "V", Qt::Key_V,
243 "C", "C", Qt::Key_C,
244 "X", "X", Qt::Key_X,
245 "Z", "Z", Qt::Key_Z,
246 "1", "1", Qt::Key_1,
247 "2", "2", Qt::Key_2,
248 "3", "3", Qt::Key_3,
249 "4", "4", Qt::Key_4,
250 "5", "5", Qt::Key_5,
251 "6", "6", Qt::Key_6,
252 "7", "7", Qt::Key_7,
253 "8", "8", Qt::Key_8,
254 "9", "9", Qt::Key_9,
255 "0", "0", Qt::Key_0,
256 "", "", Qt::Key_CapsLock,
257 " ", " ", Qt::Key_Space
258 };
259
260 for(int i=0; i<72; i++){
261 KeyData d= data[i];
262 if(d.k == key){
263 return d.value[m_type];
264 }
265 }
266 return "";
267 }
268
handleKey()269 void Keyboard::handleKey()
270 {
271 KeyButton *button = dynamic_cast<KeyButton*>(this->sender());
272 if(m_inputWidget && button){
273
274 switch (button->getKey()) {
275 case Qt::Key_CapsLock:
276 m_upper =!m_upper;
277 resetKey();
278 return;
279
280 case Qt::Key_Tab:
281 this->setVisible(false);
282 return;
283
284 case Qt::Key_Shift:
285 m_shift = !m_shift;
286 resetKey();
287 return;
288
289 case Qt::Key_Multi_key:
290 {
291 if(m_type==0){
292 m_type =1;
293 }else if(m_type ==1)
294 {
295 m_type =0;
296 }
297 resetKey();
298 }
299 return;
300 default:
301 break;
302 }
303
304 if(m_type ==1 && button->getKey()>= Qt::Key_A && button->getKey() <= Qt::Key_Z )
305 {
306 addSearch(button->getValue());
307 return;
308 }else if(button->getKey() == Qt::Key_Backspace && m_bar->count() !=0)
309 {
310 PinyinDecoderService *pinyin =PinyinDecoderService::getInstance();
311 QString str = pinyin->pinyinString(false);
312 clearpinyin();
313 if(str.size()>=1)
314 {
315 str = str.left(str.size()-1);
316 }
317 addSearch(str);
318 return;
319 }
320
321 Qt::Key key = button->getKey();
322 QString value =getKey(key);
323 if(!m_upper)
324 {
325 value = value.toLower();
326 }
327
328 QKeyEvent k(QEvent::KeyPress, key, Qt::NoModifier, value);
329 qApp->sendEvent(m_inputWidget, &k);
330 }
331 }
332
hideEvent(QHideEvent * event)333 void Keyboard::hideEvent(QHideEvent *event)
334 {
335 QWidget::hideEvent(event);
336 clearpinyin();
337 addSearch();
338 }
339
clearpinyin()340 void Keyboard::clearpinyin()
341 {
342 PinyinDecoderService *pinyin =PinyinDecoderService::getInstance();
343 QString str =pinyin->pinyinString(false);
344 for(int i=0; i<str.size(); i++)
345 {
346 pinyin->deleteSearch(0, true, true);
347 }
348 }
349
addSearch(const QString & s)350 void Keyboard::addSearch(const QString &s)
351 {
352 PinyinDecoderService *pinyin =PinyinDecoderService::getInstance();
353 QString d =pinyin->pinyinString(false);
354 qCDebug(flapp)<<"search str ="<< d;
355 if(s.isEmpty())
356 {
357 if(!d.isEmpty())
358 {
359 m_candidates = pinyin->search(d);
360 }
361 }else{
362 m_candidates = pinyin->search(d + s);
363 }
364 QList<QString> candList = pinyin->fetchCandidates(0, m_candidates, 0);
365
366 qCDebug(flapp)<<"search list ="<< candList.size();
367 QStringList list (candList);
368 list.removeAll("");
369 m_bar->setStringList(list, pinyin->pinyinString(false));
370 if(list.isEmpty())
371 {
372 clearpinyin();
373 }
374 }
375
textChose(const QString & text,int index)376 void Keyboard::textChose(const QString &text, int index)
377 {
378 qCDebug(flapp)<<"textChose : text ="<< text << " index ="<< index;
379
380 static PinyinDecoderService *pinyin =PinyinDecoderService::getInstance();
381 QVector<int>vec =pinyin->spellingStartPositions();
382 if(vec.size() >0)
383 qCDebug(flapp)<< "count="<<vec.size() << "vec[0]="<< vec[0];
384 if(vec.size() >0 && m_number < vec[0])
385 {
386 pinyin->chooceCandidate(index);
387 QList<QString> candList = pinyin->fetchCandidates(0, m_candidates, 0);
388 m_list = QStringList(candList);
389 m_bar->setStringList(m_list, pinyin->pinyinString(false));
390 QString data = text;
391 if(data.size() == vec[0])
392 {
393 data = data.right(data.size()-m_number);
394 m_number =vec[0];
395 }else{
396 m_number += text.size();
397 }
398 QKeyEvent k(QEvent::KeyPress, Qt::Key_MultipleCandidate, Qt::NoModifier, data);
399 qApp->sendEvent(m_inputWidget, &k);
400 if(m_number == vec[0]){
401 m_number =0;
402 m_bar->setStringList(QStringList());
403 clearpinyin();
404 qCDebug(flapp)<<"reset search";
405 }
406 }
407 }
408
eventFilter(QObject * watched,QEvent * event)409 bool Keyboard::eventFilter(QObject *watched, QEvent *event)
410 {
411 switch (event->type()) {
412 // case QEvent::FocusIn:
413 // {
414 // QWidget *now = dynamic_cast<QWidget*>(watched);
415 // QFocusEvent *foucsEvent = dynamic_cast<QFocusEvent*>(event);
416 // if(hasInput(now) && foucsEvent->reason() == Qt::MouseFocusReason)
417 // {
418 // if(m_inputWidget != Q_NULLPTR){
419 // m_inputWidget->removeEventFilter(this);
420 // this->disconnect(this);
421 // }
422 // now->installEventFilter(this);
423 // m_inputWidget = now;
424 // resizeWidget(m_inputWidget);
425 // setVisible(true);
426
427 // }
428
429 // }break;
430
431 case QEvent::Destroy:
432 {
433 if(watched == m_inputWidget){
434 setParent(Q_NULLPTR);
435 m_inputWidget = Q_NULLPTR;
436 }
437
438 }break;
439 case QEvent::MouseButtonPress:
440 {
441 QMouseEvent *mouseEvent =dynamic_cast<QMouseEvent*>(event);
442 if(watched == m_inputWidget&&mouseEvent->button() == Qt::LeftButton && hasInput(m_inputWidget))
443 {
444 this->resizeWidget(m_inputWidget);
445 this->setVisible(true);
446 event->accept();
447 return true;
448 }
449
450 }break;
451
452 case QEvent::Resize:
453 {
454 if(watched == this)
455 {
456 resizeWidget(m_inputWidget);
457 event->accept();
458 return true;
459 }
460 }break;
461
462 case QEvent::WindowDeactivate:
463 {
464 if(watched == qApp)
465 {
466 qApp->activeWindow()->clearFocus();
467 }
468 }break;
469 default:
470 break;
471 }
472
473 return QWidget::eventFilter(watched, event);
474 }
475
resizeWidget(QWidget * w)476 void Keyboard::resizeWidget(QWidget *w)
477 {
478 QWidget *topWidget = w->topLevelWidget();
479 setParent(topWidget);
480
481 int width = topWidget->width();
482 int height = topLevelWidget()->height()/3;
483 if(height< 150){
484 height =150;
485 }
486 //输入控件在位置比最顶层父窗口位置一半大, 显示在最顶层窗口哦上面,否则显示在最顶层窗口底部.
487 QPoint pos = w->mapTo(topWidget, w->pos());
488 qCDebug(flapp)<<"input widget pos: "<< w->pos() << "global pos: "<< pos << "window rect: s" << topWidget->rect();
489
490 if(pos.y() <= topWidget->height()/2){
491 this->setGeometry(0,topWidget->height() -height-20, width, height);
492 }else{
493 this->setGeometry(0,20, width, height);
494 }
495 }
496
hasInput(QWidget * w)497 bool Keyboard::hasInput(QWidget *w)
498 {
499 bool bRet =false;
500 //过滤 QListView 输入,防止QComboBox上显示键盘.
501 if(w != Q_NULLPTR && dynamic_cast<QAbstractItemView*>(w))
502 return bRet;
503
504 //所有输入控件必须有WA_InputMethodEnabled 属性方可显示.
505 if(w!= Q_NULLPTR
506 && w->isEnabled()
507 &&w->testAttribute(Qt::WA_InputMethodEnabled))
508 {
509 bRet =true;
510 }
511
512 return bRet;
513 }
514
foucsChange(QWidget * old,QWidget * now)515 void Keyboard::foucsChange(QWidget *old, QWidget *now)
516 {
517 Q_UNUSED(old)
518 if(hasInput(now))
519 {
520 if(m_inputWidget != Q_NULLPTR){
521 m_inputWidget->removeEventFilter(this);
522 m_inputWidget->topLevelWidget()->removeEventFilter(this);
523 this->disconnect(this);
524 }
525 now->installEventFilter(this);
526 m_inputWidget = now;
527 resizeWidget(m_inputWidget);
528 setVisible(true);
529
530 }
531 }
532
533