|
MythTV
0.26-pre
|
00001 00002 // Own header 00003 #include "mythvirtualkeyboard.h" 00004 00005 // c++ 00006 #include <iostream> 00007 00008 // qt 00009 #include <QKeyEvent> 00010 #include <QDomDocument> 00011 #include <QFile> 00012 00013 // myth 00014 #include "mythmainwindow.h" 00015 #include "mythlogging.h" 00016 #include "mythfontproperties.h" 00017 #include "mythuihelper.h" 00018 #include "mythuibutton.h" 00019 #include "mythuitextedit.h" 00020 #include "mythcorecontext.h" 00021 00022 00023 #define LOC QString("MythUIVirtualKeyboard: ") 00024 00025 static const int numcomps = 95; 00026 00027 static const QString comps[numcomps][3] = { 00028 {"!", "!", (QChar)0xa1}, {"c", "/", (QChar)0xa2}, 00029 {"l", "-", (QChar)0xa3}, {"o", "x", (QChar)0xa4}, 00030 {"y", "-", (QChar)0xa5}, {"|", "|", (QChar)0xa6}, 00031 {"s", "o", (QChar)0xa7}, {"\"", "\"", (QChar)0xa8}, 00032 {"c", "o", (QChar)0xa9}, {"-", "a", (QChar)0xaa}, 00033 {"<", "<", (QChar)0xab}, {"-", "|", (QChar)0xac}, 00034 {"-", "-", (QChar)0xad}, {"r", "o", (QChar)0xae}, 00035 {"^", "-", (QChar)0xaf}, {"^", "0", (QChar)0xb0}, 00036 {"+", "-", (QChar)0xb1}, {"^", "2", (QChar)0xb2}, 00037 {"^", "3", (QChar)0xb3}, {"/", "/", (QChar)0xb4}, 00038 {"/", "u", (QChar)0xb5}, {"P", "!", (QChar)0xb6}, 00039 {"^", ".", (QChar)0xb7}, {",", ",", (QChar)0xb8}, 00040 {"^", "1", (QChar)0xb9}, {"_", "o", (QChar)0xba}, 00041 {">", ">", (QChar)0xbb}, {"1", "4", (QChar)0xbc}, 00042 {"1", "2", (QChar)0xbd}, {"3", "4", (QChar)0xbe}, 00043 {"?", "?", (QChar)0xbf}, {"A", "`", (QChar)0xc0}, 00044 {"A", "'", (QChar)0xc1}, {"A", "^", (QChar)0xc2}, 00045 {"A", "~", (QChar)0xc3}, {"A", "\"", (QChar)0xc4}, 00046 {"A", "*", (QChar)0xc5}, {"A", "E", (QChar)0xc6}, 00047 {"C", ",", (QChar)0xc7}, {"E", "`", (QChar)0xc8}, 00048 {"E", "'", (QChar)0xc9}, {"E", "^", (QChar)0xca}, 00049 {"E", "\"", (QChar)0xcb}, {"I", "`", (QChar)0xcc}, 00050 {"I", "'", (QChar)0xcd}, {"I", "^", (QChar)0xce}, 00051 {"I", "\"", (QChar)0xcf}, {"D", "-", (QChar)0xd0}, 00052 {"N", "~", (QChar)0xd1}, {"O", "`", (QChar)0xd2}, 00053 {"O", "'", (QChar)0xd3}, {"O", "^", (QChar)0xd4}, 00054 {"O", "~", (QChar)0xd5}, {"O", "\"", (QChar)0xd6}, 00055 {"x", "x", (QChar)0xd7}, {"O", "/", (QChar)0xd8}, 00056 {"U", "`", (QChar)0xd9}, {"U", "'", (QChar)0xda}, 00057 {"U", "^", (QChar)0xdb}, {"U", "\"", (QChar)0xdc}, 00058 {"Y", "'", (QChar)0xdd}, {"T", "H", (QChar)0xde}, 00059 {"s", "s", (QChar)0xdf}, {"a", "`", (QChar)0xe0}, 00060 {"a", "'", (QChar)0xe1}, {"a", "^", (QChar)0xe2}, 00061 {"a", "~", (QChar)0xe3}, {"a", "\"", (QChar)0xe4}, 00062 {"a", "*", (QChar)0xe5}, {"a", "e", (QChar)0xe6}, 00063 {"c", ",", (QChar)0xe7}, {"e", "`", (QChar)0xe8}, 00064 {"e", "'", (QChar)0xe9}, {"e", "^", (QChar)0xea}, 00065 {"e", "\"", (QChar)0xeb}, {"i", "`", (QChar)0xec}, 00066 {"i", "'", (QChar)0xed}, {"i", "^", (QChar)0xee}, 00067 {"i", "\"", (QChar)0xef}, {"d", "-", (QChar)0xf0}, 00068 {"n", "~", (QChar)0xf1}, {"o", "`", (QChar)0xf2}, 00069 {"o", "'", (QChar)0xf3}, {"o", "^", (QChar)0xf4}, 00070 {"o", "~", (QChar)0xf5}, {"o", "\"", (QChar)0xf6}, 00071 {"-", ":", (QChar)0xf7}, {"o", "/", (QChar)0xf8}, 00072 {"u", "`", (QChar)0xf9}, {"u", "'", (QChar)0xfa}, 00073 {"u", "^", (QChar)0xfb}, {"u", "\"", (QChar)0xfc}, 00074 {"y", "'", (QChar)0xfd}, {"t", "h", (QChar)0xfe}, 00075 {"y", "\"", (QChar)0xff} 00076 }; 00077 00078 MythUIVirtualKeyboard::MythUIVirtualKeyboard(MythScreenStack *parentStack, MythUITextEdit *parentEdit) 00079 : MythScreenType(parentStack, "MythUIVirtualKeyboard") 00080 { 00081 m_parentEdit = parentEdit; 00082 00083 m_shift = false; 00084 m_alt = false; 00085 m_lock = false; 00086 00087 m_lockButton = NULL; 00088 m_altButton = NULL; 00089 m_compButton = NULL; 00090 m_shiftRButton = NULL; 00091 m_shiftLButton = NULL; 00092 00093 m_composing = false; 00094 00095 if (m_parentEdit) 00096 m_preferredPos = m_parentEdit->GetKeyboardPosition(); 00097 else 00098 m_preferredPos = VK_POSBELOWEDIT; 00099 } 00100 00101 MythUIVirtualKeyboard::~MythUIVirtualKeyboard(void) 00102 { 00103 } 00104 00105 bool MythUIVirtualKeyboard::Create() 00106 { 00107 if (!LoadWindowFromXML("keyboard/keyboard.xml", "keyboard", this)) 00108 return false; 00109 00110 BuildFocusList(); 00111 00112 loadKeyDefinitions(gCoreContext->GetLanguageAndVariant()); 00113 updateKeys(true); 00114 00115 int screenWidth, screenHeight; 00116 float xmult, ymult; 00117 GetMythUI()->GetScreenSettings(screenWidth, xmult, screenHeight, ymult); 00118 MythRect editArea = m_parentEdit->GetArea(); 00119 MythRect area = GetArea(); 00120 MythPoint newPos; 00121 00122 //FIXME this assumes the edit is a direct child of the parent screen 00123 MythUIType *parentScreen = NULL; 00124 parentScreen = dynamic_cast<MythUIType *>(m_parentEdit->parent()); 00125 if (parentScreen) 00126 { 00127 editArea.moveTopLeft(QPoint(editArea.x() + parentScreen->GetArea().x(), 00128 editArea.y() + parentScreen->GetArea().y())); 00129 } 00130 00131 switch (m_preferredPos) 00132 { 00133 case VK_POSABOVEEDIT: 00134 if (editArea.y() - area.height() - 5 > 0) 00135 { 00136 newPos = QPoint(editArea.x() + editArea.width() / 2 - area.width() / 2, 00137 editArea.y() - area.height() - 5); 00138 } 00139 else 00140 { 00141 newPos = QPoint(editArea.x() + editArea.width() / 2 - area.width() / 2, 00142 editArea.y() + editArea.height() + 5); 00143 } 00144 break; 00145 00146 case VK_POSTOPDIALOG: 00147 newPos = QPoint(screenWidth / 2 - area.width() / 2, 5); 00148 break; 00149 00150 case VK_POSBOTTOMDIALOG: 00151 newPos = QPoint(screenWidth / 2 - area.width() / 2, screenHeight - 5 - area.height()); 00152 break; 00153 00154 case VK_POSCENTERDIALOG: 00155 newPos = QPoint(screenWidth / 2 - area.width() / 2, screenHeight / 2 - area.height() / 2); 00156 break; 00157 00158 default: 00159 // VK_POSBELOWEDIT 00160 if (editArea.y() + editArea.height() + area.height() + 5 < screenHeight) 00161 { 00162 newPos = QPoint(editArea.x() + editArea.width() / 2 - area.width() / 2, 00163 editArea.y() + editArea.height() + 5); 00164 } 00165 else 00166 { 00167 newPos = QPoint(editArea.x() + editArea.width() / 2 - area.width() / 2, 00168 editArea.y() - area.height() - 5); 00169 } 00170 break; 00171 } 00172 00173 // make sure the popup doesn't go off screen 00174 if (newPos.x() < 5) 00175 newPos.setX(5); 00176 if (newPos.x() + area.width() + 5 > screenWidth) 00177 newPos.setX(screenWidth - area.width() - 5); 00178 if (newPos.y() < 5) 00179 newPos.setY(5); 00180 if (newPos.y() + area.height() + 5 > screenHeight) 00181 newPos.setY(screenHeight - area.height() - 5); 00182 00183 SetPosition(newPos); 00184 00185 return true; 00186 } 00187 00188 void MythUIVirtualKeyboard::loadKeyDefinitions(const QString &lang) 00189 { 00190 QString language = lang.toLower(); 00191 00192 QString defFile = QString("keyboard/%1.xml").arg(language); 00193 00194 if (!GetMythUI()->FindThemeFile(defFile)) 00195 { 00196 LOG(VB_GENERAL, LOG_ERR, 00197 "No keyboard definition file found for: " + language); 00198 00199 // default to US keyboard layout 00200 defFile = "keyboard/en_us.xml"; 00201 if (!GetMythUI()->FindThemeFile(defFile)) 00202 { 00203 LOG(VB_GENERAL, LOG_ERR, 00204 "Cannot find definitions file: " + defFile); 00205 return; 00206 } 00207 } 00208 00209 LOG(VB_GENERAL, LOG_NOTICE, "Loading definitions from: " + defFile); 00210 00211 QDomDocument doc("keydefinitions"); 00212 QFile file(defFile); 00213 if (!file.open(QIODevice::ReadOnly)) 00214 { 00215 LOG(VB_GENERAL, LOG_ERR, "Failed to open definitions file: " + defFile); 00216 return; 00217 } 00218 if (!doc.setContent(&file)) 00219 { 00220 LOG(VB_GENERAL, LOG_ERR, 00221 "Failed to parse definitions file: " + defFile); 00222 file.close(); 00223 return; 00224 } 00225 file.close(); 00226 00227 QDomElement docElem = doc.documentElement(); 00228 QDomNode n = docElem.firstChild(); 00229 while(!n.isNull()) 00230 { 00231 QDomElement e = n.toElement(); 00232 if(!e.isNull()) 00233 { 00234 if (e.tagName() == "key") 00235 parseKey(e); 00236 } 00237 n = n.nextSibling(); 00238 } 00239 } 00240 00241 void MythUIVirtualKeyboard::parseKey(const QDomElement &element) 00242 { 00243 QString left, right, up, down; 00244 QString normal, shift, alt, altshift; 00245 00246 QString name = element.attribute("name"); 00247 QString type = element.attribute("type"); 00248 00249 QDomNode n = element.firstChild(); 00250 while(!n.isNull()) 00251 { 00252 QDomElement e = n.toElement(); 00253 if(!e.isNull()) 00254 { 00255 if (e.tagName() == "move") 00256 { 00257 left = e.attribute("left"); 00258 right = e.attribute("right"); 00259 up = e.attribute("up"); 00260 down = e.attribute("down"); 00261 } 00262 else if (e.tagName() == "char") 00263 { 00264 normal = e.attribute("normal"); 00265 shift = e.attribute("shift"); 00266 alt = e.attribute("alt"); 00267 altshift = e.attribute("altshift"); 00268 } 00269 else 00270 LOG(VB_GENERAL, LOG_ERR, "Unknown element in key definition"); 00271 } 00272 n = n.nextSibling(); 00273 } 00274 00275 KeyDefinition key; 00276 key.name = name; 00277 key.type = type; 00278 key.left = left; 00279 key.right = right; 00280 key.up = up; 00281 key.down = down; 00282 key.normal = decodeChar(normal); 00283 key.alt = decodeChar(alt); 00284 key.shift = decodeChar(shift); 00285 key.altshift = decodeChar(altshift); 00286 00287 m_keyMap[name] = key; 00288 } 00289 00290 void MythUIVirtualKeyboard::updateKeys(bool connectSignals) 00291 { 00292 QList<MythUIType *> *children = GetAllChildren(); 00293 for (int i = 0; i < children->size(); ++i) 00294 { 00295 MythUIButton *button = dynamic_cast<MythUIButton *>(children->at(i)); 00296 if (button) 00297 { 00298 if (m_keyMap.contains(button->objectName())) 00299 { 00300 KeyDefinition key = m_keyMap.value(button->objectName()); 00301 button->SetText(getKeyText(key)); 00302 00303 if (connectSignals) 00304 { 00305 if (key.type == "shift") 00306 { 00307 if (!m_shiftLButton) 00308 m_shiftLButton = button; 00309 else if (!m_shiftRButton) 00310 m_shiftRButton = button; 00311 00312 button->SetLockable(true); 00313 connect(button, SIGNAL(Clicked()), SLOT(shiftClicked())); 00314 } 00315 else if (key.type == "char") 00316 connect(button, SIGNAL(Clicked()), SLOT(charClicked())); 00317 else if (key.type == "done") 00318 connect(button, SIGNAL(Clicked()), SLOT(returnClicked())); 00319 else if (key.type == "del") 00320 connect(button, SIGNAL(Clicked()), SLOT(delClicked())); 00321 else if (key.type == "lock") 00322 { 00323 m_lockButton = button; 00324 m_lockButton->SetLockable(true); 00325 connect(m_lockButton, SIGNAL(Clicked()), SLOT(lockClicked())); 00326 } 00327 else if (key.type == "alt") 00328 { 00329 m_altButton = button; 00330 m_altButton->SetLockable(true); 00331 connect(m_altButton, SIGNAL(Clicked()), SLOT(altClicked())); 00332 } 00333 else if (key.type == "comp") 00334 { 00335 m_compButton = button; 00336 m_compButton->SetLockable(true); 00337 connect(m_compButton, SIGNAL(Clicked()), SLOT(compClicked())); 00338 } 00339 else if (key.type == "moveleft") 00340 connect(button, SIGNAL(Clicked()), SLOT(moveleftClicked())); 00341 else if (key.type == "moveright") 00342 connect(button, SIGNAL(Clicked()), SLOT(moverightClicked())); 00343 else if (key.type == "back") 00344 connect(button, SIGNAL(Clicked()), SLOT(backClicked())); 00345 } 00346 } 00347 else 00348 LOG(VB_GENERAL, LOG_WARNING, 00349 QString("WARNING - Key '%1' not found in map") 00350 .arg(button->objectName())); 00351 } 00352 } 00353 } 00354 00355 bool MythUIVirtualKeyboard::keyPressEvent(QKeyEvent *e) 00356 { 00357 bool handled = false; 00358 QStringList actions; 00359 handled = GetMythMainWindow()->TranslateKeyPress("TV Frontend", e, actions); 00360 00361 if (handled) 00362 return true; 00363 00364 bool keyFound = false; 00365 KeyDefinition key; 00366 if (GetFocusWidget()) 00367 { 00368 if (m_keyMap.contains(GetFocusWidget()->objectName())) 00369 { 00370 key = m_keyMap.value(GetFocusWidget()->objectName()); 00371 keyFound = true;; 00372 } 00373 } 00374 00375 for (int i = 0; i < actions.size() && !handled; i++) 00376 { 00377 QString action = actions[i]; 00378 handled = true; 00379 00380 if (action == "UP") 00381 { 00382 if (keyFound) 00383 SetFocusWidget(GetChild(key.up)); 00384 } 00385 else if (action == "DOWN") 00386 { 00387 if (keyFound) 00388 SetFocusWidget(GetChild(key.down)); 00389 } 00390 else if (action == "LEFT") 00391 { 00392 if (keyFound) 00393 SetFocusWidget(GetChild(key.left)); 00394 } 00395 else if (action == "RIGHT") 00396 { 00397 if (keyFound) 00398 SetFocusWidget(GetChild(key.right)); 00399 } 00400 else 00401 handled = false; 00402 } 00403 00404 if (!handled && MythScreenType::keyPressEvent(e)) 00405 handled = true; 00406 00407 return handled; 00408 } 00409 00410 void MythUIVirtualKeyboard::charClicked(void) 00411 { 00412 if (!GetFocusWidget()) 00413 return; 00414 00415 KeyDefinition key = m_keyMap.value(GetFocusWidget()->objectName()); 00416 QString c = getKeyText(key); 00417 00418 if (m_composing) 00419 { 00420 if (m_composeStr.isEmpty()) 00421 m_composeStr = c; 00422 else 00423 { 00424 // Produce the composed key. 00425 for (int i = 0; i < numcomps; i++) 00426 { 00427 if ((m_composeStr == comps[i][0]) && (c == comps[i][1])) 00428 { 00429 c = comps[i][2]; 00430 00431 emit keyPressed(c); 00432 00433 if (m_parentEdit) 00434 { 00435 QKeyEvent *event = new QKeyEvent(QEvent::KeyPress, 0, Qt::NoModifier, c); 00436 m_parentEdit->keyPressEvent(event); 00437 } 00438 00439 break; 00440 } 00441 } 00442 00443 m_composeStr.clear(); 00444 m_composing = false; 00445 if (m_compButton) 00446 m_compButton->SetLocked(false); 00447 } 00448 } 00449 else 00450 { 00451 emit keyPressed(c); 00452 00453 if (m_parentEdit) 00454 { 00455 QKeyEvent *event = new QKeyEvent(QEvent::KeyPress, 0, Qt::NoModifier, c); 00456 m_parentEdit->keyPressEvent(event); 00457 } 00458 00459 if (m_shift && !m_lock) 00460 { 00461 m_shift = false; 00462 if (m_shiftLButton) 00463 m_shiftLButton->SetLocked(false); 00464 if (m_shiftRButton) 00465 m_shiftRButton->SetLocked(false); 00466 00467 updateKeys(); 00468 } 00469 } 00470 } 00471 00472 void MythUIVirtualKeyboard::shiftClicked(void) 00473 { 00474 m_shift = !m_shift; 00475 00476 if (m_shiftLButton) 00477 m_shiftLButton->SetLocked(m_shift); 00478 if (m_shiftRButton) 00479 m_shiftRButton->SetLocked(m_shift); 00480 if (m_lockButton && m_lock) 00481 { 00482 m_lockButton->SetLocked(false); 00483 m_lock = false; 00484 } 00485 00486 updateKeys(); 00487 } 00488 00489 void MythUIVirtualKeyboard::delClicked(void) 00490 { 00491 emit keyPressed("{DELETE}"); 00492 00493 if (m_parentEdit) 00494 { 00495 //QKeyEvent *event = new QKeyEvent(QEvent::KeyPress, Qt::Key_Delete, Qt::NoModifier, ""); 00496 QKeyEvent *event = new QKeyEvent(QEvent::KeyPress, Qt::Key_Backspace, Qt::NoModifier, ""); 00497 m_parentEdit->keyPressEvent(event); 00498 } 00499 } 00500 00501 void MythUIVirtualKeyboard::backClicked(void) 00502 { 00503 emit keyPressed("{BACK}"); 00504 00505 if (m_parentEdit) 00506 { 00507 QKeyEvent *event = new QKeyEvent(QEvent::KeyPress, Qt::Key_Backspace, Qt::NoModifier, ""); 00508 m_parentEdit->keyPressEvent(event); 00509 } 00510 } 00511 00512 void MythUIVirtualKeyboard::lockClicked(void) 00513 { 00514 m_lock = !m_lock; 00515 m_shift = m_lock; 00516 00517 if (m_shiftLButton) 00518 m_shiftLButton->SetLocked(m_shift); 00519 if (m_shiftRButton) 00520 m_shiftRButton->SetLocked(m_shift); 00521 00522 updateKeys(); 00523 } 00524 00525 void MythUIVirtualKeyboard::altClicked(void) 00526 { 00527 m_alt = !m_alt; 00528 00529 updateKeys(); 00530 } 00531 00532 void MythUIVirtualKeyboard::compClicked(void) 00533 { 00534 m_composing = !m_composing; 00535 m_composeStr.clear(); 00536 } 00537 00538 void MythUIVirtualKeyboard::returnClicked(void) 00539 { 00540 Close(); 00541 } 00542 00543 void MythUIVirtualKeyboard::moveleftClicked(void) 00544 { 00545 emit keyPressed("{MOVELEFT}"); 00546 00547 if (m_parentEdit) 00548 { 00549 QKeyEvent *event = new QKeyEvent(QEvent::KeyPress, Qt::Key_Left, Qt::NoModifier, ""); 00550 m_parentEdit->keyPressEvent(event); 00551 } 00552 } 00553 00554 void MythUIVirtualKeyboard::moverightClicked(void) 00555 { 00556 emit keyPressed("{MOVERIGHT}"); 00557 00558 if (m_parentEdit) 00559 { 00560 QKeyEvent *event = new QKeyEvent(QEvent::KeyPress, Qt::Key_Right, Qt::NoModifier, ""); 00561 m_parentEdit->keyPressEvent(event); 00562 } 00563 } 00564 00565 QString MythUIVirtualKeyboard::decodeChar(QString c) 00566 { 00567 QString res; 00568 00569 while (c.length() > 0) 00570 { 00571 if (c.startsWith("0x")) 00572 { 00573 QString sCode = c.left(6); 00574 bool bOK; 00575 short nCode = sCode.toShort(&bOK, 16); 00576 00577 c = c.mid(6); 00578 00579 if (bOK) 00580 { 00581 QChar uc(nCode); 00582 res += QString(uc); 00583 } 00584 else 00585 LOG(VB_GENERAL, LOG_ERR, QString("bad char code (%1)") 00586 .arg(sCode)); 00587 } 00588 else 00589 { 00590 res += c.left(1); 00591 c = c.mid(1); 00592 } 00593 } 00594 00595 return res; 00596 } 00597 00598 QString MythUIVirtualKeyboard::getKeyText(KeyDefinition key) 00599 { 00600 00601 if (m_shift) 00602 { 00603 if (m_alt) 00604 return key.altshift; 00605 else 00606 return key.shift; 00607 } 00608 00609 if (m_alt) 00610 return key.alt; 00611 00612 return key.normal; 00613 }
1.7.6.1