Merge pull request #22816 from CastagnaIT/fix_tx3g
[xbmc.git] / xbmc / dialogs / GUIDialogKeyboardGeneric.cpp
blob388cf0fdca593ace51c5c1adc83d3c1a1d43cf3a
1 /*
2 * Copyright (C) 2012-2018 Team Kodi
3 * This file is part of Kodi - https://kodi.tv
5 * SPDX-License-Identifier: GPL-2.0-or-later
6 * See LICENSES/README.md for more information.
7 */
9 #include "GUIDialogKeyboardGeneric.h"
11 #include "GUIDialogNumeric.h"
12 #include "GUIUserMessages.h"
13 #include "ServiceBroker.h"
14 #include "dialogs/GUIDialogKaiToast.h"
15 #include "guilib/GUIComponent.h"
16 #include "guilib/GUIEditControl.h"
17 #include "guilib/GUILabelControl.h"
18 #include "guilib/GUIWindowManager.h"
19 #include "guilib/LocalizeStrings.h"
20 #include "input/InputCodingTable.h"
21 #include "input/Key.h"
22 #include "input/KeyboardLayoutManager.h"
23 #include "input/XBMC_vkeys.h"
24 #include "interfaces/AnnouncementManager.h"
25 #include "messaging/ApplicationMessenger.h"
26 #include "settings/Settings.h"
27 #include "settings/SettingsComponent.h"
28 #include "speech/ISpeechRecognition.h"
29 #include "speech/ISpeechRecognitionListener.h"
30 #include "speech/SpeechRecognitionErrors.h"
31 #include "utils/CharsetConverter.h"
32 #include "utils/RegExp.h"
33 #include "utils/StringUtils.h"
34 #include "utils/Variant.h"
35 #include "utils/log.h"
36 #include "windowing/WinSystem.h"
38 #include <mutex>
40 using namespace KODI::MESSAGING;
42 #define BUTTON_ID_OFFSET 100
43 #define BUTTONS_PER_ROW 20
44 #define BUTTONS_MAX_ROWS 4
46 #define CTL_BUTTON_DONE 300
47 #define CTL_BUTTON_CANCEL 301
48 #define CTL_BUTTON_SHIFT 302
49 #define CTL_BUTTON_CAPS 303
50 #define CTL_BUTTON_SYMBOLS 304
51 #define CTL_BUTTON_LEFT 305
52 #define CTL_BUTTON_RIGHT 306
53 #define CTL_BUTTON_IP_ADDRESS 307
54 #define CTL_BUTTON_CLEAR 308
55 #define CTL_BUTTON_LAYOUT 309
56 #define CTL_BUTTON_REVEAL 310
57 #define CTL_LABEL_HEADING 311
58 #define CTL_EDIT 312
59 #define CTL_LABEL_HZCODE 313
60 #define CTL_LABEL_HZLIST 314
62 #define CTL_BUTTON_BACKSPACE 8
63 #define CTL_BUTTON_SPACE 32
65 #define SEARCH_DELAY 1000
67 class CSpeechRecognitionListener : public speech::ISpeechRecognitionListener
69 public:
70 CSpeechRecognitionListener(int dialogId) : m_dialogId(dialogId) {}
72 void OnReadyForSpeech() override
74 CGUIDialogKaiToast::QueueNotification(CGUIDialogKaiToast::Info,
75 g_localizeStrings.Get(39177), // Speech to text
76 g_localizeStrings.Get(39179)); // Listening...
79 void OnError(int recognitionError) override
81 uint32_t msgId = 0;
82 switch (recognitionError)
84 case speech::RecognitionError::SERVICE_NOT_AVAILABLE:
85 msgId = 39178; // Speech recognition service not available
86 break;
87 case speech::RecognitionError::NO_MATCH:
88 msgId = 39180; // No recognition result matched
89 break;
90 case speech::RecognitionError::INSUFFICIENT_PERMISSIONS:
91 msgId = 39185; // Insufficient permissions for speech recognition
92 break;
93 default:
94 msgId = 39181; // Speech recognition error
95 break;
98 CGUIDialogKaiToast::QueueNotification(CGUIDialogKaiToast::Error,
99 g_localizeStrings.Get(39177), // Speech to text
100 g_localizeStrings.Get(msgId));
103 void OnResults(const std::vector<std::string>& results) override
105 if (!results.empty())
107 CGUIMessage msg(GUI_MSG_SET_TEXT, m_dialogId, CTL_EDIT);
108 msg.SetLabel(results.front());
110 // dispatch to GUI thread
111 CServiceBroker::GetAppMessenger()->SendGUIMessage(msg, m_dialogId);
115 private:
116 const int m_dialogId{0};
119 CGUIDialogKeyboardGeneric::CGUIDialogKeyboardGeneric()
120 : CGUIDialog(WINDOW_DIALOG_KEYBOARD, "DialogKeyboard.xml")
121 , CGUIKeyboard()
122 , m_pCharCallback(NULL)
124 m_bIsConfirmed = false;
125 m_bShift = false;
126 m_hiddenInput = false;
127 m_keyType = LOWER;
128 m_currentLayout = 0;
129 m_loadType = KEEP_IN_MEMORY;
130 m_isKeyboardNavigationMode = false;
131 m_previouslyFocusedButton = 0;
132 m_pos = 0;
133 m_listwidth = 600;
136 void CGUIDialogKeyboardGeneric::OnWindowLoaded()
138 CGUIEditControl *edit = static_cast<CGUIEditControl*>(GetControl(CTL_EDIT));
139 if (edit)
141 // add control CTL_LABEL_HZCODE and CTL_LABEL_HZLIST if not exist
142 CGUIControlGroup *ParentControl = static_cast<CGUIControlGroup*>(edit->GetParentControl());
143 CLabelInfo labelInfo = edit->GetLabelInfo();
144 float px = edit->GetXPosition();
145 float py = edit->GetYPosition();
146 float pw = edit->GetWidth();
147 float ph = edit->GetHeight();
149 CGUILabelControl* control = static_cast<CGUILabelControl*>(GetControl(CTL_LABEL_HZCODE));
150 if (!control)
152 control = new CGUILabelControl(GetID(), CTL_LABEL_HZCODE, px, py + ph, 90, 30, labelInfo, false, false);
153 ParentControl->AddControl(control);
156 control = static_cast<CGUILabelControl*>(GetControl(CTL_LABEL_HZLIST));
157 if (!control)
159 labelInfo.align = XBFONT_CENTER_Y;
160 control = new CGUILabelControl(GetID(), CTL_LABEL_HZLIST, px + 95, py + ph, pw - 95, 30, labelInfo, false, false);
161 ParentControl->AddControl(control);
165 CGUIDialog::OnWindowLoaded();
168 void CGUIDialogKeyboardGeneric::OnInitWindow()
170 CGUIDialog::OnInitWindow();
172 m_bIsConfirmed = false;
173 m_isKeyboardNavigationMode = false;
175 // fill in the keyboard layouts
176 m_currentLayout = 0;
177 m_layouts.clear();
178 const KeyboardLayouts& keyboardLayouts = CServiceBroker::GetKeyboardLayoutManager()->GetLayouts();
179 const std::shared_ptr<CSettings> settings = CServiceBroker::GetSettingsComponent()->GetSettings();
180 std::vector<CVariant> layoutNames = settings->GetList(CSettings::SETTING_LOCALE_KEYBOARDLAYOUTS);
181 std::string activeLayout = settings->GetString(CSettings::SETTING_LOCALE_ACTIVEKEYBOARDLAYOUT);
183 for (const auto& layoutName : layoutNames)
185 const auto keyboardLayout = keyboardLayouts.find(layoutName.asString());
186 if (keyboardLayout != keyboardLayouts.end())
188 m_layouts.emplace_back(keyboardLayout->second);
189 if (layoutName.asString() == activeLayout)
190 m_currentLayout = m_layouts.size() - 1;
194 // set alphabetic (capitals)
195 UpdateButtons();
197 // set heading
198 if (!m_strHeading.empty())
200 SET_CONTROL_LABEL(CTL_LABEL_HEADING, m_strHeading);
201 SET_CONTROL_VISIBLE(CTL_LABEL_HEADING);
203 else
205 SET_CONTROL_HIDDEN(CTL_LABEL_HEADING);
207 // set type
209 CGUIMessage msg(GUI_MSG_SET_TYPE, GetID(), CTL_EDIT, m_hiddenInput ? CGUIEditControl::INPUT_TYPE_PASSWORD : CGUIEditControl::INPUT_TYPE_TEXT);
210 OnMessage(msg);
212 if (m_hiddenInput)
214 SET_CONTROL_VISIBLE(CTL_BUTTON_REVEAL);
215 SET_CONTROL_LABEL(CTL_BUTTON_REVEAL, g_localizeStrings.Get(12308));
217 else
218 SET_CONTROL_HIDDEN(CTL_BUTTON_REVEAL);
220 SetEditText(m_text);
222 // get HZLIST label options
223 CGUILabelControl* pEdit = static_cast<CGUILabelControl*>(GetControl(CTL_LABEL_HZLIST));
224 CLabelInfo labelInfo = pEdit->GetLabelInfo();
225 m_listfont = labelInfo.font;
226 m_listwidth = pEdit->GetWidth();
227 m_hzcode.clear();
228 m_words.clear();
229 SET_CONTROL_LABEL(CTL_LABEL_HZCODE, "");
230 SET_CONTROL_LABEL(CTL_LABEL_HZLIST, "");
232 CVariant data;
233 data["title"] = m_strHeading;
234 data["type"] = !m_hiddenInput ? "keyboard" : "password";
235 data["value"] = GetText();
236 CServiceBroker::GetAnnouncementManager()->Announce(ANNOUNCEMENT::Input, "OnInputRequested", data);
239 bool CGUIDialogKeyboardGeneric::OnAction(const CAction &action)
241 int actionId = action.GetID();
242 bool handled = true;
243 if (actionId == (KEY_VKEY | XBMCVK_BACK))
244 Backspace();
245 else if (actionId == ACTION_ENTER ||
246 (actionId == ACTION_SELECT_ITEM && (m_isKeyboardNavigationMode || GetFocusedControlID() == CTL_EDIT)))
247 OnOK();
248 else if (actionId == ACTION_SHIFT)
249 OnShift();
250 else if (actionId == ACTION_SYMBOLS)
251 OnSymbols();
252 // don't handle move left/right and select in the edit control
253 else if (!m_isKeyboardNavigationMode &&
254 (actionId == ACTION_MOVE_LEFT ||
255 actionId == ACTION_MOVE_RIGHT ||
256 actionId == ACTION_SELECT_ITEM))
257 handled = false;
258 else if (actionId == ACTION_VOICE_RECOGNIZE)
259 OnVoiceRecognition();
260 else
262 std::wstring wch = L"";
263 wch.insert(wch.begin(), action.GetUnicode());
264 std::string ch;
265 g_charsetConverter.wToUTF8(wch, ch);
266 handled = CodingCharacter(ch);
267 if (!handled)
269 // send action to edit control
270 CGUIControl *edit = GetControl(CTL_EDIT);
271 if (edit)
272 handled = edit->OnAction(action);
273 if (!handled && actionId >= KEY_VKEY && actionId < KEY_UNICODE)
275 unsigned char b = actionId & 0xFF;
276 if (b == XBMCVK_TAB)
278 // Toggle left/right key mode
279 m_isKeyboardNavigationMode = !m_isKeyboardNavigationMode;
280 if (m_isKeyboardNavigationMode)
282 m_previouslyFocusedButton = GetFocusedControlID();
283 SET_CONTROL_FOCUS(edit->GetID(), 0);
285 else
286 SET_CONTROL_FOCUS(m_previouslyFocusedButton, 0);
287 handled = true;
293 if (!handled) // unhandled by us - let's see if the baseclass wants it
294 handled = CGUIDialog::OnAction(action);
296 return handled;
299 bool CGUIDialogKeyboardGeneric::OnMessage(CGUIMessage& message)
301 switch ( message.GetMessage() )
303 case GUI_MSG_CLICKED:
305 int iControl = message.GetSenderId();
307 switch (iControl)
309 case CTL_BUTTON_DONE:
310 OnOK();
311 break;
312 case CTL_BUTTON_CANCEL:
313 Close();
314 break;
315 case CTL_BUTTON_SHIFT:
316 OnShift();
317 break;
318 case CTL_BUTTON_CAPS:
319 if (m_keyType == LOWER)
320 m_keyType = CAPS;
321 else if (m_keyType == CAPS)
322 m_keyType = LOWER;
323 UpdateButtons();
324 break;
325 case CTL_BUTTON_LAYOUT:
326 OnLayout();
327 break;
328 case CTL_BUTTON_REVEAL:
329 OnReveal();
330 break;
331 case CTL_BUTTON_SYMBOLS:
332 OnSymbols();
333 break;
334 case CTL_BUTTON_LEFT:
335 MoveCursor( -1);
336 break;
337 case CTL_BUTTON_RIGHT:
338 MoveCursor(1);
339 break;
340 case CTL_BUTTON_IP_ADDRESS:
341 OnIPAddress();
342 break;
343 case CTL_BUTTON_CLEAR:
344 SetEditText("");
345 break;
346 case CTL_EDIT:
348 CGUIMessage msg(GUI_MSG_ITEM_SELECTED, GetID(), CTL_EDIT);
349 OnMessage(msg);
350 // update callback I guess?
351 if (m_pCharCallback)
352 { // we did _something_, so make sure our search message filter is reset
353 m_pCharCallback(this, msg.GetLabel());
355 m_text = msg.GetLabel();
356 return true;
358 default:
359 OnClickButton(iControl);
360 break;
363 break;
365 case GUI_MSG_SET_TEXT:
367 // the edit control only handles these messages if it is either focused
368 // or its specific control ID is set in the message. As neither is the
369 // case here (focus is on one of the keyboard buttons) we have to force
370 // the control ID of the message to the control ID of the edit control
371 // (unfortunately we have to create a whole copy of the message object for that)
372 CGUIMessage messageCopy(message.GetMessage(), message.GetSenderId(), CTL_EDIT, message.GetParam1(), message.GetParam2(), message.GetItem());
373 messageCopy.SetLabel(message.GetLabel());
375 // ensure this goes to the edit control
376 CGUIControl *edit = GetControl(CTL_EDIT);
377 if (edit)
378 edit->OnMessage(messageCopy);
380 // close the dialog if requested
381 if (message.GetMessage() == GUI_MSG_SET_TEXT && message.GetParam1() > 0)
382 OnOK();
383 return true;
385 case GUI_MSG_CODINGTABLE_LOOKUP_COMPLETED:
387 const std::string& code = message.GetStringParam();
388 if (code == m_hzcode)
390 int response = message.GetParam1();
391 auto words = m_codingtable->GetResponse(response);
392 m_words.insert(m_words.end(), words.begin(), words.end());
393 ShowWordList(0);
398 return CGUIDialog::OnMessage(message);
401 void CGUIDialogKeyboardGeneric::SetEditText(const std::string &text)
403 CGUIMessage msg(GUI_MSG_SET_TEXT, GetID(), CTL_EDIT);
404 msg.SetLabel(text);
405 OnMessage(msg);
408 void CGUIDialogKeyboardGeneric::SetText(const std::string& text)
410 m_text = text;
413 const std::string &CGUIDialogKeyboardGeneric::GetText() const
415 return m_text;
418 void CGUIDialogKeyboardGeneric::Character(const std::string &ch)
420 if (ch.empty()) return;
421 if (!CodingCharacter(ch))
422 NormalCharacter(ch);
425 void CGUIDialogKeyboardGeneric::NormalCharacter(const std::string &ch)
427 // send text to edit control
428 CGUIControl *edit = GetControl(CTL_EDIT);
429 if (edit)
431 CAction action(ACTION_INPUT_TEXT);
432 action.SetText(ch);
433 edit->OnAction(action);
437 void CGUIDialogKeyboardGeneric::Backspace()
439 if (m_codingtable && m_hzcode.length() > 0)
441 std::wstring tmp;
442 g_charsetConverter.utf8ToW(m_hzcode, tmp);
443 tmp.erase(tmp.length() - 1, 1);
444 g_charsetConverter.wToUTF8(tmp, m_hzcode);
446 switch (m_codingtable->GetType())
448 case IInputCodingTable::TYPE_WORD_LIST:
449 SetControlLabel(CTL_LABEL_HZCODE, m_hzcode);
450 ChangeWordList(0);
451 break;
453 case IInputCodingTable::TYPE_CONVERT_STRING:
454 SetEditText(m_codingtable->ConvertString(m_hzcode));
455 break;
458 else
460 // send action to edit control
461 CGUIControl *edit = GetControl(CTL_EDIT);
462 if (edit)
463 edit->OnAction(CAction(ACTION_BACKSPACE));
465 if (m_codingtable && m_codingtable->GetType() == IInputCodingTable::TYPE_CONVERT_STRING)
466 m_codingtable->SetTextPrev(GetText());
470 void CGUIDialogKeyboardGeneric::OnClickButton(int iButtonControl)
472 if (iButtonControl == CTL_BUTTON_BACKSPACE)
474 Backspace();
476 else if (iButtonControl == CTL_BUTTON_SPACE)
478 Character(" ");
480 else
482 const CGUIControl* pButton = GetControl(iButtonControl);
483 // Do not register input for buttons with id >= 500
484 if (pButton && iButtonControl < 500)
486 Character(pButton->GetDescription());
487 // reset the shift keys
488 if (m_bShift) OnShift();
493 void CGUIDialogKeyboardGeneric::UpdateButtons()
495 SET_CONTROL_SELECTED(GetID(), CTL_BUTTON_SHIFT, m_bShift);
496 SET_CONTROL_SELECTED(GetID(), CTL_BUTTON_CAPS, m_keyType == CAPS);
497 SET_CONTROL_SELECTED(GetID(), CTL_BUTTON_SYMBOLS, m_keyType == SYMBOLS);
499 if (m_currentLayout >= m_layouts.size())
500 m_currentLayout = 0;
501 CKeyboardLayout layout = m_layouts.empty() ? CKeyboardLayout() : m_layouts[m_currentLayout];
502 m_codingtable = layout.GetCodingTable();
503 if (m_codingtable && !m_codingtable->IsInitialized())
504 m_codingtable->Initialize();
506 bool bShowWordList = false;
507 if (m_codingtable)
509 switch (m_codingtable->GetType())
511 case IInputCodingTable::TYPE_WORD_LIST:
512 bShowWordList = true;
513 break;
515 case IInputCodingTable::TYPE_CONVERT_STRING:
516 m_codingtable->SetTextPrev(GetText());
517 m_hzcode.clear();
518 break;
522 if (bShowWordList)
524 SET_CONTROL_VISIBLE(CTL_LABEL_HZCODE);
525 SET_CONTROL_VISIBLE(CTL_LABEL_HZLIST);
527 else
529 SET_CONTROL_HIDDEN(CTL_LABEL_HZCODE);
530 SET_CONTROL_HIDDEN(CTL_LABEL_HZLIST);
532 SET_CONTROL_LABEL(CTL_BUTTON_LAYOUT, layout.GetName());
534 unsigned int modifiers = CKeyboardLayout::ModifierKeyNone;
535 if ((m_keyType == CAPS && !m_bShift) || (m_keyType == LOWER && m_bShift))
536 modifiers |= CKeyboardLayout::ModifierKeyShift;
537 if (m_keyType == SYMBOLS)
539 modifiers |= CKeyboardLayout::ModifierKeySymbol;
540 if (m_bShift)
541 modifiers |= CKeyboardLayout::ModifierKeyShift;
544 for (unsigned int row = 0; row < BUTTONS_MAX_ROWS; row++)
546 for (unsigned int column = 0; column < BUTTONS_PER_ROW; column++)
548 int buttonID = (row * BUTTONS_PER_ROW) + column + BUTTON_ID_OFFSET;
549 std::string label = layout.GetCharAt(row, column, modifiers);
550 SetControlLabel(buttonID, label);
551 if (!label.empty())
552 SET_CONTROL_VISIBLE(buttonID);
553 else
554 SET_CONTROL_HIDDEN(buttonID);
559 void CGUIDialogKeyboardGeneric::OnDeinitWindow(int nextWindowID)
561 for (auto& layout : m_layouts)
563 auto codingTable = layout.GetCodingTable();
564 if (codingTable && codingTable->IsInitialized())
565 codingTable->Deinitialize();
567 // call base class
568 CGUIDialog::OnDeinitWindow(nextWindowID);
569 // reset the heading (we don't always have this)
570 m_strHeading = "";
572 CServiceBroker::GetAnnouncementManager()->Announce(ANNOUNCEMENT::Input, "OnInputFinished");
575 void CGUIDialogKeyboardGeneric::MoveCursor(int iAmount)
577 if (m_codingtable && m_words.size())
578 ChangeWordList(iAmount);
579 else
581 CGUIControl *edit = GetControl(CTL_EDIT);
582 if (edit)
583 edit->OnAction(CAction(iAmount < 0 ? ACTION_CURSOR_LEFT : ACTION_CURSOR_RIGHT));
587 void CGUIDialogKeyboardGeneric::OnLayout()
589 m_currentLayout++;
590 if (m_currentLayout >= m_layouts.size())
591 m_currentLayout = 0;
592 CKeyboardLayout layout = m_layouts.empty() ? CKeyboardLayout() : m_layouts[m_currentLayout];
593 CServiceBroker::GetSettingsComponent()->GetSettings()->SetString(CSettings::SETTING_LOCALE_ACTIVEKEYBOARDLAYOUT, layout.GetName());
594 UpdateButtons();
597 void CGUIDialogKeyboardGeneric::OnSymbols()
599 if (m_keyType == SYMBOLS)
600 m_keyType = LOWER;
601 else
602 m_keyType = SYMBOLS;
603 UpdateButtons();
606 void CGUIDialogKeyboardGeneric::OnReveal()
608 m_hiddenInput = !m_hiddenInput;
609 SET_CONTROL_LABEL(CTL_BUTTON_REVEAL, g_localizeStrings.Get(m_hiddenInput ? 12308 : 12309));
610 CGUIMessage msg(GUI_MSG_SET_TYPE, GetID(), CTL_EDIT,
611 m_hiddenInput ? CGUIEditControl::INPUT_TYPE_PASSWORD
612 : CGUIEditControl::INPUT_TYPE_TEXT);
613 OnMessage(msg);
616 void CGUIDialogKeyboardGeneric::OnShift()
618 m_bShift = !m_bShift;
619 UpdateButtons();
622 void CGUIDialogKeyboardGeneric::OnIPAddress()
624 // find any IP address in the current string if there is any
625 // We match to #.#.#.#
626 std::string text = GetText();
627 std::string ip;
628 CRegExp reg;
629 reg.RegComp("[0-9]+\\.[0-9]+\\.[0-9]+\\.[0-9]+");
630 int start = reg.RegFind(text.c_str());
631 int length = 0;
632 if (start > -1)
634 length = reg.GetSubLength(0);
635 ip = text.substr(start, length);
637 else
638 start = text.size();
639 if (CGUIDialogNumeric::ShowAndGetIPAddress(ip, g_localizeStrings.Get(14068)))
640 SetEditText(text.substr(0, start) + ip + text.substr(start + length));
643 void CGUIDialogKeyboardGeneric::OnVoiceRecognition()
645 const auto speechRecognition = CServiceBroker::GetSpeechRecognition();
646 if (speechRecognition)
648 if (!m_speechRecognitionListener)
649 m_speechRecognitionListener = std::make_shared<CSpeechRecognitionListener>(GetID());
651 speechRecognition->StartSpeechRecognition(m_speechRecognitionListener);
653 else
655 CLog::LogF(LOGWARNING, "No voice recognition implementation available.");
659 void CGUIDialogKeyboardGeneric::SetControlLabel(int id, const std::string &label)
660 { // find all controls with this id, and set all their labels
661 CGUIMessage message(GUI_MSG_LABEL_SET, GetID(), id);
662 message.SetLabel(label);
663 for (unsigned int i = 0; i < m_children.size(); i++)
665 if (m_children[i]->GetID() == id || m_children[i]->IsGroup())
666 m_children[i]->OnMessage(message);
670 void CGUIDialogKeyboardGeneric::OnOK()
672 m_bIsConfirmed = true;
673 Close();
676 void CGUIDialogKeyboardGeneric::SetHeading(const std::string &heading)
678 m_strHeading = heading;
681 int CGUIDialogKeyboardGeneric::GetWindowId() const
683 return GetID();
686 void CGUIDialogKeyboardGeneric::Cancel()
688 m_bIsConfirmed = false;
689 Close();
692 bool CGUIDialogKeyboardGeneric::ShowAndGetInput(char_callback_t pCallback, const std::string &initialString, std::string &typedString, const std::string &heading, bool bHiddenInput)
694 CGUIDialogKeyboardGeneric *pKeyboard = CServiceBroker::GetGUI()->GetWindowManager().GetWindow<CGUIDialogKeyboardGeneric>(WINDOW_DIALOG_KEYBOARD);
696 if (!pKeyboard)
697 return false;
699 m_pCharCallback = pCallback;
700 // setup keyboard
701 pKeyboard->Initialize();
702 pKeyboard->SetHeading(heading);
703 pKeyboard->SetHiddenInput(bHiddenInput);
704 pKeyboard->SetText(initialString);
705 pKeyboard->Open();
706 pKeyboard->Close();
708 // If have text - update this.
709 if (pKeyboard->IsConfirmed())
711 typedString = pKeyboard->GetText();
712 return true;
714 else return false;
717 float CGUIDialogKeyboardGeneric::GetStringWidth(const std::wstring & utf16)
719 vecText utf32;
721 utf32.resize(utf16.size());
722 for (unsigned int i = 0; i < utf16.size(); i++)
723 utf32[i] = utf16[i];
725 return m_listfont->GetTextWidth(utf32);
728 void CGUIDialogKeyboardGeneric::ChangeWordList(int direct)
730 if (direct == 0)
732 m_pos = 0;
733 m_words.clear();
734 m_codingtable->GetWordListPage(m_hzcode, true);
736 else
738 ShowWordList(direct);
739 if (direct > 0 && m_pos + m_num == static_cast<int>(m_words.size()))
740 m_codingtable->GetWordListPage(m_hzcode, false);
744 void CGUIDialogKeyboardGeneric::ShowWordList(int direct)
746 std::unique_lock<CCriticalSection> lock(m_CS);
747 std::wstring hzlist = L"";
748 CServiceBroker::GetWinSystem()->GetGfxContext().SetScalingResolution(m_coordsRes, true);
749 float width = m_listfont->GetCharWidth(L'<') + m_listfont->GetCharWidth(L'>');
750 float spacewidth = m_listfont->GetCharWidth(L' ');
751 float numwidth = m_listfont->GetCharWidth(L'1') + m_listfont->GetCharWidth(L'.');
752 int i;
754 if (direct >= 0)
756 if (direct > 0)
757 m_pos += m_num;
758 if (m_pos > static_cast<int>(m_words.size()) - 1)
759 m_pos = 0;
760 for (i = 0; m_pos + i < static_cast<int>(m_words.size()); i++)
762 if ((i > 0 && width + GetStringWidth(m_words[m_pos + i]) + numwidth > m_listwidth) || i > 9)
763 break;
764 hzlist.insert(hzlist.length(), 1, (wchar_t)(i + 48));
765 hzlist.insert(hzlist.length(), 1, L'.');
766 hzlist.append(m_words[m_pos + i]);
767 hzlist.insert(hzlist.length(), 1, L' ');
768 width += GetStringWidth(m_words[m_pos + i]) + numwidth + spacewidth;
770 m_num = i;
772 else
774 if (m_pos == 0)
775 return;
776 for (i = 1; i <= 10; i++)
778 if (m_pos - i < 0 || (i > 1 && width + GetStringWidth(m_words[m_pos - i]) + numwidth > m_listwidth))
779 break;
780 width += GetStringWidth(m_words[m_pos - i]) + numwidth + spacewidth;
782 m_num = --i;
783 m_pos -= m_num;
784 for (i = 0; i < m_num; i++)
786 hzlist.insert(hzlist.length(), 1, (wchar_t)(i + 48));
787 hzlist.insert(hzlist.length(), 1, L'.');
788 hzlist.append(m_words[m_pos + i]);
789 hzlist.insert(hzlist.length(), 1, L' ');
792 hzlist.erase(hzlist.find_last_not_of(L' ') + 1);
793 if (m_pos > 0)
794 hzlist.insert(0, 1, L'<');
795 if (m_pos + m_num < static_cast<int>(m_words.size()))
796 hzlist.insert(hzlist.length(), 1, L'>');
797 std::string utf8String;
798 g_charsetConverter.wToUTF8(hzlist, utf8String);
799 SET_CONTROL_LABEL(CTL_LABEL_HZLIST, utf8String);
802 bool CGUIDialogKeyboardGeneric::CodingCharacter(const std::string &ch)
804 if (!m_codingtable)
805 return false;
807 switch (m_codingtable->GetType())
809 case IInputCodingTable::TYPE_CONVERT_STRING:
810 if (!ch.empty() && ch[0] != 0)
812 m_hzcode += ch;
813 SetEditText(m_codingtable->ConvertString(m_hzcode));
814 return true;
816 break;
818 case IInputCodingTable::TYPE_WORD_LIST:
819 if (m_codingtable->GetCodeChars().find(ch) != std::string::npos)
821 m_hzcode += ch;
822 SetControlLabel(CTL_LABEL_HZCODE, m_hzcode);
823 ChangeWordList(0);
824 return true;
826 if (ch[0] >= '0' && ch[0] <= '9')
828 int i = m_pos + (int)ch[0] - 48;
829 if (i < (m_pos + m_num))
831 m_hzcode = "";
832 SetControlLabel(CTL_LABEL_HZCODE, m_hzcode);
833 std::string utf8String;
834 g_charsetConverter.wToUTF8(m_words[i], utf8String);
835 NormalCharacter(utf8String);
837 return true;
839 break;
842 return false;