de1b1d49eddd8a7b97fcdab5e395c3512d2732d2
[vuplus_xbmc] / xbmc / dialogs / GUIDialogKeyboardGeneric.cpp
1 /*
2  *      Copyright (C) 2012-2013 Team XBMC
3  *      http://xbmc.org
4  *
5  *  This Program is free software; you can redistribute it and/or modify
6  *  it under the terms of the GNU General Public License as published by
7  *  the Free Software Foundation; either version 2, or (at your option)
8  *  any later version.
9  *
10  *  This Program is distributed in the hope that it will be useful,
11  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  *  GNU General Public License for more details.
14  *
15  *  You should have received a copy of the GNU General Public License
16  *  along with XBMC; see the file COPYING.  If not, see
17  *  <http://www.gnu.org/licenses/>.
18  *
19  */
20
21 #include "interfaces/AnnouncementManager.h"
22 #include "input/XBMC_vkeys.h"
23 #include "guilib/GUILabelControl.h"
24 #include "guilib/GUIWindowManager.h"
25 #include "guilib/Key.h"
26 #include "guilib/LocalizeStrings.h"
27 #include "GUIUserMessages.h"
28 #include "GUIDialogNumeric.h"
29 #include "GUIDialogOK.h"
30 #include "GUIDialogKeyboardGeneric.h"
31 #include "utils/TimeUtils.h"
32 #include "utils/RegExp.h"
33 #include "ApplicationMessenger.h"
34 #include "windowing/WindowingFactory.h"
35 #include "utils/CharsetConverter.h"
36
37 #if defined(TARGET_DARWIN)
38 #include "osx/CocoaInterface.h"
39 #endif
40
41 // Symbol mapping (based on MS virtual keyboard - may need improving)
42 static char symbol_map[37] = ")!@#$%^&*([]{}-_=+;:\'\",.<>/?\\|`~    ";
43
44 #define CTL_BUTTON_DONE       300
45 #define CTL_BUTTON_CANCEL     301
46 #define CTL_BUTTON_SHIFT      302
47 #define CTL_BUTTON_CAPS       303
48 #define CTL_BUTTON_SYMBOLS    304
49 #define CTL_BUTTON_LEFT       305
50 #define CTL_BUTTON_RIGHT      306
51 #define CTL_BUTTON_IP_ADDRESS 307
52 #define CTL_BUTTON_CLEAR      308
53
54 #define CTL_LABEL_EDIT        310
55 #define CTL_LABEL_HEADING     311
56
57 #define CTL_BUTTON_BACKSPACE    8
58
59 static char symbolButtons[] = "._-@/\\";
60 #define NUM_SYMBOLS sizeof(symbolButtons) - 1
61
62 #define SEARCH_DELAY         1000
63 #define REMOTE_SMS_DELAY     1000
64
65 CGUIDialogKeyboardGeneric::CGUIDialogKeyboardGeneric()
66 : CGUIDialog(WINDOW_DIALOG_KEYBOARD, "DialogKeyboard.xml")
67 , CGUIKeyboard()
68 , m_pCharCallback(NULL)
69 {
70   m_bIsConfirmed = false;
71   m_bShift = false;
72   m_hiddenInput = false;
73   m_keyType = LOWER;
74   m_strHeading = "";
75   m_iCursorPos = 0;
76   m_iEditingOffset = 0;
77   m_lastRemoteClickTime = 0;
78   m_loadType = KEEP_IN_MEMORY;
79 }
80
81 void CGUIDialogKeyboardGeneric::OnInitWindow()
82 {
83   CGUIDialog::OnInitWindow();
84
85   m_bIsConfirmed = false;
86
87   // set alphabetic (capitals)
88   UpdateButtons();
89
90   CGUILabelControl* pEdit = ((CGUILabelControl*)GetControl(CTL_LABEL_EDIT));
91   if (pEdit)
92   {
93     pEdit->ShowCursor();
94   }
95
96   // set heading
97   if (!m_strHeading.empty())
98   {
99     SET_CONTROL_LABEL(CTL_LABEL_HEADING, m_strHeading);
100     SET_CONTROL_VISIBLE(CTL_LABEL_HEADING);
101   }
102   else
103   {
104     SET_CONTROL_HIDDEN(CTL_LABEL_HEADING);
105   }
106   g_Windowing.EnableTextInput(true);
107
108   CVariant data;
109   data["title"] = m_strHeading;
110   data["type"] = !m_hiddenInput ? "keyboard" : "password";
111   data["value"] = GetText();
112   ANNOUNCEMENT::CAnnouncementManager::Announce(ANNOUNCEMENT::Input, "xbmc", "OnInputRequested", data);
113 }
114
115 bool CGUIDialogKeyboardGeneric::OnAction(const CAction &action)
116 {
117   bool handled(true);
118   if (action.GetID() == ACTION_BACKSPACE)
119   {
120     Backspace();
121   }
122   else if (action.GetID() == ACTION_ENTER)
123   {
124     OnOK();
125   }
126   else if (action.GetID() == ACTION_CURSOR_LEFT)
127   {
128     MoveCursor( -1);
129   }
130   else if (action.GetID() == ACTION_CURSOR_RIGHT)
131   {
132     if (m_strEditing.IsEmpty() && (unsigned int) GetCursorPos() == m_strEdit.size() && (m_strEdit.size() == 0 || m_strEdit[m_strEdit.size() - 1] != ' '))
133     { // add a space
134       Character(L' ');
135     }
136     else
137       MoveCursor(1);
138   }
139   else if (action.GetID() == ACTION_SHIFT)
140   {
141     OnShift();
142   }
143   else if (action.GetID() == ACTION_SYMBOLS)
144   {
145     OnSymbols();
146   }
147   else if (action.GetID() >= REMOTE_0 && action.GetID() <= REMOTE_9)
148   {
149     OnRemoteNumberClick(action.GetID());
150   }
151   else if (action.GetID() == ACTION_PASTE)
152   {
153     OnPasteClipboard();
154   }
155   else if (action.GetID() >= KEY_VKEY && action.GetID() < KEY_ASCII)
156   { // input from the keyboard (vkey, not ascii)
157     if (!m_strEditing.IsEmpty())
158       return handled;
159     uint8_t b = action.GetID() & 0xFF;
160     if (b == XBMCVK_HOME)
161     {
162       SetCursorPos(0);
163     }
164     else if (b == XBMCVK_END)
165     {
166       SetCursorPos(m_strEdit.GetLength());
167     }
168     else if (b == XBMCVK_LEFT)
169     {
170       MoveCursor( -1);
171     }
172     else if (b == XBMCVK_RIGHT)
173     {
174       MoveCursor(1);
175     }
176     else if (b == XBMCVK_RETURN || b == XBMCVK_NUMPADENTER)
177     {
178       OnOK();
179     }
180     else if (b == XBMCVK_DELETE)
181     {
182       if (GetCursorPos() < m_strEdit.GetLength())
183       {
184         MoveCursor(1);
185         Backspace();
186       }
187     }
188     else if (b == XBMCVK_BACK) Backspace();
189     else if (b == XBMCVK_ESCAPE) Close();
190   }
191   else if (action.GetID() >= KEY_ASCII)
192   { // input from the keyboard
193     //char ch = action.GetID() & 0xFF;
194     int ch = action.GetUnicode();
195     
196     // Ignore non-printing characters
197     if ( !((0 <= ch && ch < 0x8) || (0xE <= ch && ch < 0x1B) || (0x1C <= ch && ch < 0x20)) )
198     {
199       switch (ch)
200       {
201       case 0x8: // backspace
202         Backspace();
203         break;
204       case 0x9: // Tab (do nothing)
205       case 0xB: // Non-printing character, ignore
206       case 0xC: // Non-printing character, ignore
207         break;
208       case 0xA: // enter
209       case 0xD: // enter
210         OnOK();
211         break;
212       case 0x1B: // escape
213         Close();
214         break;
215       case 0x7F: // Delete
216         if (GetCursorPos() < m_strEdit.GetLength())
217         {
218           MoveCursor(1);
219           Backspace();
220         }
221         break;
222       default:  //use character input
223         // When we support text input method, we only accept text by gui text message.
224         if (!g_Windowing.IsTextInputEnabled())
225           Character(action.GetUnicode());
226         break;
227       }
228     }
229   }
230   else // unhandled by us - let's see if the baseclass wants it
231     handled = CGUIDialog::OnAction(action);
232
233   if (handled && m_pCharCallback)
234   { // we did _something_, so make sure our search message filter is reset
235     m_pCharCallback(this, GetText());
236   }
237   return handled;
238 }
239
240 bool CGUIDialogKeyboardGeneric::OnMessage(CGUIMessage& message)
241 {
242   CGUIDialog::OnMessage(message);
243
244
245   switch ( message.GetMessage() )
246   {
247   case GUI_MSG_CLICKED:
248     {
249       int iControl = message.GetSenderId();
250
251       switch (iControl)
252       {
253       case CTL_BUTTON_DONE:
254         OnOK();
255         break;
256       case CTL_BUTTON_CANCEL:
257         Close();
258         break;
259       case CTL_BUTTON_SHIFT:
260         OnShift();
261         break;
262       case CTL_BUTTON_CAPS:
263         if (m_keyType == LOWER)
264           m_keyType = CAPS;
265         else if (m_keyType == CAPS)
266           m_keyType = LOWER;
267         UpdateButtons();
268         break;
269       case CTL_BUTTON_SYMBOLS:
270         OnSymbols();
271         break;
272       case CTL_BUTTON_LEFT:
273         MoveCursor( -1);
274         break;
275       case CTL_BUTTON_RIGHT:
276         MoveCursor(1);
277         break;
278       case CTL_BUTTON_IP_ADDRESS:
279         OnIPAddress();
280         break;
281       case CTL_BUTTON_CLEAR:
282         SetText("");
283         break;
284       default:
285         m_lastRemoteKeyClicked = 0;
286         OnClickButton(iControl);
287         break;
288       }
289     }
290     break;
291
292   case GUI_MSG_SET_TEXT:
293     SetText(message.GetLabel());
294
295     // close the dialog if requested
296     if (message.GetParam1() > 0)
297       OnOK();
298     break;
299
300   case GUI_MSG_INPUT_TEXT:
301     InputText(message.GetLabel());
302     break;
303
304   case GUI_MSG_INPUT_TEXT_EDIT:
305     InputTextEditing(message.GetLabel(), message.GetParam1(), message.GetParam2());
306     break;
307   }
308
309   return true;
310 }
311
312 void CGUIDialogKeyboardGeneric::SetText(const CStdString& aTextString)
313 {
314   m_strEdit.clear();
315   m_strEditing.clear();
316   m_iEditingOffset = 0;
317   g_charsetConverter.utf8ToW(aTextString, m_strEdit);
318   UpdateLabel();
319   SetCursorPos(m_strEdit.size());
320 }
321
322 void CGUIDialogKeyboardGeneric::InputText(const CStdString& aTextString)
323 {
324   CStdStringW newStr;
325   g_charsetConverter.utf8ToW(aTextString, newStr);
326   if (!newStr.IsEmpty())
327   {
328     m_strEditing.clear();
329     m_iEditingOffset = 0;
330     m_strEdit.Insert(GetCursorPos(), newStr);
331     UpdateLabel();
332     MoveCursor(newStr.size());
333   }
334 }
335
336 void CGUIDialogKeyboardGeneric::InputTextEditing(const CStdString& aTextString, int start, int length)
337 {
338   m_strEditing.clear();
339   m_iEditingOffset = start;
340   m_iEditingLength = length;
341   g_charsetConverter.utf8ToW(aTextString, m_strEditing);
342 //  CLog::Log(LOGDEBUG, "CGUIDialogKeyboardGeneric::InputTextEditing len %lu range(%d, %d) -> range len %d", m_strEditing.size(), m_iEditingOffset, length, m_iEditingLength);
343   UpdateLabel();
344   SetCursorPos(GetCursorPos());
345 }
346
347 CStdString CGUIDialogKeyboardGeneric::GetText() const
348 {
349   CStdString utf8String;
350   g_charsetConverter.wToUTF8(m_strEdit, utf8String);
351   return utf8String;
352 }
353
354 void CGUIDialogKeyboardGeneric::Character(WCHAR ch)
355 {
356   if (!ch) return;
357   m_strEditing.clear();
358   m_iEditingOffset = 0;
359   // TODO: May have to make this routine take a WCHAR for the symbols?
360   m_strEdit.Insert(GetCursorPos(), ch);
361   UpdateLabel();
362   MoveCursor(1);
363 }
364
365 void CGUIDialogKeyboardGeneric::FrameMove()
366 {
367   // reset the hide state of the label when the remote
368   // sms style input times out
369   if (m_lastRemoteClickTime && m_lastRemoteClickTime + REMOTE_SMS_DELAY < CTimeUtils::GetFrameTime())
370   {
371     // finished inputting a sms style character - turn off our shift and symbol states
372     ResetShiftAndSymbols();
373   }
374   CGUIDialog::FrameMove();
375 }
376
377 void CGUIDialogKeyboardGeneric::UpdateLabel() // FIXME seems to be called twice for one USB SDL keyboard action/character
378 {
379   CGUILabelControl* pEdit = ((CGUILabelControl*)GetControl(CTL_LABEL_EDIT));
380   if (pEdit)
381   {
382     CStdStringW edit = m_strEdit;
383     pEdit->SetHighlight(0, 0);
384     pEdit->SetSelection(0, 0);
385     if (m_hiddenInput)
386     { // convert to *'s
387       edit.clear();
388       if (m_lastRemoteClickTime + REMOTE_SMS_DELAY > CTimeUtils::GetFrameTime() && m_iCursorPos > 0)
389       { // using the remove to input, so display the last key input
390         edit.append(m_iCursorPos - 1, L'*');
391         edit.append(1, m_strEdit[m_iCursorPos - 1]);
392       }
393       else
394         edit.append(m_strEdit.size(), L'*');
395     }
396     else if (!m_strEditing.IsEmpty())
397     {
398       edit.Insert(m_iCursorPos, m_strEditing);
399       pEdit->SetHighlight(m_iCursorPos, m_iCursorPos + m_strEditing.size());
400       if (m_iEditingLength > 0)
401         pEdit->SetSelection(m_iCursorPos + m_iEditingOffset, m_iCursorPos + m_iEditingOffset + m_iEditingLength);
402     }
403     // convert back to utf8
404     CStdString utf8Edit;
405     g_charsetConverter.wToUTF8(edit, utf8Edit);
406     pEdit->SetLabel(utf8Edit);
407     // Send off a search message
408     unsigned int now = CTimeUtils::GetFrameTime();
409     // don't send until the REMOTE_SMS_DELAY has passed
410     if (m_lastRemoteClickTime && m_lastRemoteClickTime + REMOTE_SMS_DELAY >= now)
411       return;
412
413     if (m_pCharCallback)
414     {
415       // do not send editing text comes from system input method
416       if (!m_hiddenInput && !m_strEditing.IsEmpty())
417         g_charsetConverter.wToUTF8(m_strEdit, utf8Edit);
418       m_pCharCallback(this, utf8Edit);
419     }
420   }
421 }
422
423 void CGUIDialogKeyboardGeneric::Backspace()
424 {
425   int iPos = GetCursorPos();
426   if (iPos > 0)
427   {
428     m_strEdit.erase(iPos - 1, 1);
429     MoveCursor(-1);
430     UpdateLabel();
431   }
432 }
433
434 void CGUIDialogKeyboardGeneric::OnClickButton(int iButtonControl)
435 {
436   if (iButtonControl == CTL_BUTTON_BACKSPACE)
437   {
438     Backspace();
439   }
440   else
441     Character(GetCharacter(iButtonControl));
442 }
443
444 void CGUIDialogKeyboardGeneric::OnRemoteNumberClick(int key)
445 {
446   unsigned int now = CTimeUtils::GetFrameTime();
447
448   if (m_lastRemoteClickTime)
449   { // a remote key has been pressed
450     if (key != m_lastRemoteKeyClicked || m_lastRemoteClickTime + REMOTE_SMS_DELAY < now)
451     { // a different key was clicked than last time, or we have timed out
452       m_lastRemoteKeyClicked = key;
453       m_indexInSeries = 0;
454       // reset our shift and symbol states, and update our label to ensure the search filter is sent
455       ResetShiftAndSymbols();
456       UpdateLabel();
457     }
458     else
459     { // same key as last time within the appropriate time period
460       m_indexInSeries++;
461       Backspace();
462     }
463   }
464   else
465   { // key is pressed for the first time
466     m_lastRemoteKeyClicked = key;
467     m_indexInSeries = 0;
468   }
469
470   int arrayIndex = key - REMOTE_0;
471   m_indexInSeries = m_indexInSeries % strlen(s_charsSeries[arrayIndex]);
472   m_lastRemoteClickTime = now;
473
474   // Select the character that will be pressed
475   const char* characterPressed = s_charsSeries[arrayIndex];
476   characterPressed += m_indexInSeries;
477
478   // use caps where appropriate
479   char ch = *characterPressed;
480   bool caps = (m_keyType == CAPS && !m_bShift) || (m_keyType == LOWER && m_bShift);
481   if (!caps && *characterPressed >= 'A' && *characterPressed <= 'Z')
482     ch += 32;
483   Character(ch);
484 }
485
486 char CGUIDialogKeyboardGeneric::GetCharacter(int iButton)
487 {
488   // First the numbers
489   if (iButton >= 48 && iButton <= 57)
490   {
491     if (m_keyType == SYMBOLS)
492     {
493       OnSymbols();
494       return symbol_map[iButton -48];
495     }
496     else
497       return (char)iButton;
498   }
499   else if (iButton == 32) // space
500     return (char)iButton;
501   else if (iButton >= 65 && iButton < 91)
502   {
503     if (m_keyType == SYMBOLS)
504     { // symbol
505       OnSymbols();
506       return symbol_map[iButton - 65 + 10];
507     }
508     if ((m_keyType == CAPS && m_bShift) || (m_keyType == LOWER && !m_bShift))
509     { // make lower case
510       iButton += 32;
511     }
512     if (m_bShift)
513     { // turn off the shift key
514       OnShift();
515     }
516     return (char) iButton;
517   }
518   else
519   { // check for symbols
520     for (unsigned int i = 0; i < NUM_SYMBOLS; i++)
521       if (iButton == symbolButtons[i])
522         return (char)iButton;
523   }
524   return 0;
525 }
526
527 void CGUIDialogKeyboardGeneric::UpdateButtons()
528 {
529   if (m_bShift)
530   { // show the button depressed
531     CGUIMessage msg(GUI_MSG_SELECTED, GetID(), CTL_BUTTON_SHIFT);
532     OnMessage(msg);
533   }
534   else
535   {
536     CGUIMessage msg(GUI_MSG_DESELECTED, GetID(), CTL_BUTTON_SHIFT);
537     OnMessage(msg);
538   }
539   if (m_keyType == CAPS)
540   {
541     CGUIMessage msg(GUI_MSG_SELECTED, GetID(), CTL_BUTTON_CAPS);
542     OnMessage(msg);
543   }
544   else
545   {
546     CGUIMessage msg(GUI_MSG_DESELECTED, GetID(), CTL_BUTTON_CAPS);
547     OnMessage(msg);
548   }
549   if (m_keyType == SYMBOLS)
550   {
551     CGUIMessage msg(GUI_MSG_SELECTED, GetID(), CTL_BUTTON_SYMBOLS);
552     OnMessage(msg);
553   }
554   else
555   {
556     CGUIMessage msg(GUI_MSG_DESELECTED, GetID(), CTL_BUTTON_SYMBOLS);
557     OnMessage(msg);
558   }
559   char szLabel[2];
560   szLabel[0] = 32;
561   szLabel[1] = 0;
562   CStdString aLabel = szLabel;
563
564   // set numerals
565   for (int iButton = 48; iButton <= 57; iButton++)
566   {
567     if (m_keyType == SYMBOLS)
568       aLabel[0] = symbol_map[iButton - 48];
569     else
570       aLabel[0] = iButton;
571     SetControlLabel(iButton, aLabel);
572   }
573
574   // set correct alphabet characters...
575
576   for (int iButton = 65; iButton <= 90; iButton++)
577   {
578     // set the correct case...
579     if ((m_keyType == CAPS && m_bShift) || (m_keyType == LOWER && !m_bShift))
580     { // make lower case
581       aLabel[0] = iButton + 32;
582     }
583     else if (m_keyType == SYMBOLS)
584     {
585       aLabel[0] = symbol_map[iButton - 65 + 10];
586     }
587     else
588     {
589       aLabel[0] = iButton;
590     }
591     SetControlLabel(iButton, aLabel);
592   }
593   for (unsigned int i = 0; i < NUM_SYMBOLS; i++)
594   {
595     aLabel[0] = symbolButtons[i];
596     SetControlLabel(symbolButtons[i], aLabel);
597   }
598 }
599
600
601 void CGUIDialogKeyboardGeneric::OnDeinitWindow(int nextWindowID)
602 {
603   // call base class
604   CGUIDialog::OnDeinitWindow(nextWindowID);
605   // reset the heading (we don't always have this)
606   m_strHeading = "";
607
608   g_Windowing.EnableTextInput(false);
609   ANNOUNCEMENT::CAnnouncementManager::Announce(ANNOUNCEMENT::Input, "xbmc", "OnInputFinished");
610 }
611
612 void CGUIDialogKeyboardGeneric::MoveCursor(int iAmount)
613 {
614   if (!m_strEditing.IsEmpty())
615     return;
616   SetCursorPos(GetCursorPos() + iAmount);
617 }
618
619 void CGUIDialogKeyboardGeneric::SetCursorPos(int iPos)
620 {
621   if (iPos < 0)
622     iPos = 0;
623   else if (iPos > (int)m_strEdit.size())
624     iPos = (int)m_strEdit.size();
625   m_iCursorPos = iPos;
626   CGUILabelControl* pEdit = ((CGUILabelControl*)GetControl(CTL_LABEL_EDIT));
627   if (pEdit)
628   {
629     pEdit->SetCursorPos(m_iCursorPos + (m_hiddenInput ? 0 : m_iEditingOffset));
630   }
631 }
632
633 int CGUIDialogKeyboardGeneric::GetCursorPos() const
634 {
635   return m_iCursorPos;
636 }
637
638 void CGUIDialogKeyboardGeneric::OnSymbols()
639 {
640   if (m_keyType == SYMBOLS)
641     m_keyType = LOWER;
642   else
643     m_keyType = SYMBOLS;
644   UpdateButtons();
645 }
646
647 void CGUIDialogKeyboardGeneric::OnShift()
648 {
649   m_bShift = !m_bShift;
650   UpdateButtons();
651 }
652
653 void CGUIDialogKeyboardGeneric::OnIPAddress()
654 {
655   // find any IP address in the current string if there is any
656   // We match to #.#.#.#
657   CStdString utf8String;
658   g_charsetConverter.wToUTF8(m_strEdit, utf8String);
659   CStdString ip;
660   CRegExp reg;
661   reg.RegComp("[0-9]+\\.[0-9]+\\.[0-9]+\\.[0-9]+");
662   int start = reg.RegFind(utf8String.c_str());
663   int length = 0;
664   if (start > -1)
665   {
666     length = reg.GetSubLength(0);
667     ip = utf8String.Mid(start, length);
668   }
669   else
670     start = utf8String.size();
671   if (CGUIDialogNumeric::ShowAndGetIPAddress(ip, g_localizeStrings.Get(14068)))
672   {
673     utf8String = utf8String.Left(start) + ip + utf8String.Mid(start + length);
674     g_charsetConverter.utf8ToW(utf8String, m_strEdit);
675     UpdateLabel();
676     CGUILabelControl* pEdit = ((CGUILabelControl*)GetControl(CTL_LABEL_EDIT));
677     if (pEdit)
678       pEdit->SetCursorPos(m_strEdit.size());
679   }
680 }
681
682 void CGUIDialogKeyboardGeneric::ResetShiftAndSymbols()
683 {
684   if (m_bShift) OnShift();
685   if (m_keyType == SYMBOLS) OnSymbols();
686   m_lastRemoteClickTime = 0;
687 }
688
689 const char* CGUIDialogKeyboardGeneric::s_charsSeries[10] = { " 0!@#$%^&*()[]{}<>/\\|", ".,1;:\'\"-+_=?`~", "ABC2", "DEF3", "GHI4", "JKL5", "MNO6", "PQRS7", "TUV8", "WXYZ9" };
690
691 void CGUIDialogKeyboardGeneric::SetControlLabel(int id, const CStdString &label)
692 { // find all controls with this id, and set all their labels
693   CGUIMessage message(GUI_MSG_LABEL_SET, GetID(), id);
694   message.SetLabel(label);
695   for (unsigned int i = 0; i < m_children.size(); i++)
696   {
697     if (m_children[i]->GetID() == id || m_children[i]->IsGroup())
698       m_children[i]->OnMessage(message);
699   }
700 }
701
702 void CGUIDialogKeyboardGeneric::OnOK()
703 {
704   m_bIsConfirmed = true;
705   Close();
706 }
707
708 void CGUIDialogKeyboardGeneric::SetHeading(const std::string &heading)
709 {
710   m_strHeading = heading;
711 }
712
713 int CGUIDialogKeyboardGeneric::GetWindowId() const
714 {
715   return GetID();
716 }
717
718 void CGUIDialogKeyboardGeneric::Cancel()
719 {
720   m_bIsConfirmed = false;
721   Close();
722 }
723
724 bool CGUIDialogKeyboardGeneric::ShowAndGetInput(char_callback_t pCallback, const std::string &initialString, std::string &typedString, const std::string &heading, bool bHiddenInput)
725 {
726   CGUIDialogKeyboardGeneric *pKeyboard = (CGUIDialogKeyboardGeneric*)g_windowManager.GetWindow(WINDOW_DIALOG_KEYBOARD);
727
728   if (!pKeyboard)
729     return false;
730
731   m_pCharCallback = pCallback;
732   // setup keyboard
733   pKeyboard->Initialize();
734   pKeyboard->SetHeading(heading);
735   pKeyboard->SetHiddenInput(bHiddenInput);
736   pKeyboard->SetText(initialString);
737   // do this using a thread message to avoid render() conflicts
738   ThreadMessage tMsg = {TMSG_DIALOG_DOMODAL, WINDOW_DIALOG_KEYBOARD, (unsigned int)g_windowManager.GetActiveWindow()};
739   CApplicationMessenger::Get().SendMessage(tMsg, true);
740   pKeyboard->Close();
741
742   // If have text - update this.
743   if (pKeyboard->IsConfirmed())
744   {
745     typedString = pKeyboard->GetText();
746     return true;
747   }
748   else return false;
749 }
750
751 void CGUIDialogKeyboardGeneric::OnPasteClipboard(void)
752 {
753   CStdStringW unicode_text;
754   CStdStringA utf8_text;
755
756 // Get text from the clipboard
757   utf8_text = g_Windowing.GetClipboardText();
758
759   // Insert the pasted text at the current cursor position.
760   if (utf8_text.length() > 0)
761   {
762     g_charsetConverter.utf8ToW(utf8_text, unicode_text);
763
764     int i = GetCursorPos();
765     CStdStringW left_end = m_strEdit.Left(i);
766     CStdStringW right_end = m_strEdit.Right(m_strEdit.length() - i);
767
768     m_strEdit = left_end;
769     m_strEdit.append(unicode_text);
770     m_strEdit.append(right_end);
771     UpdateLabel();
772     MoveCursor(unicode_text.length());
773   }
774 }