vcaptain.cpp 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289
  1. #include <QtWidgets>
  2. #include <QString>
  3. #include <QDebug>
  4. #include <QShortcut>
  5. #include "vcaptain.h"
  6. #include "veditarea.h"
  7. #include "vedittab.h"
  8. #include "vfilelist.h"
  9. #include "vnavigationmode.h"
  10. #include "vconfigmanager.h"
  11. extern VConfigManager *g_config;
  12. VCaptain::VCaptain(QWidget *p_parent)
  13. : QWidget(p_parent),
  14. m_mode(CaptainMode::Normal),
  15. m_widgetBeforeCaptain(NULL),
  16. m_nextMajorKey('a'),
  17. m_ignoreFocusChange(false)
  18. {
  19. connect(qApp, &QApplication::focusChanged,
  20. this, &VCaptain::handleFocusChanged);
  21. setWindowFlags(Qt::FramelessWindowHint);
  22. // Make it as small as possible. This widget will stay at the top-left corner
  23. // of VMainWindow.
  24. resize(1, 1);
  25. // Register Captain mode leader key.
  26. // This can fix the Input Method blocking issue.
  27. m_captainModeShortcut = new QShortcut(QKeySequence(g_config->getShortcutKeySequence("CaptainMode")),
  28. this);
  29. m_captainModeShortcut->setContext(Qt::ApplicationShortcut);
  30. connect(m_captainModeShortcut, &QShortcut::activated,
  31. this, &VCaptain::trigger);
  32. // Register Navigation mode as Captain mode target.
  33. registerCaptainTarget(tr("NavigationMode"),
  34. g_config->getCaptainShortcutKeySequence("NavigationMode"),
  35. this,
  36. navigationModeByCaptain);
  37. }
  38. QChar VCaptain::getNextMajorKey()
  39. {
  40. QChar ret = m_nextMajorKey;
  41. if (m_nextMajorKey == 'z') {
  42. m_nextMajorKey = QChar();
  43. } else if (!m_nextMajorKey.isNull()) {
  44. m_nextMajorKey = QChar(m_nextMajorKey.toLatin1() + 1);
  45. }
  46. return ret;
  47. }
  48. void VCaptain::registerNavigationTarget(VNavigationMode *p_target)
  49. {
  50. QChar key = getNextMajorKey();
  51. if (!key.isNull()) {
  52. p_target->registerNavigation(key);
  53. m_naviTargets.push_back(NaviModeTarget(p_target, true));
  54. }
  55. }
  56. void VCaptain::handleFocusChanged(QWidget *p_old, QWidget * p_now)
  57. {
  58. Q_UNUSED(p_now);
  59. if (p_old == this
  60. && !m_ignoreFocusChange
  61. && !checkMode(CaptainMode::Normal)) {
  62. exitCaptainMode();
  63. }
  64. }
  65. void VCaptain::trigger()
  66. {
  67. if (!checkMode(CaptainMode::Normal)) {
  68. exitCaptainMode();
  69. return;
  70. }
  71. triggerCaptainMode();
  72. }
  73. void VCaptain::keyPressEvent(QKeyEvent *p_event)
  74. {
  75. int key = p_event->key();
  76. Qt::KeyboardModifiers modifiers = p_event->modifiers();
  77. Q_ASSERT(!checkMode(CaptainMode::Normal));
  78. if (VUtils::isMetaKey(key)) {
  79. QWidget::keyPressEvent(p_event);
  80. return;
  81. }
  82. if (handleKeyPress(key, modifiers)) {
  83. p_event->accept();
  84. } else {
  85. QWidget::keyPressEvent(p_event);
  86. }
  87. }
  88. bool VCaptain::handleKeyPress(int p_key, Qt::KeyboardModifiers p_modifiers)
  89. {
  90. bool ret = true;
  91. m_ignoreFocusChange = true;
  92. if (checkMode(CaptainMode::Navigation)) {
  93. ret = handleKeyPressNavigationMode(p_key, p_modifiers);
  94. m_ignoreFocusChange = false;
  95. return ret;
  96. }
  97. ret = handleKeyPressCaptainMode(p_key, p_modifiers);
  98. m_ignoreFocusChange = false;
  99. return ret;
  100. }
  101. bool VCaptain::handleKeyPressNavigationMode(int p_key,
  102. Qt::KeyboardModifiers /* p_modifiers */)
  103. {
  104. Q_ASSERT(m_mode == CaptainMode::Navigation);
  105. bool hasConsumed = false;
  106. bool pending = false;
  107. for (auto &target : m_naviTargets) {
  108. if (hasConsumed) {
  109. target.m_available = false;
  110. target.m_target->hideNavigation();
  111. continue;
  112. }
  113. if (target.m_available) {
  114. bool succeed = false;
  115. // May change focus, so we need to ignore focus change here.
  116. bool consumed = target.m_target->handleKeyNavigation(p_key, succeed);
  117. if (consumed) {
  118. hasConsumed = true;
  119. if (succeed) {
  120. // Exit.
  121. m_widgetBeforeCaptain = NULL;
  122. } else {
  123. // Consumed but not succeed. Need more keys.
  124. pending = true;
  125. }
  126. } else {
  127. // Do not ask this target any more.
  128. target.m_available = false;
  129. target.m_target->hideNavigation();
  130. }
  131. }
  132. }
  133. if (pending) {
  134. return true;
  135. }
  136. exitCaptainMode();
  137. return true;
  138. }
  139. void VCaptain::triggerNavigationMode()
  140. {
  141. setMode(CaptainMode::Navigation);
  142. for (auto &target : m_naviTargets) {
  143. target.m_available = true;
  144. target.m_target->showNavigation();
  145. }
  146. }
  147. void VCaptain::exitNavigationMode()
  148. {
  149. setMode(CaptainMode::Normal);
  150. for (auto &target : m_naviTargets) {
  151. target.m_available = true;
  152. target.m_target->hideNavigation();
  153. }
  154. }
  155. void VCaptain::restoreFocus()
  156. {
  157. if (m_widgetBeforeCaptain) {
  158. m_widgetBeforeCaptain->setFocus();
  159. m_widgetBeforeCaptain = NULL;
  160. }
  161. }
  162. void VCaptain::exitCaptainMode()
  163. {
  164. if (checkMode(CaptainMode::Normal)) {
  165. return;
  166. } else if (checkMode(CaptainMode::Navigation)) {
  167. exitNavigationMode();
  168. }
  169. setMode(CaptainMode::Normal);
  170. m_ignoreFocusChange = false;
  171. restoreFocus();
  172. emit captainModeChanged(false);
  173. }
  174. bool VCaptain::registerCaptainTarget(const QString &p_name,
  175. const QString &p_key,
  176. void *p_target,
  177. CaptainFunc p_func)
  178. {
  179. if (p_key.isEmpty()) {
  180. return false;
  181. }
  182. QString normKey = QKeySequence(p_key).toString();
  183. if (m_captainTargets.contains(normKey)) {
  184. return false;
  185. }
  186. CaptainModeTarget target(p_name,
  187. normKey,
  188. p_target,
  189. p_func);
  190. m_captainTargets.insert(normKey, target);
  191. qDebug() << "registered:" << target.toString() << normKey;
  192. return true;
  193. }
  194. void VCaptain::triggerCaptainTarget(const QString &p_key)
  195. {
  196. auto it = m_captainTargets.find(p_key);
  197. if (it == m_captainTargets.end()) {
  198. return;
  199. }
  200. const CaptainModeTarget &target = it.value();
  201. qDebug() << "triggered:" << target.toString();
  202. CaptainData data(m_widgetBeforeCaptain);
  203. if (!target.m_function(target.m_target, (void *)&data)) {
  204. m_widgetBeforeCaptain = NULL;
  205. }
  206. }
  207. bool VCaptain::navigationModeByCaptain(void *p_target, void *p_data)
  208. {
  209. Q_UNUSED(p_data);
  210. VCaptain *obj = static_cast<VCaptain *>(p_target);
  211. obj->triggerNavigationMode();
  212. return true;
  213. }
  214. void VCaptain::triggerCaptainMode()
  215. {
  216. m_widgetBeforeCaptain = QApplication::focusWidget();
  217. m_ignoreFocusChange = false;
  218. setMode(CaptainMode::Pending);
  219. emit captainModeChanged(true);
  220. // Focus to listen pending key press.
  221. setFocus();
  222. }
  223. bool VCaptain::handleKeyPressCaptainMode(int p_key,
  224. Qt::KeyboardModifiers p_modifiers)
  225. {
  226. Q_ASSERT(checkMode(CaptainMode::Pending));
  227. QString normKey = QKeySequence(p_key | p_modifiers).toString();
  228. triggerCaptainTarget(normKey);
  229. if (!checkMode(CaptainMode::Navigation)) {
  230. exitCaptainMode();
  231. }
  232. return true;
  233. }
  234. void VCaptain::setCaptainModeEnabled(bool p_enabled)
  235. {
  236. m_captainModeShortcut->setEnabled(p_enabled);
  237. }