Ticket #9613: multikeybindings_v3.patch
File multikeybindings_v3.patch, 27.5 KB (added by , 14 years ago) |
---|
-
mythtv/libs/libmythtv/dbcheck.cpp
diff --git a/mythtv/libs/libmythtv/dbcheck.cpp b/mythtv/libs/libmythtv/dbcheck.cpp index 47e368a..2314eb2 100644
a b tmp.constData(), 5962 5962 " description varchar(255) default NULL," 5963 5963 " keylist varchar(128) default NULL," 5964 5964 " hostname varchar(64) NOT NULL default ''," 5965 " multikey varchar(128) default NULL," 5965 5966 " PRIMARY KEY (destination,hostname)" 5966 5967 ");", 5967 5968 "CREATE TABLE keybindings (" … … tmp.constData(), 5970 5971 " description varchar(255) default NULL," 5971 5972 " keylist varchar(128) default NULL," 5972 5973 " hostname varchar(64) NOT NULL default ''," 5974 " multikey varchar(128) default NULL," 5973 5975 " PRIMARY KEY (`context`,`action`,hostname)" 5974 5976 ");", 5975 5977 "CREATE TABLE keyword (" -
mythtv/libs/libmythtv/tv_play.cpp
diff --git a/mythtv/libs/libmythtv/tv_play.cpp b/mythtv/libs/libmythtv/tv_play.cpp index b2ba709..e118ca5 100644
a b TV::TV(void) 874 874 endOfPlaybackTimerId(0), embedCheckTimerId(0), 875 875 endOfRecPromptTimerId(0), videoExitDialogTimerId(0), 876 876 pseudoChangeChanTimerId(0), speedChangeTimerId(0), 877 errorRecoveryTimerId(0), exitPlayerTimerId(0) 877 errorRecoveryTimerId(0), exitPlayerTimerId(0), 878 multikeyContext(new MultikeyContext()) 878 879 { 879 880 VERBOSE(VB_GENERAL, LOC + "Creating TV object"); 880 881 ctorTime.start(); … … TV::~TV(void) 1213 1214 } 1214 1215 ReturnPlayerLock(mctx); 1215 1216 1217 if (multikeyContext) 1218 { 1219 delete multikeyContext; 1220 multikeyContext = NULL; 1221 } 1222 1216 1223 GetMythMainWindow()->GetPaintWindow()->show(); 1217 1224 1218 1225 VERBOSE(VB_PLAYBACK, "TV::~TV() -- end"); … … bool TV::ProcessKeypress(PlayerContext *actx, QKeyEvent *e) 3299 3306 if (ignoreKeys) 3300 3307 { 3301 3308 handled = GetMythMainWindow()->TranslateKeyPress( 3302 "TV Playback", e, actions );3309 "TV Playback", e, actions, true, multikeyContext); 3303 3310 3304 3311 if (handled || actions.isEmpty()) 3312 { 3313 CommitMultikey(actx); 3305 3314 return true; 3315 } 3306 3316 3307 3317 bool esc = has_action("ESCAPE", actions) || 3308 3318 has_action("BACK", actions); … … bool TV::ProcessKeypress(PlayerContext *actx, QKeyEvent *e) 3310 3320 bool play = has_action(ACTION_PLAY, actions); 3311 3321 3312 3322 if ((!esc || browsehelper->IsBrowsing()) && !pause && !play) 3323 { 3324 CommitMultikey(actx); 3313 3325 return false; 3326 } 3314 3327 } 3315 3328 3316 3329 OSD *osd = GetOSDLock(actx); … … bool TV::ProcessKeypress(PlayerContext *actx, QKeyEvent *e) 3324 3337 if (editmode && !handled) 3325 3338 { 3326 3339 handled |= GetMythMainWindow()->TranslateKeyPress( 3327 "TV Editing", e, actions );3340 "TV Editing", e, actions, true, multikeyContext); 3328 3341 3329 3342 if (!handled) 3330 3343 { … … bool TV::ProcessKeypress(PlayerContext *actx, QKeyEvent *e) 3368 3381 } 3369 3382 3370 3383 if (handled) 3384 { 3385 CommitMultikey(actx); 3371 3386 return true; 3387 } 3372 3388 3373 3389 // If text is already queued up, be more lax on what is ok. 3374 3390 // This allows hex teletext entry and minor channel entry. … … bool TV::ProcessKeypress(PlayerContext *actx, QKeyEvent *e) 3380 3396 if (ok || txt=="_" || txt=="-" || txt=="#" || txt==".") 3381 3397 { 3382 3398 AddKeyToInputQueue(actx, txt.at(0).toLatin1()); 3399 CommitMultikey(actx, false); 3383 3400 return true; 3384 3401 } 3385 3402 } … … bool TV::ProcessKeypress(PlayerContext *actx, QKeyEvent *e) 3390 3407 { 3391 3408 QStringList tt_actions; 3392 3409 handled = GetMythMainWindow()->TranslateKeyPress( 3393 "Teletext Menu", e, tt_actions );3410 "Teletext Menu", e, tt_actions, true, multikeyContext); 3394 3411 3395 3412 if (!handled && !tt_actions.isEmpty()) 3396 3413 { … … bool TV::ProcessKeypress(PlayerContext *actx, QKeyEvent *e) 3399 3416 if (actx->player->HandleTeletextAction(tt_actions[i])) 3400 3417 { 3401 3418 actx->UnlockDeletePlayer(__FILE__, __LINE__); 3419 CommitMultikey(actx); 3402 3420 return true; 3403 3421 } 3404 3422 } … … bool TV::ProcessKeypress(PlayerContext *actx, QKeyEvent *e) 3410 3428 { 3411 3429 QStringList itv_actions; 3412 3430 handled = GetMythMainWindow()->TranslateKeyPress( 3413 "TV Playback", e, itv_actions );3431 "TV Playback", e, itv_actions, true, multikeyContext); 3414 3432 3415 3433 if (!handled && !itv_actions.isEmpty()) 3416 3434 { … … bool TV::ProcessKeypress(PlayerContext *actx, QKeyEvent *e) 3419 3437 if (actx->player->ITVHandleAction(itv_actions[i])) 3420 3438 { 3421 3439 actx->UnlockDeletePlayer(__FILE__, __LINE__); 3440 CommitMultikey(actx); 3422 3441 return true; 3423 3442 } 3424 3443 } … … bool TV::ProcessKeypress(PlayerContext *actx, QKeyEvent *e) 3427 3446 actx->UnlockDeletePlayer(__FILE__, __LINE__); 3428 3447 3429 3448 handled = GetMythMainWindow()->TranslateKeyPress( 3430 "TV Playback", e, actions );3449 "TV Playback", e, actions, true, multikeyContext); 3431 3450 3432 3451 if (handled || actions.isEmpty()) 3452 { 3453 CommitMultikey(actx); 3433 3454 return true; 3455 } 3434 3456 3435 3457 handled = false; 3436 3458 … … bool TV::ProcessKeypress(PlayerContext *actx, QKeyEvent *e) 3457 3479 #endif // DEBUG_ACTIONS 3458 3480 3459 3481 if (handled) 3482 { 3483 CommitMultikey(actx); 3460 3484 return true; 3485 } 3461 3486 3462 3487 if (!handled) 3463 3488 { … … bool TV::ProcessKeypress(PlayerContext *actx, QKeyEvent *e) 3471 3496 { 3472 3497 AddKeyToInputQueue(actx, '0' + val); 3473 3498 handled = true; 3499 CommitMultikey(actx, false); 3474 3500 } 3475 3501 } 3476 3502 } … … bool TV::ProcessKeypress(PlayerContext *actx, QKeyEvent *e) 3478 3504 return true; 3479 3505 } 3480 3506 3507 void TV::CommitMultikey(PlayerContext *ctx, bool updateOSD) 3508 { 3509 MultikeyContext::MultikeyStatus status; 3510 QString prefix; 3511 multikeyContext->Commit(status, prefix); 3512 bool isMultikey = (QKeySequence(prefix).count() > 1); 3513 if (updateOSD) 3514 { 3515 switch (status) 3516 { 3517 case MultikeyContext::kMKnoPrefix: 3518 // clear the OSD text 3519 HideOSDWindow(ctx, "osd_input"); 3520 break; 3521 case MultikeyContext::kMKpartialMatch: 3522 SetOSDText(ctx, "osd_input", "osd_number_entry", 3523 prefix, kOSDTimeout_Med); 3524 break; 3525 case MultikeyContext::kMKfullMatch: 3526 // same as partial match but with short timeout 3527 if (isMultikey) 3528 SetOSDText(ctx, "osd_input", "osd_number_entry", 3529 prefix, kOSDTimeout_Short); 3530 break; 3531 case MultikeyContext::kMKbadMatch: 3532 // same as full match but with error text 3533 SetOSDText(ctx, "osd_input", "osd_number_entry", 3534 prefix + ": " + QObject::tr("Unknown key sequence"), 3535 kOSDTimeout_Short); 3536 break; 3537 } 3538 } 3539 } 3540 3481 3541 bool TV::BrowseHandleAction(PlayerContext *ctx, const QStringList &actions) 3482 3542 { 3483 3543 if (!browsehelper->IsBrowsing()) -
mythtv/libs/libmythtv/tv_play.h
diff --git a/mythtv/libs/libmythtv/tv_play.h b/mythtv/libs/libmythtv/tv_play.h index 9739519..83f51f7 100644
a b using namespace std; 41 41 42 42 class QDateTime; 43 43 class OSD; 44 class MultikeyContext; 44 45 class RemoteEncoder; 45 46 class MythPlayer; 46 47 class DetectLetterbox; … … class MTV_PUBLIC TV : public QObject 386 387 void ClearInputQueues(const PlayerContext*, bool hideosd); 387 388 bool CommitQueuedInput(PlayerContext*); 388 389 bool ProcessSmartChannel(const PlayerContext*, QString&); 390 void CommitMultikey(PlayerContext*, bool updateOSD=true); 389 391 390 392 // query key queues 391 393 bool HasQueuedInput(void) const … … class MTV_PUBLIC TV : public QObject 842 844 TimerContextMap signalMonitorTimerId; 843 845 TimerContextMap tvchainUpdateTimerId; 844 846 847 MultikeyContext *multikeyContext; 848 845 849 public: 846 850 // Constants 847 851 static const int kInitFFRWSpeed; ///< 1x, default to normal speed -
mythtv/libs/libmythui/mythmainwindow.cpp
diff --git a/mythtv/libs/libmythui/mythmainwindow.cpp b/mythtv/libs/libmythui/mythmainwindow.cpp index 7ecb158..6b4d66b 100644
a b using namespace std; 86 86 #define LOC_WARN QString("MythMainWindow, Warning: ") 87 87 #define LOC_ERR QString("MythMainWindow, Error: ") 88 88 89 class MultikeyData 90 { 91 public: 92 void AddMultikeyMapping(const QString &multikey, QString action) 93 { 94 QKeySequence seq(multikey); 95 switch (seq.count()) 96 { 97 case 4: 98 ++multikeyPrefixes[QKeySequence(seq[0], seq[1], seq[2])]; 99 // fallthrough 100 case 3: 101 ++multikeyPrefixes[QKeySequence(seq[0], seq[1])]; 102 // fallthrough 103 case 2: 104 ++multikeyPrefixes[QKeySequence(seq[0])]; 105 // fallthrough 106 case 1: 107 multikeyActionMap[seq].append(action); 108 } 109 } 110 111 bool IsMultikeyPrefix(const QString &multikey) 112 { 113 return multikeyPrefixes.count(QKeySequence(multikey)); 114 } 115 116 bool GetMultikeyMapping(const QString &multikey, QStringList &actions) 117 { 118 QKeySequence seq(multikey); 119 if (multikeyActionMap.count(seq) > 0) 120 { 121 actions += multikeyActionMap[seq]; 122 return true; 123 } 124 return false; 125 } 126 127 private: 128 QMap<QKeySequence, QStringList> multikeyActionMap; 129 QMap<QKeySequence, int> multikeyPrefixes; 130 }; 131 89 132 class KeyContext 90 133 { 91 134 public: 92 135 void AddMapping(int key, QString action) 93 136 { 94 137 actionMap[key].append(action); 138 multiData.AddMultikeyMapping(QKeySequence(key).toString(), action); 95 139 } 96 140 97 141 bool GetMapping(int key, QStringList &actions) … … class KeyContext 105 149 } 106 150 107 151 QMap<int, QStringList> actionMap; 152 MultikeyData multiData; 108 153 }; 109 154 110 155 struct JumpData … … class MythMainWindowPrivate 216 261 QHash<QString, KeyContext *> keyContexts; 217 262 QMap<int, JumpData*> jumpMap; 218 263 QMap<QString, JumpData> destinationMap; 264 MultikeyData jumpMultikeyData; 219 265 QMap<QString, MPData> mediaPluginMap; 220 266 221 267 void (*exitmenucallback)(void); … … class MythMainWindowPrivate 264 310 bool m_pendingUpdate; 265 311 }; 266 312 313 // Returns false if the key couldn't be added (prefix too long). 314 bool MultikeyContext::AddKey(int key) 315 { 316 currentPrefix = oldPrefix; 317 bool result = true; 318 QKeySequence seq(currentPrefix); 319 int k1 = seq[0]; 320 int k2 = seq[1]; 321 int k3 = seq[2]; 322 int k4 = seq[3]; 323 if (k1 == 0) 324 k1 = key; 325 else if (k2 == 0) 326 k2 = key; 327 else if (k3 == 0) 328 k3 = key; 329 else if (k4 == 0) 330 k4 = key; 331 else 332 result = false; 333 if (result) 334 currentPrefix = QKeySequence(k1, k2, k3, k4).toString(); 335 return result; 336 } 337 267 338 // Make keynum in QKeyEvent be equivalent to what's in QKeySequence 268 339 int MythMainWindowPrivate::TranslateKeyNum(QKeyEvent* e) 269 340 { … … void MythMainWindow::ExitToMainMenu(void) 1440 1511 * \param e The keypress event to lookup. 1441 1512 * \param actions The QStringList that will contain the list of actions. 1442 1513 * \param allowJumps if true then jump points are allowed 1514 * \param prefixContext if non-NULL then multi-key bindings are allowed. 1443 1515 * 1444 1516 * \return true if the key event has been handled (the keypress was a jumpoint) 1445 1517 false if the caller should continue to handle keypress 1446 1518 */ 1447 1519 bool MythMainWindow::TranslateKeyPress(const QString &context, 1448 1520 QKeyEvent *e, QStringList &actions, 1449 bool allowJumps) 1521 bool allowJumps, 1522 MultikeyContext *prefixContext) 1450 1523 { 1451 1524 actions.clear(); 1452 1525 … … bool MythMainWindow::TranslateKeyPress(const QString &context, 1460 1533 } 1461 1534 1462 1535 int keynum = d->TranslateKeyNum(e); 1463 1464 QStringList localActions; 1465 if (allowJumps && (d->jumpMap.count(keynum) > 0) && 1466 (!d->jumpMap[keynum]->localAction.isEmpty()) && 1467 (d->keyContexts.value(context)) && 1468 (d->keyContexts.value(context)->GetMapping(keynum, localActions))) 1469 { 1470 if (localActions.contains(d->jumpMap[keynum]->localAction)) 1471 allowJumps = false; 1536 bool checkOnlyJumpPoints = false; 1537 bool wasEmpty = prefixContext ? prefixContext->GetPrefix().isEmpty() : true; 1538 bool noOverflow = prefixContext ? prefixContext->AddKey(keynum) : true; 1539 const QString singleKey = QKeySequence(keynum).toString(); 1540 const QString prefix = prefixContext ? prefixContext->GetPrefix() : singleKey; 1541 MultikeyContext::MultikeyStatus status; 1542 JumpData *singleKeyJump = NULL, *multiKeyJump = NULL; 1543 // There is a potential race condition where an input timeout 1544 // thread resets the context at the same time this code is 1545 // operating on it. 1546 QStringList singleKeyJumpActions, multiKeyJumpActions; 1547 QStringList singleKeyActions, multiKeyActions; 1548 KeyContext *kctx = d->keyContexts.value(context); 1549 KeyContext *gctx = d->keyContexts.value("Global"); 1550 1551 if (allowJumps) 1552 { 1553 // Find single-key jumppoint bindings. This is only used when 1554 // a multi-key sequence (regular or jumppoint) is aborted 1555 // mid-sequence with a single-key jump point. 1556 if (d->jumpMultikeyData.GetMultikeyMapping(singleKey, singleKeyJumpActions)) 1557 singleKeyJump = &d->destinationMap[singleKeyJumpActions[0]]; 1558 // Find multi-key jumppoint bindings. 1559 if (noOverflow && d->jumpMultikeyData.GetMultikeyMapping(prefix, multiKeyJumpActions)) 1560 multiKeyJump = &d->destinationMap[multiKeyJumpActions[0]]; 1561 } 1562 // Find regular bindings (both single- and multi-key) in the given 1563 // and global contexts. 1564 if (kctx) 1565 { 1566 if (noOverflow) 1567 kctx->multiData.GetMultikeyMapping(prefix, multiKeyActions); 1568 kctx->multiData.GetMultikeyMapping(singleKey, singleKeyActions); 1569 } 1570 if (gctx && context != "Global") 1571 { 1572 if (noOverflow) 1573 gctx->multiData.GetMultikeyMapping(prefix, multiKeyActions); 1574 gctx->multiData.GetMultikeyMapping(singleKey, singleKeyActions); 1575 } 1576 1577 // Disable the jump point if there is a corresponding local action 1578 // for the key sequence. 1579 if (multiKeyJump && 1580 !multiKeyJump->localAction.isEmpty() && 1581 multiKeyActions.contains(multiKeyJump->localAction)) 1582 { 1583 multiKeyJump = singleKeyJump = NULL; 1584 } 1585 if (singleKeyJump && 1586 !singleKeyJump->localAction.isEmpty() && 1587 singleKeyActions.contains(singleKeyJump->localAction)) 1588 { 1589 multiKeyJump = singleKeyJump = NULL; 1590 multiKeyActions = singleKeyActions; 1591 } 1592 1593 // Execute the jump point if there is one. 1594 if (multiKeyJump || (singleKeyJump && multiKeyActions.isEmpty())) 1595 { 1596 JumpData *jumpEntry = multiKeyJump ? multiKeyJump : singleKeyJump; 1597 if (!jumpEntry->exittomain && d->exitmenucallback == NULL) 1598 { 1599 if (prefixContext) 1600 prefixContext->SetStatus(MultikeyContext::kMKfullMatch); 1601 void (*callback)(void) = jumpEntry->callback; 1602 callback(); 1603 return true; 1604 } 1605 if (d->exitmenucallback == NULL) 1606 { 1607 if (prefixContext) 1608 prefixContext->SetStatus(MultikeyContext::kMKfullMatch); 1609 d->exitingtomain = true; 1610 d->exitmenucallback = jumpEntry->callback; 1611 QCoreApplication::postEvent( 1612 this, new QEvent(MythEvent::kExitToMainMenuEventType)); 1613 return true; 1614 } 1472 1615 } 1473 1616 1474 if (allowJumps && d->jumpMap.count(keynum) > 0 &&1475 !d->jumpMap[keynum]->exittomain && d->exitmenucallback == NULL)1617 // Handle a regular action if there is one. 1618 if (!multiKeyActions.isEmpty()) 1476 1619 { 1477 void (*callback)(void) = d->jumpMap[keynum]->callback; 1478 callback(); 1479 return true; 1620 if (prefixContext) 1621 prefixContext->SetStatus(MultikeyContext::kMKfullMatch); 1622 actions = multiKeyActions; 1623 return false; 1480 1624 } 1481 1625 1482 if (allowJumps &&1483 d->jumpMap.count(keynum) > 0 && d->exitmenucallback == NULL)1626 // No full match, so handle partial matches and bad matches. 1627 if (noOverflow) 1484 1628 { 1485 d->exitingtomain = true; 1486 d->exitmenucallback = d->jumpMap[keynum]->callback; 1487 QCoreApplication::postEvent( 1488 this, new QEvent(MythEvent::kExitToMainMenuEventType)); 1489 return true; 1629 // Check for a partial match. 1630 if ((kctx && kctx->multiData.IsMultikeyPrefix(prefix)) || 1631 (gctx && context != "Global" && gctx->multiData.IsMultikeyPrefix(prefix)) || 1632 (d->jumpMultikeyData.IsMultikeyPrefix(prefix))) 1633 { 1634 if (prefixContext) 1635 prefixContext->SetStatus(MultikeyContext::kMKpartialMatch); 1636 return false; 1637 } 1490 1638 } 1491 1492 if (d->keyContexts.value(context)) 1493 d->keyContexts.value(context)->GetMapping(keynum, actions); 1494 1495 if (context != "Global") 1496 d->keyContexts.value("Global")->GetMapping(keynum, actions); 1497 1639 if (prefixContext) 1640 prefixContext->SetStatus(wasEmpty ? MultikeyContext::kMKnoPrefix : 1641 MultikeyContext::kMKbadMatch); 1498 1642 return false; 1499 1643 } 1500 1644 … … void MythMainWindow::ClearKeyContext(const QString &context) 1523 1667 } 1524 1668 1525 1669 void MythMainWindow::BindKey(const QString &context, const QString &action, 1526 const QString &key )1670 const QString &key, const QString &multikey) 1527 1671 { 1528 1672 QKeySequence keyseq(key); 1529 1673 … … void MythMainWindow::BindKey(const QString &context, const QString &action, 1551 1695 if (action == "ESCAPE" && context == "Global" && i == 0) 1552 1696 d->escapekey = keynum; 1553 1697 } 1698 1699 QStringList multidummyaction(""); 1700 if (d->keyContexts.value(context)->multiData.GetMultikeyMapping(multikey, multidummyaction)) 1701 { 1702 VERBOSE(VB_GENERAL, QString("Multikey %1 is bound to multiple actions " 1703 "in context %2.") 1704 .arg(multikey).arg(context)); 1705 } 1706 d->keyContexts.value(context)->multiData.AddMultikeyMapping(multikey, action); 1554 1707 } 1555 1708 1556 1709 void MythMainWindow::RegisterKey(const QString &context, const QString &action, 1557 1710 const QString &description, const QString &key) 1558 1711 { 1559 1712 QString keybind = key; 1713 QString multikeybind = ""; 1560 1714 1561 1715 MSqlQuery query(MSqlQuery::InitCon()); 1562 1716 1563 1717 if (d->m_useDB && query.isConnected()) 1564 1718 { 1565 query.prepare("SELECT keylist, description FROM keybindings WHERE "1719 query.prepare("SELECT keylist, description, multikey FROM keybindings WHERE " 1566 1720 "context = :CONTEXT AND action = :ACTION AND " 1567 1721 "hostname = :HOSTNAME ;"); 1568 1722 query.bindValue(":CONTEXT", context); … … void MythMainWindow::RegisterKey(const QString &context, const QString &action, 1573 1727 { 1574 1728 keybind = query.value(0).toString(); 1575 1729 QString db_description = query.value(1).toString(); 1730 multikeybind = query.value(2).toString(); 1576 1731 1577 1732 // Update keybinding description if changed 1578 1733 if (db_description != description) … … void MythMainWindow::RegisterKey(const QString &context, const QString &action, 1599 1754 else 1600 1755 { 1601 1756 QString inskey = keybind; 1757 QString insmultikey = multikeybind; 1602 1758 1603 1759 query.prepare("INSERT INTO keybindings (context, action, " 1604 "description, keylist, hostname ) VALUES "1760 "description, keylist, hostname, multikey) VALUES " 1605 1761 "( :CONTEXT, :ACTION, :DESCRIPTION, :KEYLIST, " 1606 ":HOSTNAME );");1762 ":HOSTNAME, :MULTIKEY );"); 1607 1763 query.bindValue(":CONTEXT", context); 1608 1764 query.bindValue(":ACTION", action); 1609 1765 query.bindValue(":DESCRIPTION", description); 1610 1766 query.bindValue(":KEYLIST", inskey); 1611 1767 query.bindValue(":HOSTNAME", GetMythDB()->GetHostName()); 1768 query.bindValue(":MULTIKEY", insmultikey); 1612 1769 1613 1770 if (!query.exec() && !(GetMythDB()->SuppressDBMessages())) 1614 1771 { … … void MythMainWindow::RegisterKey(const QString &context, const QString &action, 1617 1774 } 1618 1775 } 1619 1776 1620 BindKey(context, action, keybind );1777 BindKey(context, action, keybind, multikeybind); 1621 1778 } 1622 1779 1623 1780 QString MythMainWindow::GetKey(const QString &context, … … void MythMainWindow::ClearJump(const QString &destination) 1662 1819 } 1663 1820 1664 1821 1665 void MythMainWindow::BindJump(const QString &destination, const QString &key) 1822 void MythMainWindow::BindJump(const QString &destination, const QString &key, 1823 const QString &multikey) 1666 1824 { 1667 1825 /* make sure the jump point exists */ 1668 1826 if (d->destinationMap.find(destination) == d->destinationMap.end()) … … void MythMainWindow::BindJump(const QString &destination, const QString &key) 1684 1842 // .arg(keybind).arg(destination)); 1685 1843 1686 1844 d->jumpMap[keynum] = &d->destinationMap[destination]; 1845 d->jumpMultikeyData.AddMultikeyMapping(QKeySequence(keynum).toString(), destination); 1687 1846 } 1688 1847 else 1689 1848 { … … void MythMainWindow::BindJump(const QString &destination, const QString &key) 1695 1854 // VERBOSE(VB_GENERAL, QString("JumpPoint: %2 exists, no keybinding") 1696 1855 // .arg(destination)); 1697 1856 1857 d->jumpMultikeyData.AddMultikeyMapping(multikey, destination); 1698 1858 } 1699 1859 1700 1860 void MythMainWindow::RegisterJump(const QString &destination, … … void MythMainWindow::RegisterJump(const QString &destination, 1703 1863 bool exittomain, QString localAction) 1704 1864 { 1705 1865 QString keybind = key; 1866 QString multikeybind = ""; 1706 1867 1707 1868 MSqlQuery query(MSqlQuery::InitCon()); 1708 1869 if (query.isConnected()) 1709 1870 { 1710 query.prepare("SELECT keylist FROM jumppoints WHERE "1871 query.prepare("SELECT keylist, multikey FROM jumppoints WHERE " 1711 1872 "destination = :DEST and hostname = :HOST ;"); 1712 1873 query.bindValue(":DEST", destination); 1713 1874 query.bindValue(":HOST", GetMythDB()->GetHostName()); … … void MythMainWindow::RegisterJump(const QString &destination, 1715 1876 if (query.exec() && query.next()) 1716 1877 { 1717 1878 keybind = query.value(0).toString(); 1879 multikeybind = query.value(1).toString(); 1718 1880 } 1719 1881 else 1720 1882 { 1721 1883 QString inskey = keybind; 1884 QString insmultikey = multikeybind; 1722 1885 1723 1886 query.prepare("INSERT INTO jumppoints (destination, description, " 1724 "keylist, hostname ) VALUES ( :DEST, :DESC, :KEYLIST, "1725 ":HOST );");1887 "keylist, hostname, multikey) VALUES ( :DEST, :DESC, :KEYLIST, " 1888 ":HOST, :MULTIKEY );"); 1726 1889 query.bindValue(":DEST", destination); 1727 1890 query.bindValue(":DESC", description); 1728 1891 query.bindValue(":KEYLIST", inskey); 1729 1892 query.bindValue(":HOST", GetMythDB()->GetHostName()); 1893 query.bindValue(":MULTIKEY", insmultikey); 1730 1894 1731 1895 if (!query.exec() || !query.isActive()) 1732 1896 { … … void MythMainWindow::RegisterJump(const QString &destination, 1739 1903 { callback, destination, description, exittomain, localAction }; 1740 1904 d->destinationMap[destination] = jd; 1741 1905 1742 BindJump(destination, keybind );1906 BindJump(destination, keybind, multikeybind); 1743 1907 } 1744 1908 1745 1909 void MythMainWindow::JumpTo(const QString& destination, bool pop) -
mythtv/libs/libmythui/mythmainwindow.h
diff --git a/mythtv/libs/libmythui/mythmainwindow.h b/mythtv/libs/libmythui/mythmainwindow.h index c007067..566d1c0 100644
a b class MythPainterWindowVDPAU; 27 27 class MythPainterWindowD3D9; 28 28 class MythRender; 29 29 30 class MultikeyContext 31 { 32 public: 33 enum MultikeyStatus { 34 kMKnoPrefix, 35 kMKpartialMatch, 36 kMKfullMatch, 37 kMKbadMatch 38 }; 39 MultikeyContext(void) 40 : oldPrefix(""), currentPrefix(""), status(kMKnoPrefix) {} 41 void SetStatus(MultikeyStatus why) { status = why; } 42 const QString &GetPrefix(void) { return currentPrefix; } 43 bool AddKey(int key); 44 void Commit(MultikeyStatus &s, QString &prefix) { 45 prefix = currentPrefix; 46 s = status; 47 if (status != kMKpartialMatch) 48 { 49 currentPrefix = ""; 50 status = kMKnoPrefix; 51 } 52 oldPrefix = currentPrefix; 53 } 54 private: 55 QString oldPrefix; 56 QString currentPrefix; 57 MultikeyStatus status; 58 }; 59 30 60 class MUI_PUBLIC MythMainWindow : public QWidget 31 61 { 32 62 Q_OBJECT … … class MUI_PUBLIC MythMainWindow : public QWidget 48 78 MythScreenStack *GetStackAt(int pos); 49 79 50 80 bool TranslateKeyPress(const QString &context, QKeyEvent *e, 51 QStringList &actions, bool allowJumps = true) 81 QStringList &actions, bool allowJumps = true, 82 MultikeyContext *prefixContext = NULL) 52 83 MUNUSED_RESULT; 53 84 54 85 void ResetKeys(void); 55 86 void ClearKey(const QString &context, const QString &action); 56 87 void ClearKeyContext(const QString &context); 57 88 void BindKey(const QString &context, const QString &action, 58 const QString &key );89 const QString &key, const QString &multikey); 59 90 void RegisterKey(const QString &context, const QString &action, 60 91 const QString &description, const QString &key); 61 92 QString GetKey(const QString &context, const QString &action) const; 62 93 63 94 void ClearJump(const QString &destination); 64 void BindJump(const QString &destination, const QString &key); 95 void BindJump(const QString &destination, const QString &key, 96 const QString &multikey); 65 97 void RegisterJump(const QString &destination, const QString &description, 66 98 const QString &key, void (*callback)(void), 67 99 bool exittomain = true, QString localAction = ""); -
mythtv/programs/mythfrontend/keybindings.cpp
diff --git a/mythtv/programs/mythfrontend/keybindings.cpp b/mythtv/programs/mythfrontend/keybindings.cpp index e15de26..d099923 100644
a b void KeyBindings::CommitAction(const ActionID &id) 283 283 } 284 284 285 285 GetMythMainWindow()->ClearKey(id.GetContext(), id.GetAction()); 286 GetMythMainWindow()->BindKey(id.GetContext(), id.GetAction(), keys );286 GetMythMainWindow()->BindKey(id.GetContext(), id.GetAction(), keys, ""); 287 287 } 288 288 289 289 /** \fn KeyBindings::CommitJumppoint(const ActionID&) … … void KeyBindings::CommitJumppoint(const ActionID &id) 312 312 } 313 313 314 314 GetMythMainWindow()->ClearJump(id.GetAction()); 315 GetMythMainWindow()->BindJump(id.GetAction(), keys); 315 // XXX- The following line causes the jumppoint editor to erase 316 // from memory (but not from the database) any existing multikey 317 // binding for the jumppoint. Fixing this would require further 318 // digging into action{,set}.{h,cpp}. 319 GetMythMainWindow()->BindJump(id.GetAction(), keys, ""); 316 320 } 317 321 318 322 /** \fn KeyBindings::CommitChanges(void)