void PageRecord::StopPage(bool save) { if(!m_page_started) return; StopOutput(true); StopInput(); Logger::LogInfo("[PageRecord::StopPage] " + tr("Stopping page ...")); if(m_output_manager != NULL) { // stop the output if(save) { m_output_manager->Finish(); if(m_output_manager->GetVideoEncoder() != NULL) { m_wait_saving = true; unsigned int frames_left = m_output_manager->GetVideoEncoder()->GetFrameLatency(); QProgressDialog dialog(tr("Encoding remaining data ..."), QString(), 0, frames_left, this); dialog.setWindowTitle(MainWindow::WINDOW_CAPTION); dialog.setWindowModality(Qt::WindowModal); dialog.setCancelButton(NULL); dialog.setMinimumDuration(500); while(!m_output_manager->IsFinished()) { //qDebug() << "frames left" << frames_left << "current" << m_output_manager->GetVideoEncoder()->GetFrameLatency(); dialog.setValue(frames_left - clamp(m_output_manager->GetVideoEncoder()->GetFrameLatency(), 0u, frames_left)); usleep(20000); } m_wait_saving = false; } } m_output_manager.reset(); // delete the file if it isn't needed if(!save && m_file_protocol.isNull()) { if(QFileInfo(m_output_settings.file).exists()) QFile(m_output_settings.file).remove(); } } // destroy the GLInject input m_gl_inject_input.reset(); // stop JACK input #if SSR_USE_JACK m_jack_input.reset(); #endif Logger::LogInfo("[PageRecord::StopPage] " + tr("Stopped page.")); m_page_started = false; UpdateSysTray(); OnUpdateHotkey(); OnUpdateSoundNotifications(); m_timer_update_info->stop(); OnUpdateInformation(); }
/// Called once this element is no longer visible for any reason. E.g. switching game states to display another UI, or when this or a parent has been popped from the ui. void UIInput::OnExitScope() { /// Call it for children too. UIElement::OnExitScope(); if (inputActive) { StopInput(); } }
/// Default calls parent class RemoveState. If the Active flag is removed, input is also halted/cancelled. void UIInput::RemoveState(int state, bool recursive /*= false*/) { bool wasActive = this->state & UIState::ACTIVE; UIElement::RemoveState(state, recursive); // And restore old string! if (wasActive && (state & UIState::ACTIVE)) { editText = previousText; StopInput(); } }
void PageRecord::StopPage(bool save) { if(!m_page_started) return; StopOutput(true); StopInput(); Logger::LogInfo("[PageRecord::StopPage] " + tr("Stopping page ...")); if(m_output_manager != NULL) { // stop the output if(save) FinishOutput(); m_output_manager.reset(); // delete the file if it isn't needed if(!save && m_file_protocol.isNull()) { if(QFileInfo(m_output_settings.file).exists()) QFile(m_output_settings.file).remove(); } } // destroy the GLInject input m_gl_inject_input.reset(); // stop JACK input #if SSR_USE_JACK m_jack_input.reset(); #endif Logger::LogInfo("[PageRecord::StopPage] " + tr("Stopped page.")); m_page_started = false; UpdateSysTray(); OnUpdateSoundNotifications(); m_timer_update_info->stop(); OnUpdateInformation(); }
void PageRecord::StopPage(bool save) { if(!m_page_started) return; StopOutput(true); StopInput(); Logger::LogInfo("[PageRecord::StopPage] " + tr("Stopping page ...")); if(m_output_manager != NULL) { // stop the output if(save) m_output_manager->Finish(); m_output_manager.reset(); // delete the file if it isn't needed if(!save && m_file_protocol.isNull()) { if(QFileInfo(m_output_settings.file).exists()) QFile(m_output_settings.file).remove(); } } // free the shared memory for OpenGL recording // This doesn't stop the program, and the memory is only actually freed when the recorded program stops too. m_gl_inject_launcher.reset(); Logger::LogInfo("[PageRecord::StopPage] " + tr("Stopped page.")); m_page_started = false; UpdateSysTray(); OnUpdateHotkey(); m_info_timer->stop(); OnUpdateInformation(); m_glinject_event_timer->stop(); }
/// /// HandleIDMCP PERROR HandleIDCMP( FRAME *frame, struct Objects *o, struct Values *v, struct PPTBase *PPTBase ) { ULONG sig, sigmask, sigport = 0L; struct Library *ColorWheelBase = o->ColorWheelBase; struct IntuitionBase *IntuitionBase = PPTBase->lb_Intuition; BOOL V39 = FALSE; if( PPTBase->lb_Gfx->LibNode.lib_Version >= 39 && ColorWheelBase ) V39 = TRUE; if(StartInput(frame, GINP_PICK_POINT, NULL) == PERR_OK) sigport = (1 << PPTBase->mport->mp_SigBit); GetAttr( WINDOW_SigMask, o->Win, &sigmask ); for(;;) { sig = Wait( sigport|sigmask|SIGBREAKF_CTRL_C|SIGBREAKF_CTRL_F ); if( sig & SIGBREAKF_CTRL_C ) { SetErrorCode( frame, PERR_BREAK ); DisposeObject( o->Win ); StopInput(frame); return PERR_BREAK; } if( sig & SIGBREAKF_CTRL_F ) { WindowToFront( o->win ); ActivateWindow( o->win ); } if( sig & sigport ) { struct gPointMessage *gp; gp = (struct gPointMessage*)GetMsg(PPTBase->mport); /* * Ignore all other types of messages, except pickpoints. */ if( gp->msg.code == PPTMSG_PICK_POINT ) { D(bug("User picked point (%d,%d)\n",gp->x,gp->y)); if( frame->pix->colorspace == CS_RGB ) { RGBPixel *cp; cp = (RGBPixel *)GetPixelRow( frame, gp->y ); SetGadgetAttrs( GAD(o->Red), o->win, NULL, SLIDER_Level, cp[gp->x].r, TAG_DONE ); SetGadgetAttrs( GAD(o->Green), o->win, NULL, SLIDER_Level, cp[gp->x].g, TAG_DONE ); SetGadgetAttrs( GAD(o->Blue), o->win, NULL, SLIDER_Level, cp[gp->x].b, TAG_DONE ); } else { ARGBPixel *cp; cp = (ARGBPixel *)GetPixelRow( frame, gp->y ); SetGadgetAttrs( GAD(o->Trans), o->win, NULL, SLIDER_Level, cp[gp->x].a, TAG_DONE ); SetGadgetAttrs( GAD(o->Red), o->win, NULL, SLIDER_Level, cp[gp->x].r, TAG_DONE ); SetGadgetAttrs( GAD(o->Green), o->win, NULL, SLIDER_Level, cp[gp->x].g, TAG_DONE ); SetGadgetAttrs( GAD(o->Blue), o->win, NULL, SLIDER_Level, cp[gp->x].b, TAG_DONE ); } v->background = FALSE; } ReplyMsg( (struct Message *)gp ); } if( sig & sigmask ) { ULONG rc, tmp; struct ColorWheelRGB rgb; struct ColorWheelHSB hsb; while(( rc = HandleEvent( o->Win )) != WMHI_NOMORE ) { switch(rc) { case WMHI_CLOSEWINDOW: case GID_CANCEL: D(bug("User cancelled\n")); SetErrorCode( frame, PERR_CANCELED ); DisposeObject( o->Win ); StopInput(frame); return PERR_CANCELED; /* * Can't happen if running under <V39, but let's be * sure anyway */ case GID_GRADIENTSLIDER: if( V39 ) { GetAttr(GRAD_CurVal, o->RealGradient, &tmp); // D(bug("New value: %d\n",tmp)); GetAttr( WHEEL_HSB, o->Wheel, (ULONG *)&hsb ); hsb.cw_Brightness = (0xFFFF - tmp) * 0x00010001; ConvertHSBToRGB( &hsb, &rgb ); SetGadgetAttrs( GAD(o->Red), o->win, NULL, SLIDER_Level, rgb.cw_Red>>24, TAG_DONE ); SetGadgetAttrs( GAD(o->Green), o->win, NULL, SLIDER_Level, rgb.cw_Green>>24, TAG_DONE ); SetGadgetAttrs( GAD(o->Blue), o->win, NULL, SLIDER_Level, rgb.cw_Blue>>24, TAG_DONE ); v->background = FALSE; } break; /* * Ditto */ case GID_WHEEL: if( V39 ) { GetAttr( WHEEL_RGB, o->Wheel, (ULONG *) &rgb ); SetGadgetAttrs( GAD(o->Red), o->win, NULL, SLIDER_Level, rgb.cw_Red>>24, TAG_DONE ); SetGadgetAttrs( GAD(o->Green), o->win, NULL, SLIDER_Level, rgb.cw_Green>>24, TAG_DONE ); SetGadgetAttrs( GAD(o->Blue), o->win, NULL, SLIDER_Level, rgb.cw_Blue>>24, TAG_DONE ); v->background = FALSE; } break; case GID_RED: if( V39 ) { GetAttr( SLIDER_Level, o->Red, (ULONG *)&tmp ); GetAttr( WHEEL_RGB, o->Wheel, (ULONG *) &rgb ); rgb.cw_Red = tmp * 0x01010101; SetGadgetAttrs( GAD(o->Wheel), o->win, NULL, WHEEL_RGB, &rgb, TAG_DONE ); v->background = FALSE; } break; case GID_GREEN: if( V39 ) { GetAttr( SLIDER_Level, o->Green, (ULONG *)&tmp ); GetAttr( WHEEL_RGB, o->Wheel, (ULONG *) &rgb ); rgb.cw_Green = tmp * 0x01010101; SetGadgetAttrs( GAD(o->Wheel), o->win, NULL, WHEEL_RGB, &rgb, TAG_DONE ); v->background = FALSE; } break; case GID_BLUE: if( V39 ) { GetAttr( SLIDER_Level, o->Blue, (ULONG *)&tmp ); GetAttr( WHEEL_RGB, o->Wheel, (ULONG *) &rgb ); rgb.cw_Blue = tmp * 0x01010101; SetGadgetAttrs( GAD(o->Wheel), o->win, NULL, WHEEL_RGB, &rgb, TAG_DONE ); v->background = FALSE; } break; case GID_BACKGROUND: GetBackGround( frame, v, PPTBase ); if( V39 ) { rgb.cw_Red = v->r * 0x01010101; rgb.cw_Green = v->g * 0x01010101; rgb.cw_Blue = v->b * 0x01010101; SetGadgetAttrs( GAD(o->Wheel), o->win, NULL, WHEEL_RGB, &rgb, TAG_DONE ); DoMethod( o->Win, WM_REPORT_ID, GID_WHEEL, 0L ); // A bug in OS? } else { SetGadgetAttrs( GAD(o->Red), o->win, NULL, SLIDER_Level,v->r, TAG_DONE ); SetGadgetAttrs( GAD(o->Green), o->win, NULL, SLIDER_Level,v->g, TAG_DONE ); SetGadgetAttrs( GAD(o->Blue), o->win, NULL, SLIDER_Level,v->b, TAG_DONE ); } break; case GID_BLACK: rgb.cw_Red = rgb.cw_Green = rgb.cw_Blue = 0L; if( V39 ) { SetGadgetAttrs( GAD(o->Wheel), o->win, NULL, WHEEL_RGB, &rgb, TAG_DONE ); DoMethod( o->Win, WM_REPORT_ID, GID_WHEEL, 0L ); // A bug in OS? } else { SetGadgetAttrs( GAD(o->Red), o->win, NULL, SLIDER_Level,rgb.cw_Red>>24, TAG_DONE ); SetGadgetAttrs( GAD(o->Green), o->win, NULL, SLIDER_Level,rgb.cw_Green>>24, TAG_DONE ); SetGadgetAttrs( GAD(o->Blue), o->win, NULL, SLIDER_Level,rgb.cw_Blue>>24, TAG_DONE ); } v->background = FALSE; break; case GID_WHITE: rgb.cw_Red = rgb.cw_Green = rgb.cw_Blue = 0xFFFFFFFF; if (V39 ) { SetGadgetAttrs( GAD(o->Wheel), o->win, NULL, WHEEL_RGB, &rgb, TAG_DONE ); DoMethod( o->Win, WM_REPORT_ID, GID_WHEEL, 0L ); // A bug in OS? } else { SetGadgetAttrs( GAD(o->Red), o->win, NULL, SLIDER_Level,rgb.cw_Red>>24, TAG_DONE ); SetGadgetAttrs( GAD(o->Green), o->win, NULL, SLIDER_Level,rgb.cw_Green>>24, TAG_DONE ); SetGadgetAttrs( GAD(o->Blue), o->win, NULL, SLIDER_Level,rgb.cw_Blue>>24, TAG_DONE ); } v->background = FALSE; break; case GID_OK: D(bug("User hit OK\n")); DoGadgets( frame, o, v, PPTBase ); GetAttr( WINDOW_Bounds, o->Win, (ULONG *)&v->window ); DisposeObject( o->Win ); StopInput(frame); return PERR_OK; } } } /* if(sig&sigmask) */ }
void PageRecord::StartPage() { if(m_page_started) return; assert(!m_input_started); assert(!m_output_started); // save the settings in case libav/ffmpeg decides to kill the process m_main_window->SaveSettings(); // clear the log m_textedit_log->clear(); // clear the preview if(m_previewing) { m_video_previewer->Reset(); m_audio_previewer->Reset(); } PageInput *page_input = m_main_window->GetPageInput(); PageOutput *page_output = m_main_window->GetPageOutput(); // get the video input settings m_video_area = page_input->GetVideoArea(); m_video_area_follow_fullscreen = page_input->GetVideoAreaFollowFullscreen(); m_video_x = page_input->GetVideoX(); m_video_y = page_input->GetVideoY(); #if SSR_USE_OPENGL_RECORDING if(m_video_area == PageInput::VIDEO_AREA_GLINJECT) { m_video_in_width = 0; m_video_in_height = 0; } else { #else { #endif m_video_in_width = page_input->GetVideoW(); m_video_in_height = page_input->GetVideoH(); } m_video_in_width = page_input->GetVideoW(); m_video_in_height = page_input->GetVideoH(); m_video_frame_rate = page_input->GetVideoFrameRate(); m_video_scaling = page_input->GetVideoScalingEnabled(); m_video_scaled_width = page_input->GetVideoScaledW(); m_video_scaled_height = page_input->GetVideoScaledH(); m_video_record_cursor = page_input->GetVideoRecordCursor(); // get the audio input settings m_audio_enabled = page_input->GetAudioEnabled(); m_audio_channels = 2; m_audio_sample_rate = 48000; m_audio_backend = page_input->GetAudioBackend(); #if SSR_USE_ALSA m_alsa_source = page_input->GetALSASourceName(); #endif #if SSR_USE_PULSEAUDIO m_pulseaudio_source = page_input->GetPulseAudioSourceName(); #endif #if SSR_USE_JACK bool jack_connect_system_capture = page_input->GetJackConnectSystemCapture(); bool jack_connect_system_playback = page_input->GetJackConnectSystemPlayback(); #endif // override sample rate for problematic cases (these are hard-coded for now) if(page_output->GetContainer() == PageOutput::CONTAINER_OTHER && page_output->GetContainerAVName() == "flv") { m_audio_sample_rate = 44100; } #if SSR_USE_OPENGL_RECORDING // get the glinject settings QString glinject_channel = page_input->GetGLInjectChannel(); bool glinject_relax_permissions = page_input->GetGLInjectRelaxPermissions(); QString glinject_command = page_input->GetGLInjectCommand(); QString glinject_working_directory = page_input->GetGLInjectWorkingDirectory(); bool glinject_auto_launch = page_input->GetGLInjectAutoLaunch(); bool glinject_limit_fps = page_input->GetGLInjectLimitFPS(); #endif // get file settings m_file_base = page_output->GetFile(); m_file_protocol = page_output->GetFileProtocol(); m_separate_files = page_output->GetSeparateFiles(); m_add_timestamp = page_output->GetAddTimestamp(); // get the output settings m_output_settings.file = QString(); // will be set later m_output_settings.container_avname = page_output->GetContainerAVName(); m_output_settings.video_codec_avname = page_output->GetVideoCodecAVName(); m_output_settings.video_kbit_rate = page_output->GetVideoKBitRate(); m_output_settings.video_options.clear(); m_output_settings.video_width = 0; m_output_settings.video_height = 0; m_output_settings.video_frame_rate = m_video_frame_rate; m_output_settings.video_allow_frame_skipping = page_output->GetVideoAllowFrameSkipping(); m_output_settings.audio_codec_avname = (m_audio_enabled)? page_output->GetAudioCodecAVName() : QString(); m_output_settings.audio_kbit_rate = page_output->GetAudioKBitRate(); m_output_settings.audio_options.clear(); m_output_settings.audio_channels = m_audio_channels; m_output_settings.audio_sample_rate = m_audio_sample_rate; // some codec-specific things // you can get more information about all these options by running 'ffmpeg -h' or 'avconv -h' from a terminal switch(page_output->GetVideoCodec()) { case PageOutput::VIDEO_CODEC_H264: { // x264 has a 'constant quality' mode, where the bit rate is simply set to whatever is needed to keep a certain quality. The quality is set // with the 'crf' option. 'preset' changes the encoding speed (and hence the efficiency of the compression) but doesn't really influence the quality, // which is great because it means you don't have to experiment with different bit rates and different speeds to get good results. m_output_settings.video_options.push_back(std::make_pair(QString("crf"), QString::number(page_output->GetH264CRF()))); m_output_settings.video_options.push_back(std::make_pair(QString("preset"), EnumToString(page_output->GetH264Preset()))); break; } case PageOutput::VIDEO_CODEC_VP8: { // The names of there parameters are very unintuitive. The two options we care about (because they change the speed) are 'deadline' and 'cpu-used'. // 'deadline=best' is unusably slow. 'deadline=good' is the normal setting, it tells the encoder to use the speed set with 'cpu-used'. Higher // numbers will use *less* CPU, confusingly, so a higher number is faster. I haven't done much testing with 'realtime' so I'm not sure if it's a good idea here. // It sounds useful, but I think it will use so much CPU that it will slow down the program that is being recorded. m_output_settings.video_options.push_back(std::make_pair(QString("deadline"), QString("good"))); m_output_settings.video_options.push_back(std::make_pair(QString("cpu-used"), QString::number(page_output->GetVP8CPUUsed()))); break; } case PageOutput::VIDEO_CODEC_OTHER: { m_output_settings.video_options = GetOptionsFromString(page_output->GetVideoOptions()); break; } default: break; // to keep GCC happy } switch(page_output->GetAudioCodec()) { case PageOutput::AUDIO_CODEC_OTHER: { m_output_settings.audio_options = GetOptionsFromString(page_output->GetAudioOptions()); break; } default: break; // to keep GCC happy } // hide the audio previewer if there is no audio GroupVisible({m_label_mic_icon, m_audio_previewer}, m_audio_enabled); Logger::LogInfo("[PageRecord::StartPage] " + tr("Starting page ...")); try { #if SSR_USE_OPENGL_RECORDING // for OpenGL recording, create the input now if(m_video_area == PageInput::VIDEO_AREA_GLINJECT) { if(glinject_auto_launch) GLInjectInput::LaunchApplication(glinject_channel, glinject_relax_permissions, glinject_command, glinject_working_directory); m_gl_inject_input.reset(new GLInjectInput(glinject_channel, glinject_relax_permissions, m_video_record_cursor, glinject_limit_fps, m_video_frame_rate)); } #endif #if SSR_USE_JACK if(m_audio_enabled) { // for JACK, start the input now if(m_audio_backend == PageInput::AUDIO_BACKEND_JACK) m_jack_input.reset(new JACKInput(jack_connect_system_capture, jack_connect_system_playback)); } #endif } catch(...) { Logger::LogError("[PageRecord::StartPage] " + tr("Error: Something went wrong during initialization.")); #if SSR_USE_OPENGL_RECORDING m_gl_inject_input.reset(); #endif #if SSR_USE_JACK m_jack_input.reset(); #endif } Logger::LogInfo("[PageRecord::StartPage] " + tr("Started page.")); m_page_started = true; m_recorded_something = false; m_wait_saving = false; m_error_occurred = false; UpdateSysTray(); #if SSR_USE_ALSA OnUpdateSoundNotifications(); #endif UpdateInput(); OnUpdateInformation(); m_timer_update_info->start(1000); } void PageRecord::StopPage(bool save) { if(!m_page_started) return; StopOutput(true); StopInput(); Logger::LogInfo("[PageRecord::StopPage] " + tr("Stopping page ...")); if(m_output_manager != NULL) { // stop the output if(save) FinishOutput(); m_output_manager.reset(); // delete the file if it isn't needed if(!save && m_file_protocol.isNull()) { if(QFileInfo(m_output_settings.file).exists()) QFile(m_output_settings.file).remove(); } } #if SSR_USE_OPENGL_RECORDING // stop GLInject input m_gl_inject_input.reset(); #endif #if SSR_USE_JACK // stop JACK input m_jack_input.reset(); #endif Logger::LogInfo("[PageRecord::StopPage] " + tr("Stopped page.")); m_page_started = false; UpdateSysTray(); #if SSR_USE_ALSA OnUpdateSoundNotifications(); #endif m_timer_update_info->stop(); OnUpdateInformation(); } void PageRecord::StartOutput() { assert(m_page_started); if(m_output_started) return; #if SSR_USE_ALSA if(m_simple_synth != NULL) { m_simple_synth->PlaySequence(SEQUENCE_RECORD_START.data(), SEQUENCE_RECORD_START.size()); usleep(200000); } #endif try { Logger::LogInfo("[PageRecord::StartOutput] " + tr("Starting output ...")); if(m_output_manager == NULL) { // set the file name m_output_settings.file = GetNewSegmentFile(m_file_base, m_add_timestamp); // for X11 recording, update the video size (if possible) if(m_x11_input != NULL) m_x11_input->GetCurrentSize(&m_video_in_width, &m_video_in_height); #if SSR_USE_OPENGL_RECORDING // for OpenGL recording, detect the video size if(m_video_area == PageInput::VIDEO_AREA_GLINJECT && !m_video_scaling) { if(m_gl_inject_input == NULL) { Logger::LogError("[PageRecord::StartOutput] " + tr("Error: Could not get the size of the OpenGL application because the GLInject input has not been created.")); throw GLInjectException(); } m_gl_inject_input->GetCurrentSize(&m_video_in_width, &m_video_in_height); if(m_video_in_width == 0 && m_video_in_height == 0) { Logger::LogError("[PageRecord::StartOutput] " + tr("Error: Could not get the size of the OpenGL application. Either the " "application wasn't started correctly, or the application hasn't created an OpenGL window yet. If " "you want to start recording before starting the application, you have to enable scaling and enter " "the video size manually.")); throw GLInjectException(); } } #endif // calculate the output width and height if(m_video_scaling) { // Only even width and height is allowed because some pixel formats (e.g. YUV420) require this. m_output_settings.video_width = m_video_scaled_width / 2 * 2; m_output_settings.video_height = m_video_scaled_height / 2 * 2; #if SSR_USE_OPENGL_RECORDING } else if(m_video_area == PageInput::VIDEO_AREA_GLINJECT) { // The input size is the size of the OpenGL application and can't be changed. The output size is set to the current size of the application. m_output_settings.video_width = m_video_in_width / 2 * 2; m_output_settings.video_height = m_video_in_height / 2 * 2; #endif } else { // If the user did not explicitly select scaling, then don't force scaling just because the recording area is one pixel too large. // One missing row/column of pixels is probably better than a blurry video (and scaling is SLOW). m_video_in_width = m_video_in_width / 2 * 2; m_video_in_height = m_video_in_height / 2 * 2; m_output_settings.video_width = m_video_in_width; m_output_settings.video_height = m_video_in_height; } // start the output m_output_manager.reset(new OutputManager(m_output_settings)); } else { // start a new segment m_output_manager->GetSynchronizer()->NewSegment(); } Logger::LogInfo("[PageRecord::StartOutput] " + tr("Started output.")); m_output_started = true; m_recorded_something = true; UpdateSysTray(); UpdateRecordPauseButton(); UpdateInput(); } catch(...) { Logger::LogError("[PageRecord::StartOutput] " + tr("Error: Something went wrong during initialization.")); } }
/// 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; }
/// 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; }
EFFECTEXEC(frame,tags,PPTBase,EffectBase) { ULONG sig, rc, *args; BOOL quit = FALSE, reallyrexx = FALSE; FRAME *newframe = NULL, *with = NULL; struct gFixRectMessage gfr = {0}; ULONG fc, wc; struct Values *av; D(bug(MYNAME": Exec()\n")); /* * Defaults */ v.ratio = 128; v.method = Direct; v.bounds.Top = v.bounds.Left = ~0; v.bounds.Width = 200; v.bounds.Height = 100; v.tile = FALSE; if( av = GetOptions(MYNAME) ) { v = *av; } /* * Copy to local variables */ BGUIBase = PPTBase->lb_BGUI; IntuitionBase = (struct IntuitionBase *)PPTBase->lb_Intuition; DOSBase = PPTBase->lb_DOS; SysBase = PPTBase->lb_Sys; /* * Parse AREXX message, which has to exist. * BUG: If necessary, should wait for D&D from the main window. * BUG: Should make sanity checks! */ args = (ULONG *) TagData( PPTX_RexxArgs, tags ); if( args ) { /* WITH */ if( args[0] ) { with = FindFrame( (ID) PEEKL(args[0]) ); if(!with) { SetErrorMsg(frame,"Unknown frame ID for WITH parameter"); return NULL; } } /* TOP */ if( args[1] ) { gfr.y = (WORD) PEEKL(args[1]); reallyrexx = TRUE; } /* LEFT */ if( args[2] ) { gfr.x = (WORD) PEEKL(args[2]); reallyrexx = TRUE; } /* METHOD */ if( args[3] ) { int i; for( i = 0; method_labels[i]; i++ ) { if(stricmp( method_labels[i], (char *)args[3] ) == 0 ) { v.method = i; reallyrexx = TRUE; break; } } } /* RATIO */ if( v.method == Mix ) { if( args[4] ) { v.ratio = PEEKL( args[4] ); } else { SetErrorCode(frame,PERR_INVALIDARGS); } } /* TILE */ if( args[5] ) { v.tile = TRUE; } else { v.tile = FALSE; } } else { SetErrorMsg(frame,"Image compositing can be used with Drag&Drop (or REXX) only"); return NULL; } /* * Make some sanity checks */ if( frame->pix->width < with->pix->width || frame->pix->height < with->pix->height ) { SetErrorMsg(frame,"You cannot composite a larger picture on a smaller one!"); return NULL; } fc = frame->pix->colorspace; wc = with->pix->colorspace; if( ! (wc == fc || (fc == CS_ARGB && wc == CS_RGB) || (fc == CS_RGB && wc == CS_ARGB ))) { SetErrorMsg(frame, "Only images of the same color space can be composited"); return NULL; } gfr.dim.Left = 0; gfr.dim.Top = 0; gfr.dim.Height = with->pix->height; gfr.dim.Width = with->pix->width; /* * Open window and start parsing */ if( reallyrexx == FALSE ) { if( GimmeWindow(frame, with, PPTBase) ) { ULONG sigmask, gimask = 0L; GetAttr( WINDOW_SigMask, Win, &sigmask ); StartInput(frame, GINP_FIXED_RECT, (struct PPTMessage *) &gfr); gimask = (1 << PPTBase->mport->mp_SigBit); while( !quit ) { sig = Wait( sigmask|gimask|SIGBREAKF_CTRL_C|SIGBREAKF_CTRL_F ); if( sig & SIGBREAKF_CTRL_C ) { D(bug("BREAK!\n")); SetErrorCode( frame, PERR_BREAK ); quit = TRUE; break; } if( sig & SIGBREAKF_CTRL_F ) { WindowToFront(win); ActivateWindow(win); } if( sig & gimask ) { struct gFixRectMessage *pmsg; if(pmsg = (struct gFixRectMessage *)GetMsg( PPTBase->mport )) { if( pmsg->msg.code == PPTMSG_FIXED_RECT ) { D(bug("User picked a point @ (%d,%d)\n",pmsg->x, pmsg->y)); gfr.x = pmsg->x; gfr.y = pmsg->y; // SetGadgetAttrs( ( struct Gadget *)OKButton, win, NULL, GA_Disabled, FALSE ); } ReplyMsg( (struct Message *)pmsg ); } } if( sig & sigmask ) { while( (rc = HandleEvent( Win )) != WMHI_NOMORE ) { ULONG t; switch(rc) { case GID_OK: GetAttr( CYC_Active, Method, (ULONG *)&v.method ); GetAttr( SLIDER_Level, Ratio, &v.ratio ); /* * Save the window attributes for later retrieval. */ GetAttr( WINDOW_Bounds, Win, (ULONG *) &v.bounds ); GetAttr( GA_Selected, Tile, &t ); StopInput( frame ); v.tile = (BOOL) t; WindowClose(Win); newframe = DoComposite( frame, with, &gfr, v.method, (WORD) v.ratio, v.tile, PPTBase ); quit = TRUE; break; case GID_CANCEL: quit = TRUE; StopInput( frame ); break; } } } } } } else { /* gfr is already set up */ newframe = DoComposite( frame, with, &gfr, v.method, (WORD) v.ratio, v.tile, PPTBase ); } if(Win) DisposeObject(Win); if( newframe ) { PutOptions( MYNAME, &v, sizeof(struct Values) ); } D(bug("Returning %08X...\n",newframe)); return newframe; }