bool CGUIDialogKaraokeSongSelector::OnAction(const CAction & action) { CLog::Log( LOGDEBUG, "CGUIDialogKaraokeSongSelector::OnAction %d" , action.GetID()); if ( GetKeyNumber( action.GetID() ) != -1 ) { OnButtonNumeric( GetKeyNumber( action.GetID() ) ); return true; } switch(action.GetID()) { case ACTION_SELECT_ITEM: OnButtonSelect(); break; case ACTION_DELETE_ITEM: case ACTION_BACKSPACE: OnBackspace(); break; } return CGUIDialog::OnAction( action ); }
/// Used for getting text. This will be local translated language key codes? int UIInput::OnChar(int asciiCode) { bool isActive = (state & UIState::ACTIVE); assert(inputActive == isActive); if (!this->inputActive) return 0; /// Make sure the buffer period has passed ^^ /* clock_t currentTime = clock(); if (currentTime < textInputStartTime + 10) /// 100 ms delay before input can be done o-o return; */ // NOTE: Caret is visualized as being right behind the new letter, or right after the letter being added. // So caret 3 in the word Ashwood would be: Ash|wood // Backspace if (asciiCode == 0x08){ OnBackspace(); return 0; } /// If control is held, only evaluate it as a special command. if (InputMan.KeyPressed(KEY::CTRL)) { switch(asciiCode) { /// Generated by CTRL+A on windows.. o.O "Start of heading" case 1: { std::cout<<"ERKA:REKA"; // Select all text! o.o editText.SelectAll(); OnTextUpdated(); break; } case 'A': case 'a': { std::cout<<"ERKA:REKA"; break; } } return 0; } // Escape, cancel input else if (asciiCode == 0x1B) { // And restore old string! editText = previousText; StopInput(); return 0; } else { #define _DEBUG_ASCII /// Ignore crap letters switch(asciiCode){ case 0: case 4: // End of transmission, not the same as ETB case 13: // Vertical tab, whatever that is case 19: // XOFF, with XON is TERM=18 flow control case 22: // Synchrous idle, CTRL+V, dunno.. #ifdef _DEBUG_ASCII // std::cout<<"\nSkipping crap letters.. :3"; #endif return 0; default: #ifdef _DEBUG_ASCII // std::cout<<"\nAsciiCode: "<<(int)asciiCode<<" "<<(unsigned char)asciiCode; #endif break; } /// Accept only alpha-numeric + other accepted signs implemented in Expression bool ok = false; if (mathematicalExpressionsOnly) { if (isalnum(asciiCode)) ok = true; switch(asciiCode) { case '.': case ',': case '(': case ')': case '*': case '+': case '-': case '/': case '%': case '^': ok = true; break; } } /// If only accept numbers, skip all except a few ascii.. else if (numbersOnly) { if (isdigit(asciiCode)) ok = true; switch(asciiCode) { case '.': case '-': ok = true; break; } } /// No limit defined? Then automatically accept all characters. else { ok = true; } if (!ok) return 0; /// If any text is selected, remove it and start inserting characters where it was. if (editText.DeleteSelection()) caretPosition = editText.caretPosition; String firstHalf = editText.Part(0, caretPosition); String secondHalf = editText.Part(caretPosition); editText = firstHalf + (char)asciiCode + secondHalf; // inputBuffers[selectedInputBuffer][caretPosition] = asciiCode; ++caretPosition; editText.caretPosition = caretPosition; OnTextUpdated(); } return 0; }
bool TouchTextEntry(TCHAR *text, size_t width, const TCHAR *caption, AllowedCharacters accb, bool default_shift_state) { if (width == 0) width = MAX_TEXTENTRY; max_width = std::min(MAX_TEXTENTRY, width); const DialogLook &look = UIGlobals::GetDialogLook(); WndForm form(look); form.Create(UIGlobals::GetMainWindow(), caption); form.SetKeyDownFunction(FormKeyDown); form.SetCharacterFunction(FormCharacter); ContainerWindow &client_area = form.GetClientAreaWindow(); const PixelRect rc = client_area.GetClientRect(); const PixelScalar client_height = rc.bottom - rc.top; const PixelScalar padding = Layout::Scale(2); const PixelScalar backspace_width = Layout::Scale(36); const PixelScalar backspace_left = rc.right - padding - backspace_width; const PixelScalar editor_height = Layout::Scale(22); const PixelScalar editor_bottom = padding + editor_height; const PixelScalar button_height = Layout::Scale(40); constexpr unsigned keyboard_rows = 5; const PixelScalar keyboard_top = editor_bottom + padding; const PixelScalar keyboard_height = keyboard_rows * button_height; const PixelScalar keyboard_bottom = keyboard_top + keyboard_height; const bool vertical = client_height >= keyboard_bottom + button_height; const PixelScalar button_top = vertical ? rc.bottom - button_height : keyboard_bottom - button_height; const PixelScalar button_bottom = vertical ? rc.bottom : keyboard_bottom; const PixelScalar ok_left = vertical ? 0 : padding; const PixelScalar ok_right = vertical ? rc.right / 3 : ok_left + Layout::Scale(80); const PixelScalar cancel_left = vertical ? ok_right : Layout::Scale(175); const PixelScalar cancel_right = vertical ? rc.right * 2 / 3 : cancel_left + Layout::Scale(60); const PixelScalar clear_left = vertical ? cancel_right : Layout::Scale(235); const PixelScalar clear_right = vertical ? rc.right : clear_left + Layout::Scale(50); WndProperty _editor(client_area, look, _T(""), { 0, padding, backspace_left - padding, editor_bottom }, 0, WindowStyle()); _editor.SetReadOnly(); editor = &_editor; ButtonWindowStyle button_style; button_style.TabStop(); WndButton ok_button(client_area, look.button, _("OK"), { ok_left, button_top, ok_right, button_bottom }, button_style, form, mrOK); WndButton cancel_button(client_area, look.button, _("Cancel"), { cancel_left, button_top, cancel_right, button_bottom }, button_style, form, mrCancel); auto clear_listener = MakeLambdaActionListener([](unsigned id){ ClearText(); }); WndButton clear_button(client_area, look.button, _("Clear"), { clear_left, button_top, clear_right, button_bottom }, button_style, clear_listener, 0); KeyboardWidget keyboard(look.button, FormCharacter, !accb, default_shift_state); const PixelRect keyboard_rc = { padding, keyboard_top, rc.right - padding, keyboard_bottom }; keyboard.Initialise(client_area, keyboard_rc); keyboard.Prepare(client_area, keyboard_rc); keyboard.Show(keyboard_rc); kb = &keyboard; auto backspace_listener = MakeLambdaActionListener([](unsigned id){ OnBackspace(); }); WndButton backspace_button(client_area, look.button, _T("<-"), { backspace_left, padding, rc.right - padding, editor_bottom }, button_style, backspace_listener, 0); AllowedCharactersCallback = accb; cursor = 0; ClearText(); if (!StringIsEmpty(text)) { CopyString(edittext, text, width); cursor = _tcslen(text); } UpdateTextboxProp(); bool result = form.ShowModal() == mrOK; keyboard.Hide(); keyboard.Unprepare(); if (result) { CopyString(text, edittext, width); } return result; }
/// Used by input-captuing elements. Should not be called for any base UI elements(?) int UIInput::OnKeyDown(int keyCode, bool downBefore) { bool isActive = (state & UIState::ACTIVE); assert(inputActive == isActive); if (!inputActive) return 0; int oldCaretPosition = editText.caretPosition; bool moveCommand = false; switch(keyCode) { case KEY::BACKSPACE: { #ifndef WINDOWS // Double trigger at the moment.. OnBackspace(); #endif break; } case KEY::ESCAPE: { std::cout<<"\nCanceling input."; editText = previousText; // Make inactive. StopInput(); break; } case KEY::ENTER: { // Don't evaluate Enter and certain other keys if they were down before if (downBefore) return 0; StopInput(); // Activate the messages this element had, if any. If using as a compound e.g. inside a StringInput, then this onTrigger may be omitted. if (onTrigger.Length()) MesMan.QueueMessages(onTrigger, this); else { } /// Notify of the update to self and then parents, so that extra actions may be taken. this->OnInputUpdated(this); break; } // Delete case KEY::DELETE_KEY: { // Delete selection if any if (editText.DeleteSelection()) { caretPosition = editText.caretPosition; break; } String left = editText.Part(0, caretPosition); String right = editText.Part(caretPosition+1); editText = left + right; // Update the text to render. editText.caretPosition = caretPosition; break; } case KEY::END: caretPosition = editText.Length(); editText.caretPosition = caretPosition; moveCommand = true; break; case KEY::HOME: caretPosition = 0; editText.caretPosition = caretPosition; moveCommand = true; break; case KEY::UP: { parent->OnKeyDown(keyCode, downBefore); break; } case KEY::DOWN: { parent->OnKeyDown(keyCode, downBefore); break; } case KEY::LEFT: if (caretPosition > 0) { if (InputMan.KeyPressed(KEY::CTRL)) { caretPosition = editText.CaretPositionAtPreviousWord(); } else { --caretPosition; } // Update the text to render. editText.caretPosition = caretPosition; } moveCommand = true; break; case KEY::RIGHT: if (caretPosition < editText.Length()) { if (InputMan.KeyPressed(KEY::CTRL)) { caretPosition = editText.CaretPositionAtNextWord(); } else { ++caretPosition; } // Update the text to render. editText.caretPosition = caretPosition; } moveCommand = true; break; } // If was trying to move.. if (moveCommand /*&& oldCaretPosition != editText.caretPosition*/) { if (!InputMan.KeyPressed(KEY::SHIFT)) { // Reset the "previous caret"! editText.previousCaretPosition = -1; } // But if shift is pressed, and the previous caret is -1, then set it! else if (editText.previousCaretPosition == -1) { editText.previousCaretPosition = oldCaretPosition; } } OnTextUpdated(); // Return from here no matter what now, since we don't want any hot-key // whatsoever to be triggered while entering any input! return 0; }