// ------------------------------------------------------------------------------------------------- void GREENZONE::adjustUp() { int at = currFrameCounter - 1; // at = the frame above currFrameCounter // find how many consequent lag frames there are int num_frames_to_erase = 0; while (lagLog.getLagInfoAtFrame(at++) == LAGGED_YES) num_frames_to_erase++; if (num_frames_to_erase > 0) { bool markers_changed = false; // delete these frames of lag currMovieData.eraseRecords(currFrameCounter - 1, num_frames_to_erase); lagLog.eraseFrame(currFrameCounter - 1, num_frames_to_erase); if (taseditorConfig.bindMarkersToInput) { if (markersManager.eraseMarker(currFrameCounter - 1, num_frames_to_erase)) markers_changed = true; } // update movie data size, because Playback cursor must always be inside the movie // if movie length is less or equal to currFrame, pad it with empty frames if (((int)currMovieData.records.size() - 1) <= currFrameCounter) currMovieData.insertEmpty(-1, currFrameCounter - ((int)currMovieData.records.size() - 1)); // update Piano Roll (reduce it if needed) pianoRoll.updateLinesCount(); // register changes int first_input_changes = history.registerAdjustLag(currFrameCounter - 1, 0 - num_frames_to_erase); // if Input in the frame above currFrameCounter has changed then invalidate Greenzone (rewind 1 frame back) // also if the frame above currFrameCounter is lag frame then rewind 1 frame (invalidate Greenzone), because maybe this frame also needs lag removal if ((first_input_changes >= 0 && first_input_changes < currFrameCounter) || (lagLog.getLagInfoAtFrame(currFrameCounter - 1) != LAGGED_NO)) { // custom invalidation procedure, not retriggering LostPosition/PauseFrame invalidate(first_input_changes); bool emu_was_paused = (FCEUI_EmulationPaused() != 0); int saved_pause_frame = playback.getPauseFrame(); playback.ensurePlaybackIsInsideGreenzone(); if (saved_pause_frame >= 0) playback.startSeekingToFrame(saved_pause_frame); if (emu_was_paused) playback.pauseEmulation(); } else { // just invalidate Greenzone after currFrameCounter (this is necessary in order to force user to re-emulate everything after the point, because the lag log data after the currFrameCounter is now in unknown state and it should be collected again) invalidate(currFrameCounter); } if (markers_changed) selection.mustFindCurrentMarker = playback.mustFindCurrentMarker = true; } }
void HISTORY::save(EMUFILE *os, bool really_save) { if (really_save) { int real_pos, last_tick = 0; // write "HISTORY" string os->fwrite(historySaveID, HISTORY_ID_LEN); // write vars write32le(historyCursorPos, os); write32le(historyTotalItems, os); // write items starting from history_start_pos for (int i = 0; i < historyTotalItems; ++i) { real_pos = (historyStartPos + i) % historySize; snapshots[real_pos].save(os); bookmarkBackups[real_pos].save(os); os->fwrite(¤tBranchNumberBackups[real_pos], 1); if (i / SAVING_HISTORY_PROGRESSBAR_UPDATE_RATE > last_tick) { playback.setProgressbar(i, historyTotalItems); last_tick = i / PROGRESSBAR_UPDATE_RATE; } } } else { // write "HISTORX" string os->fwrite(historySkipSaveID, HISTORY_ID_LEN); } }
bool exitTASEditor() { if (!askToSaveProject()) return false; // destroy window taseditorWindow.exit(); disableGeneralKeyboardInput(); // release memory editor.free(); pianoRoll.free(); markersManager.free(); greenzone.free(); bookmarks.free(); branches.free(); popupDisplay.free(); history.free(); playback.stopSeeking(); selection.free(); // restore "eoptions" eoptions = saved_eoptions; // restore autosaves EnableAutosave = saved_EnableAutosave; DoPriority(); // restore frame_display frame_display = saved_frame_display; UpdateCheckedMenuItems(); // switch off TAS Editor mode movieMode = MOVIEMODE_INACTIVE; FCEU_DispMessage("TAS Editor disengaged", 0); FCEUMOV_CreateCleanMovie(); return true; }
// --------------------------------------------------------------------------------- LRESULT APIENTRY historyListWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) { extern HISTORY history; switch(msg) { case WM_CHAR: case WM_KEYDOWN: case WM_KEYUP: case WM_KILLFOCUS: return 0; case WM_LBUTTONDOWN: case WM_LBUTTONDBLCLK: { if (GetFocus() != hWnd) SetFocus(hWnd); // perform hit test LVHITTESTINFO info; info.pt.x = GET_X_LPARAM(lParam); info.pt.y = GET_Y_LPARAM(lParam); ListView_SubItemHitTest(hWnd, (LPARAM)&info); history.handleSingleClick(info.iItem); return 0; } case WM_MBUTTONDOWN: case WM_MBUTTONDBLCLK: { if (GetFocus() != hWnd) SetFocus(hWnd); playback.handleMiddleButtonClick(); return 0; } case WM_RBUTTONDOWN: case WM_RBUTTONDBLCLK: if (GetFocus() != hWnd) SetFocus(hWnd); return 0; case WM_MOUSEWHEEL: { if (!history.isCursorOverHistoryList()) return SendMessage(pianoRoll.hwndList, msg, wParam, lParam); break; } case WM_MOUSEWHEEL_RESENT: { // this is message from Piano Roll // it means that cursor is currently over History List, and user scrolls the wheel (although focus may be on some other window) // ensure that wParam's low-order word is 0 (so fwKeys = 0) CallWindowProc(hwndHistoryList_oldWndProc, hWnd, WM_MOUSEWHEEL, wParam & ~(LOWORD(-1)), lParam); return 0; } case WM_MOUSEACTIVATE: if (GetFocus() != hWnd) SetFocus(hWnd); break; } return CallWindowProc(hwndHistoryList_oldWndProc, hWnd, msg, wParam, lParam); }
void createNewProject() { if (!askToSaveProject()) return; static struct NewProjectParameters params; if (DialogBoxParam(fceu_hInstance, MAKEINTRESOURCE(IDD_TASEDITOR_NEWPROJECT), taseditorWindow.hwndTASEditor, newProjectProc, (LPARAM)¶ms) > 0) { FCEUMOV_CreateCleanMovie(); // apply selected options setInputType(currMovieData, params.inputType); applyMovieInputConfig(); if (params.copyCurrentInput) // copy Input from current snapshot (from history) history.getCurrentSnapshot().inputlog.toMovie(currMovieData); if (!params.copyCurrentMarkers) markersManager.reset(); if (params.authorName != L"") currMovieData.comments.push_back(L"author " + params.authorName); // reset Taseditor project.init(); // new project has blank name greenzone.reset(); if (params.copyCurrentInput) // copy LagLog from current snapshot (from history) greenzone.lagLog = history.getCurrentSnapshot().laglog; playback.reset(); playback.restartPlaybackFromZeroGround(); bookmarks.reset(); branches.reset(); history.reset(); pianoRoll.reset(); selection.reset(); editor.reset(); splicer.reset(); recorder.reset(); popupDisplay.reset(); taseditorWindow.redraw(); taseditorWindow.updateCaption(); } }
void GREENZONE::adjustDown() { int at = currFrameCounter - 1; bool markers_changed = false; // clone frame and insert lag currMovieData.cloneRegion(at, 1); lagLog.insertFrame(at, true, 1); if (taseditorConfig.bindMarkersToInput) { if (markersManager.insertEmpty(at, 1)) markers_changed = true; } // register changes int first_input_changes = history.registerAdjustLag(at, +1); // If Input in the frame above currFrameCounter has changed then invalidate Greenzone (rewind 1 frame back) // This should never actually happen, because we clone the frame, so the Input doesn't change // But the check should remain, in case we decide to insert blank frame instead of cloning if (first_input_changes >= 0 && first_input_changes < currFrameCounter) { // custom invalidation procedure, not retriggering LostPosition/PauseFrame invalidate(first_input_changes); bool emu_was_paused = (FCEUI_EmulationPaused() != 0); int saved_pause_frame = playback.getPauseFrame(); playback.ensurePlaybackIsInsideGreenzone(); if (saved_pause_frame >= 0) playback.startSeekingToFrame(saved_pause_frame); if (emu_was_paused) playback.pauseEmulation(); } else { // just invalidate Greenzone after currFrameCounter invalidate(currFrameCounter); } if (markers_changed) selection.mustFindCurrentMarker = playback.mustFindCurrentMarker = true; }
// everyframe function void updateTASEditor() { if (taseditorWindow.hwndTASEditor) { // TAS Editor is engaged // update all modules that need to be updated every frame // the order is somewhat important, e.g. Greenzone must update before Bookmark Set, Piano Roll must update before Selection taseditorWindow.update(); greenzone.update(); recorder.update(); pianoRoll.update(); markersManager.update(); playback.update(); bookmarks.update(); branches.update(); popupDisplay.update(); selection.update(); splicer.update(); history.update(); project.update(); // run Lua functions if needed if (taseditorConfig.enableLuaAutoFunction) TaseditorAutoFunction(); if (mustCallManualLuaFunction) { TaseditorManualFunction(); mustCallManualLuaFunction = false; } } else { // TAS Editor is not engaged TaseditorAutoFunction(); // but we still should run Lua auto function if (mustEngageTaseditor) { char fullname[1000]; strcpy(fullname, curMovieFilename); if (enterTASEditor()) loadProject(fullname); mustEngageTaseditor = false; } } }
// invalidate and restore playback void GREENZONE::invalidateAndUpdatePlayback(int after) { if (after >= 0) { if (after >= currMovieData.getNumRecords()) after = currMovieData.getNumRecords() - 1; // clear all savestates that became irrelevant for (int i = savestates.size() - 1; i > after; i--) clearSavestateOfFrame(i); if (greenzoneSize > after + 1 || currFrameCounter > after) { greenzoneSize = after + 1; FCEUMOV_IncrementRerecordCount(); // either set Playback cursor to be inside the Greenzone or run seeking to restore Playback cursor position if (currFrameCounter >= greenzoneSize) { if (playback.getPauseFrame() >= 0 && !FCEUI_EmulationPaused()) { // emulator was running, so continue seeking, but don't follow the Playback cursor playback.jump(playback.getPauseFrame(), false, true, false); } else { playback.setLastPosition(currFrameCounter); if (taseditorConfig.autoRestoreLastPlaybackPosition) // start seeking to the green arrow, but don't follow the Playback cursor playback.jump(playback.getLastPosition(), false, true, false); else playback.ensurePlaybackIsInsideGreenzone(); } } } } // redraw Piano Roll even if Greenzone didn't change pianoRoll.redraw(); bookmarks.redrawBookmarksList(); }
// returns true if couldn't load bool HISTORY::load(EMUFILE *is, unsigned int offset) { int i = -1; SNAPSHOT snap; BOOKMARK bookm; if (offset) { if (is->fseek(offset, SEEK_SET)) goto error; } else { reset(); return false; } // read "HISTORY" string char save_id[HISTORY_ID_LEN]; if ((int)is->fread(save_id, HISTORY_ID_LEN) < HISTORY_ID_LEN) goto error; if (!strcmp(historySkipSaveID, save_id)) { // string says to skip loading History FCEU_printf("No History in the file\n"); reset(); return false; } if (strcmp(historySaveID, save_id)) goto error; // string is not valid // delete old items snapshots.resize(historySize); bookmarkBackups.resize(historySize); currentBranchNumberBackups.resize(historySize); // read vars if (!read32le(&historyCursorPos, is)) goto error; if (!read32le(&historyTotalItems, is)) goto error; if (historyCursorPos > historyTotalItems) goto error; historyStartPos = 0; // read items int total = historyTotalItems; if (historyTotalItems > historySize) { // user can't afford that much undo levels, skip some items int num_items_to_skip = historyTotalItems - historySize; // first try to skip items over history_cursor_pos (future items), because "redo" is less important than "undo" int num_redo_items = historyTotalItems-1 - historyCursorPos; if (num_items_to_skip >= num_redo_items) { // skip all redo items historyTotalItems = historyCursorPos+1; num_items_to_skip -= num_redo_items; // and still need to skip some undo items for (i = 0; i < num_items_to_skip; ++i) { if (snap.skipLoad(is)) goto error; if (bookm.skipLoad(is)) goto error; if (is->fseek(1, SEEK_CUR)) goto error; // backup_current_branch } total -= num_items_to_skip; historyCursorPos -= num_items_to_skip; } historyTotalItems -= num_items_to_skip; } // load items for (i = 0; i < historyTotalItems; ++i) { if (snapshots[i].load(is)) goto error; if (bookmarkBackups[i].load(is)) goto error; if (is->fread(¤tBranchNumberBackups[i], 1) != 1) goto error; playback.setProgressbar(i, historyTotalItems); } // skip redo items if needed for (; i < total; ++i) { if (snap.skipLoad(is)) goto error; if (bookm.skipLoad(is)) goto error; if (is->fseek(1, SEEK_CUR)) goto error; // backup_current_branch } // everything went well // init vars undoHintPos = oldUndoHintPos = undoHintTimer = -1; oldShowUndoHint = showUndoHint = false; updateList(); redrawList(); return false; error: FCEU_printf("Error loading History\n"); reset(); return true; }
// returns true if couldn't load bool GREENZONE::load(EMUFILE *is, unsigned int offset) { free(); if (offset) { if (is->fseek(offset, SEEK_SET)) goto error; } else { reset(); playback.restartPlaybackFromZeroGround(); // reset Playback cursor to frame 0 return false; } int frame = 0, prev_frame = -1, size = 0; int last_tick = 0; // read "GREENZONE" string char save_id[GREENZONE_ID_LEN]; if ((int)is->fread(save_id, GREENZONE_ID_LEN) < GREENZONE_ID_LEN) goto error; if (!strcmp(greenzone_skipsave_id, save_id)) { // string says to skip loading Greenzone // read LagLog lagLog.load(is); // read Playback cursor position if (read32le(&frame, is)) { currFrameCounter = frame; greenzoneSize = currFrameCounter + 1; savestates.resize(greenzoneSize); if (currFrameCounter) { // there must be one savestate in the file if (read32le(&size, is) && size >= 0) { savestates[frame].resize(size); if (is->fread(&savestates[frame][0], size) == size) { if (loadSavestateOfFrame(currFrameCounter)) { FCEU_printf("No Greenzone in the file\n"); return false; } } } } else { // literally no Greenzone in the file, but this is still not a error reset(); playback.restartPlaybackFromZeroGround(); // reset Playback cursor to frame 0 FCEU_printf("No Greenzone in the file, Playback at frame 0\n"); return false; } } goto error; } if (strcmp(greenzone_save_id, save_id)) goto error; // string is not valid // read LagLog lagLog.load(is); // read size if (read32le(&size, is) && size >= 0 && size <= currMovieData.getNumRecords()) { greenzoneSize = size; savestates.resize(greenzoneSize); // read Playback cursor position if (read32le(&frame, is)) { currFrameCounter = frame; int greenzone_tail_frame = currFrameCounter - taseditorConfig.greenzoneCapacity; int greenzone_tail_frame2 = greenzone_tail_frame - 2 * taseditorConfig.greenzoneCapacity; int greenzone_tail_frame4 = greenzone_tail_frame - 4 * taseditorConfig.greenzoneCapacity; int greenzone_tail_frame8 = greenzone_tail_frame - 8 * taseditorConfig.greenzoneCapacity; int greenzone_tail_frame16 = greenzone_tail_frame - 16 * taseditorConfig.greenzoneCapacity; // read savestates while(1) { if (!read32le(&frame, is)) break; if (frame < 0) break; // -1 = eof // update TASEditor progressbar from time to time if (frame / PROGRESSBAR_UPDATE_RATE > last_tick) { playback.setProgressbar(frame, greenzoneSize); last_tick = frame / PROGRESSBAR_UPDATE_RATE; } // read savestate if (!read32le(&size, is)) break; if (size < 0) break; if (frame <= greenzone_tail_frame16 || (frame <= greenzone_tail_frame8 && (frame & 0xF)) || (frame <= greenzone_tail_frame4 && (frame & 0x7)) || (frame <= greenzone_tail_frame2 && (frame & 0x3)) || (frame <= greenzone_tail_frame && (frame & 0x1))) { // skip loading this savestate if (is->fseek(size, SEEK_CUR) != 0) break; } else { // load this savestate if ((int)savestates.size() <= frame) savestates.resize(frame + 1); savestates[frame].resize(size); if ((int)is->fread(&savestates[frame][0], size) < size) break; prev_frame = frame; // successfully read one Greenzone frame info } } if (prev_frame+1 == greenzoneSize) { // everything went fine - load savestate at cursor position if (loadSavestateOfFrame(currFrameCounter)) return false; } // uh, okay, but maybe we managed to read at least something useful from the file // first see if original position of currFrameCounter was read successfully if (loadSavestateOfFrame(currFrameCounter)) { greenzoneSize = prev_frame+1; // cut greenZoneCount to last good frame FCEU_printf("Greenzone loaded partially\n"); return false; } // then at least jump to some frame that was read successfully for (; prev_frame >= 0; prev_frame--) { if (loadSavestateOfFrame(prev_frame)) { currFrameCounter = prev_frame; greenzoneSize = prev_frame+1; // cut greenZoneCount to this good frame FCEU_printf("Greenzone loaded partially, Playback moved to the end of greenzone\n"); return false; } } } } error: FCEU_printf("Error loading Greenzone\n"); reset(); playback.restartPlaybackFromZeroGround(); // reset Playback cursor to frame 0 return true; }
void GREENZONE::save(EMUFILE *os, int save_type) { if (save_type != GREENZONE_SAVING_MODE_NO) { collectCurrentState(); // in case the project is being saved before the greenzone.update() was called within current frame runGreenzoneCleaning(); if (greenzoneSize > (int)savestates.size()) greenzoneSize = savestates.size(); // write "GREENZONE" string os->fwrite(greenzone_save_id, GREENZONE_ID_LEN); // write LagLog lagLog.save(os); // write size write32le(greenzoneSize, os); // write Playback cursor position write32le(currFrameCounter, os); } int frame, size; int last_tick = 0; switch (save_type) { case GREENZONE_SAVING_MODE_ALL: { // write savestates for (frame = 0; frame < greenzoneSize; ++frame) { // update TASEditor progressbar from time to time if (frame / PROGRESSBAR_UPDATE_RATE > last_tick) { playback.setProgressbar(frame, greenzoneSize); last_tick = frame / PROGRESSBAR_UPDATE_RATE; } if (!savestates[frame].size()) continue; write32le(frame, os); // write savestate size = savestates[frame].size(); write32le(size, os); os->fwrite(&savestates[frame][0], size); } // write -1 as eof for greenzone write32le(-1, os); break; } case GREENZONE_SAVING_MODE_16TH: { // write savestates for (frame = 0; frame < greenzoneSize; ++frame) { if (!(frame & 0xF) || frame == currFrameCounter) { // update TASEditor progressbar from time to time if (frame / PROGRESSBAR_UPDATE_RATE > last_tick) { playback.setProgressbar(frame, greenzoneSize); last_tick = frame / PROGRESSBAR_UPDATE_RATE; } if (!savestates[frame].size()) continue; write32le(frame, os); // write savestate size = savestates[frame].size(); write32le(size, os); os->fwrite(&savestates[frame][0], size); } } // write -1 as eof for greenzone write32le(-1, os); break; } case GREENZONE_SAVING_MODE_MARKED: { // write savestates for (frame = 0; frame < greenzoneSize; ++frame) { if (markersManager.getMarkerAtFrame(frame) || frame == currFrameCounter) { // update TASEditor progressbar from time to time if (frame / PROGRESSBAR_UPDATE_RATE > last_tick) { playback.setProgressbar(frame, greenzoneSize); last_tick = frame / PROGRESSBAR_UPDATE_RATE; } if (!savestates[frame].size()) continue; write32le(frame, os); // write savestate size = savestates[frame].size(); write32le(size, os); os->fwrite(&savestates[frame][0], size); } } // write -1 as eof for greenzone write32le(-1, os); break; } case GREENZONE_SAVING_MODE_NO: { // write "GREENZONX" string os->fwrite(greenzone_skipsave_id, GREENZONE_ID_LEN); // write LagLog lagLog.save(os); // write Playback cursor position write32le(currFrameCounter, os); if (currFrameCounter > 0) { // write ONE savestate for currFrameCounter collectCurrentState(); int size = savestates[currFrameCounter].size(); write32le(size, os); os->fwrite(&savestates[currFrameCounter][0], size); } break; } } }
// this gate handles some FCEUX hotkeys (EMUCMD) void handleEmuCmdByTaseditor(int command) { switch (command) { case EMUCMD_SAVE_SLOT_0: case EMUCMD_SAVE_SLOT_1: case EMUCMD_SAVE_SLOT_2: case EMUCMD_SAVE_SLOT_3: case EMUCMD_SAVE_SLOT_4: case EMUCMD_SAVE_SLOT_5: case EMUCMD_SAVE_SLOT_6: case EMUCMD_SAVE_SLOT_7: case EMUCMD_SAVE_SLOT_8: case EMUCMD_SAVE_SLOT_9: { if (taseditorConfig.oldControlSchemeForBranching) bookmarks.command(COMMAND_SELECT, command - EMUCMD_SAVE_SLOT_0); else bookmarks.command(COMMAND_JUMP, command - EMUCMD_SAVE_SLOT_0); break; } case EMUCMD_SAVE_SLOT_NEXT: { int slot = bookmarks.getSelectedSlot() + 1; if (slot >= TOTAL_BOOKMARKS) slot = 0; bookmarks.command(COMMAND_SELECT, slot); break; } case EMUCMD_SAVE_SLOT_PREV: { int slot = bookmarks.getSelectedSlot() - 1; if (slot < 0) slot = TOTAL_BOOKMARKS - 1; bookmarks.command(COMMAND_SELECT, slot); break; } case EMUCMD_SAVE_STATE: bookmarks.command(COMMAND_SET); break; case EMUCMD_SAVE_STATE_SLOT_0: case EMUCMD_SAVE_STATE_SLOT_1: case EMUCMD_SAVE_STATE_SLOT_2: case EMUCMD_SAVE_STATE_SLOT_3: case EMUCMD_SAVE_STATE_SLOT_4: case EMUCMD_SAVE_STATE_SLOT_5: case EMUCMD_SAVE_STATE_SLOT_6: case EMUCMD_SAVE_STATE_SLOT_7: case EMUCMD_SAVE_STATE_SLOT_8: case EMUCMD_SAVE_STATE_SLOT_9: bookmarks.command(COMMAND_SET, command - EMUCMD_SAVE_STATE_SLOT_0); break; case EMUCMD_LOAD_STATE: bookmarks.command(COMMAND_DEPLOY); break; case EMUCMD_LOAD_STATE_SLOT_0: case EMUCMD_LOAD_STATE_SLOT_1: case EMUCMD_LOAD_STATE_SLOT_2: case EMUCMD_LOAD_STATE_SLOT_3: case EMUCMD_LOAD_STATE_SLOT_4: case EMUCMD_LOAD_STATE_SLOT_5: case EMUCMD_LOAD_STATE_SLOT_6: case EMUCMD_LOAD_STATE_SLOT_7: case EMUCMD_LOAD_STATE_SLOT_8: case EMUCMD_LOAD_STATE_SLOT_9: bookmarks.command(COMMAND_DEPLOY, command - EMUCMD_LOAD_STATE_SLOT_0); break; case EMUCMD_MOVIE_PLAY_FROM_BEGINNING: movie_readonly = true; playback.jump(0); break; case EMUCMD_RELOAD: taseditorWindow.loadRecentProject(0); break; case EMUCMD_TASEDITOR_RESTORE_PLAYBACK: playback.restoreLastPosition(); break; case EMUCMD_TASEDITOR_CANCEL_SEEKING: playback.cancelSeeking(); break; case EMUCMD_TASEDITOR_SWITCH_AUTORESTORING: taseditorConfig.autoRestoreLastPlaybackPosition ^= 1; taseditorWindow.updateCheckedItems(); break; case EMUCMD_TASEDITOR_SWITCH_MULTITRACKING: recorder.multitrackRecordingJoypadNumber++; if (recorder.multitrackRecordingJoypadNumber > joysticksPerFrame[getInputType(currMovieData)]) recorder.multitrackRecordingJoypadNumber = 0; break; case EMUCMD_TASEDITOR_RUN_MANUAL_LUA: // the function will be called in next window update mustCallManualLuaFunction = true; break; } }
// this getter contains formula to decide whether to record or replay movie bool isTaseditorRecording() { if (movie_readonly || playback.getPauseFrame() >= 0 || (taseditorConfig.oldControlSchemeForBranching && !recorder.stateWasLoadedInReadWriteMode)) return false; // replay return true; // record }
// returns true if Taseditor is engaged at the end of the function bool enterTASEditor() { if (taseditorWindow.hwndTASEditor) { // TAS Editor is already engaged, just set focus to its window if (!taseditorConfig.windowIsMaximized) ShowWindow(taseditorWindow.hwndTASEditor, SW_SHOWNORMAL); SetForegroundWindow(taseditorWindow.hwndTASEditor); return true; } else if (FCEU_IsValidUI(FCEUI_TASEDITOR)) { // start TAS Editor // create window taseditorWindow.init(); if (taseditorWindow.hwndTASEditor) { enableGeneralKeyboardInput(); // save "eoptions" saved_eoptions = eoptions; // set "Run in background" eoptions |= EO_BGRUN; // "Set high-priority thread" eoptions |= EO_HIGHPRIO; DoPriority(); // switch off autosaves saved_EnableAutosave = EnableAutosave; EnableAutosave = 0; // switch on frame_display saved_frame_display = frame_display; frame_display = 1; UpdateCheckedMenuItems(); // init modules editor.init(); pianoRoll.init(); selection.init(); splicer.init(); playback.init(); greenzone.init(); recorder.init(); markersManager.init(); project.init(); bookmarks.init(); branches.init(); popupDisplay.init(); history.init(); taseditor_lua.init(); // either start new movie or use current movie if (!FCEUMOV_Mode(MOVIEMODE_RECORD|MOVIEMODE_PLAY) || currMovieData.savestate.size() != 0) { if (currMovieData.savestate.size() != 0) FCEUD_PrintError("This version of TAS Editor doesn't work with movies starting from savestate."); // create new movie FCEUI_StopMovie(); movieMode = MOVIEMODE_TASEDITOR; FCEUMOV_CreateCleanMovie(); playback.restartPlaybackFromZeroGround(); } else { // use current movie to create a new project FCEUI_StopMovie(); movieMode = MOVIEMODE_TASEDITOR; } // if movie length is less or equal to currFrame, pad it with empty frames if (((int)currMovieData.records.size() - 1) < currFrameCounter) currMovieData.insertEmpty(-1, currFrameCounter - ((int)currMovieData.records.size() - 1)); // ensure that movie has correct set of ports/fourscore setInputType(currMovieData, getInputType(currMovieData)); // force the input configuration stored in the movie to apply to FCEUX config applyMovieInputConfig(); // reset some modules that need MovieData info pianoRoll.reset(); recorder.reset(); // create initial snapshot in history history.reset(); // reset Taseditor variables mustCallManualLuaFunction = false; SetFocus(history.hwndHistoryList); // set focus only once, to show blue selection cursor SetFocus(pianoRoll.hwndList); FCEU_DispMessage("TAS Editor engaged", 0); taseditorWindow.redraw(); return true; } else { // couldn't init window return false; } } else { // right now TAS Editor launch is not allowed by emulator return true; } }
// ------------------------------------------------------------------------- LRESULT APIENTRY UpperMarkerEditWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) { extern PLAYBACK playback; extern SELECTION selection; switch(msg) { case WM_SETFOCUS: { markersManager.markerNoteEditMode = MARKER_NOTE_EDIT_UPPER; // enable editing SendMessage(playback.hwndPlaybackMarkerEditField, EM_SETREADONLY, false, 0); // disable FCEUX keyboard disableGeneralKeyboardInput(); break; } case WM_KILLFOCUS: { // if we were editing, save and finish editing if (markersManager.markerNoteEditMode == MARKER_NOTE_EDIT_UPPER) { markersManager.updateEditedMarkerNote(); markersManager.markerNoteEditMode = MARKER_NOTE_EDIT_NONE; } // disable editing (make the bg grayed) SendMessage(playback.hwndPlaybackMarkerEditField, EM_SETREADONLY, true, 0); // enable FCEUX keyboard if (taseditorWindow.TASEditorIsInFocus) enableGeneralKeyboardInput(); break; } case WM_CHAR: case WM_KEYDOWN: { if (markersManager.markerNoteEditMode == MARKER_NOTE_EDIT_UPPER) { switch(wParam) { case VK_ESCAPE: // revert text to original note text SetWindowText(playback.hwndPlaybackMarkerEditField, markersManager.getNoteCopy(playback.displayedMarkerNumber).c_str()); SetFocus(pianoRoll.hwndList); return 0; case VK_RETURN: // exit and save text changes SetFocus(pianoRoll.hwndList); return 0; case VK_TAB: { // switch to lower edit control (also exit and save text changes) SetFocus(selection.hwndSelectionMarkerEditField); // scroll to the Marker if (taseditorConfig.followMarkerNoteContext) pianoRoll.followMarker(selection.displayedMarkerNumber); return 0; } } } break; } case WM_MBUTTONDOWN: case WM_MBUTTONDBLCLK: { playback.handleMiddleButtonClick(); return 0; } case WM_LBUTTONDOWN: case WM_RBUTTONDOWN: { // scroll to the Marker if (taseditorConfig.followMarkerNoteContext) pianoRoll.followMarker(playback.displayedMarkerNumber); break; } } return CallWindowProc(playbackMarkerEdit_oldWndproc, hWnd, msg, wParam, lParam); }