Beispiel #1
0
static void DoFun(int frameskip, int periodic_saves)
{
	uint8 *gfx;
	int32 *sound;
	int32 ssize;
	static int fskipc = 0;
	static int opause = 0;

    //TODO peroidic saves, working on it right now
    if (periodic_saves && FCEUD_GetTime() % PERIODIC_SAVE_INTERVAL < 30){
        FCEUI_SaveState(NULL, false);
    }
#ifdef FRAMESKIP
	fskipc = (fskipc + 1) % (frameskip + 1);
#endif

	if(NoWaiting) {
		gfx = 0;
	}
	FCEUI_Emulate(&gfx, &sound, &ssize, fskipc);
	FCEUD_Update(gfx, sound, ssize);

	if(opause!=FCEUI_EmulationPaused()) {
		opause=FCEUI_EmulationPaused();
		SilenceSound(opause);
	}
}
Beispiel #2
0
void PLAYBACK::toggleEmulationPause()
{
	if (FCEUI_EmulationPaused())
		unpauseEmulation();
	else
		pauseEmulation();
}
Beispiel #3
0
void update_input() {
    usb_do_poll();
    
    unsigned char pad[4];
    memset(pad, 0, sizeof (char) * 4);

    for (int dwUser = 0; dwUser < 2; dwUser++) {
        
        get_controller_data(&Gamepads[dwUser], dwUser);
        
        if (!FCEUI_EmulationPaused()) {
            if (Gamepads[dwUser].s1_y > 13107)
                pad[dwUser] |= JOY_B;

            if (Gamepads[dwUser].s1_y < -13107)
                pad[dwUser] |= JOY_UP;

            if (Gamepads[dwUser].s1_x > 13107)
                pad[dwUser] |= JOY_RIGHT;

            if (Gamepads[dwUser].s1_x < -13107)
                pad[dwUser] |= JOY_LEFT;

            if (Gamepads[dwUser].up)
                pad[dwUser] |= JOY_UP;

            if (Gamepads[dwUser].down)
                pad[dwUser] |= JOY_DOWN;

            if (Gamepads[dwUser].left)
                pad[dwUser] |= JOY_LEFT;

            if (Gamepads[dwUser].right)
                pad[dwUser] |= JOY_RIGHT;

            if (Gamepads[dwUser].a)
                pad[dwUser] |= JOY_A;

            if (Gamepads[dwUser].b)
                pad[dwUser] |= JOY_B;

            if (Gamepads[dwUser].x)
                pad[dwUser] |= JOY_A;

            if (Gamepads[dwUser].y)
                pad[dwUser] |= JOY_B;

            if (Gamepads[dwUser].start)
                pad[dwUser] |= JOY_START;

            if (Gamepads[dwUser].select)
                pad[dwUser] |= JOY_SELECT;
        }
    }
    //-------------------------------------------------------------------------------------
    // Set input from all the gamepads
    //------------------------------------------------------------------------------------- 
    powerpadbuf = pad[0] | pad[1] << 8; //| pad[2] << 16 | pad[3] << 24;;
}
Beispiel #4
0
// returns true if user pressed OK, false if Cancel
bool DoSymbolicDebugNaming(int offset, HWND parentHWND)
{
	if (!FCEUI_EmulationPaused())
		FCEUI_ToggleEmulationPause();
	loadNameFiles();
	if (DialogBoxParam(fceu_hInstance, MAKEINTRESOURCE(IDD_SYMBOLIC_DEBUG_NAMING), parentHWND, SymbolicNamingCallB, offset))
		return true;
	return false;
}
Beispiel #5
0
void FCEU_FDSInsert(void) {
	if (FCEUI_EmulationPaused()) EmulationPaused |= 2;

	if (FCEUMOV_Mode(MOVIEMODE_RECORD))
		FCEUMOV_AddCommand(FCEUNPCMD_FDSINSERT);

	if (TotalSides == 0) {
		FCEU_DispMessage("Not FDS; can't eject disk.", 0);
		return;
	}
	if (InDisk == 255) {
		FCEU_DispMessage("Disk %d Side %s Inserted", 0, SelectDisk >> 1, (SelectDisk & 1) ? "B" : "A");
		InDisk = SelectDisk;
	} else {
Beispiel #6
0
// -------------------------------------------------------------------------------------------------
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;
	}
}
Beispiel #7
0
void HISTORY::update()
{
	// Update undo_hint
	if (oldUndoHintPos != undoHintPos && oldUndoHintPos >= 0)
		pianoRoll.redrawRow(oldUndoHintPos);
	oldUndoHintPos = undoHintPos;
	oldShowUndoHint = showUndoHint;
	showUndoHint = false;
	if (undoHintPos >= 0)
	{
		if ((int)clock() < undoHintTimer)
			showUndoHint = true;
		else
			undoHintPos = -1;		// finished hinting
	}
	if (oldShowUndoHint != showUndoHint)
		pianoRoll.redrawRow(undoHintPos);

	// When CPU is idle, compress items from time to time
	if (clock() > nextAutocompressTime)
	{
		if (FCEUI_EmulationPaused())
		{
			// search for the first occurrence of an item containing non-compressed snapshot
			int real_pos;
			for (int i = historyTotalItems - 1; i >= 0; i--)
			{
				real_pos = (historyStartPos + i) % historySize;
				if (!snapshots[real_pos].isAlreadyCompressed())
				{
					snapshots[real_pos].compressData();
					break;
				} else if (bookmarkBackups[real_pos].notEmpty && bookmarkBackups[real_pos].snapshot.isAlreadyCompressed())
				{
					bookmarkBackups[real_pos].snapshot.compressData();
					break;
				}
			}
		}
		nextAutocompressTime = clock() + TIME_BETWEEN_AUTOCOMPRESSIONS;
	}
}
Beispiel #8
0
// 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();
}
Beispiel #9
0
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;
}
Beispiel #10
0
void FCEU_PutImage(void)
{
	if(dosnapsave==2)	//Save screenshot as, currently only flagged & run by the Win32 build. //TODO SDL: implement this?
	{
		char nameo[512];
		strcpy(nameo,FCEUI_GetSnapshotAsName().c_str());
		if (nameo[0])
		{
			SaveSnapshot(nameo);
			FCEU_DispMessage("Snapshot Saved.",0);
		}
		dosnapsave=0;
	}
	if(GameInfo->type==GIT_NSF)
	{
		DrawNSF(XBuf);

		//Save snapshot after NSF screen is drawn.  Why would we want to do it before?
		if(dosnapsave==1)
		{
			ReallySnap();
			dosnapsave=0;
		}
	}
	else
	{
		//Save backbuffer before overlay stuff is written.
		if(!FCEUI_EmulationPaused())
			memcpy(XBackBuf, XBuf, 256*256);

		//Some messages need to be displayed before the avi is dumped
		DrawMessage(true);

#ifdef _S9XLUA_H
		// Lua gui should draw before the avi is dumped.
		FCEU_LuaGui(XBuf);
#endif

		//Save snapshot
		if(dosnapsave==1)
		{
			ReallySnap();
			dosnapsave=0;
		}

		if (!FCEUI_AviEnableHUDrecording()) snapAVI();

		if(GameInfo->type==GIT_VSUNI)
			FCEU_VSUniDraw(XBuf);

		FCEU_DrawSaveStates(XBuf);
		FCEU_DrawMovies(XBuf);
		FCEU_DrawLagCounter(XBuf);
		FCEU_DrawNTSCControlBars(XBuf);
		FCEU_DrawRecordingStatus(XBuf);
		ShowFPS();
	}

	if(FCEUD_ShouldDrawInputAids())
		FCEU_DrawInput(XBuf);

	//Fancy input display code
	if(input_display)
	{
		extern uint32 JSAutoHeld;
		uint32 held;

		int controller, c, ci, color;
		int i, j;
		uint32 on  = FCEUMOV_Mode(MOVIEMODE_PLAY) ? 0x90:0xA7;	//Standard, or Gray depending on movie mode
		uint32 oni = 0xA0;		//Color for immediate keyboard buttons
		uint32 blend = 0xB6;		//Blend of immiate and last held buttons
		uint32 ahold = 0x87;		//Auto hold
		uint32 off = 0xCF;

		uint8 *t = XBuf+(FSettings.LastSLine-9)*256 + 20;		//mbg merge 7/17/06 changed t to uint8*
		if(input_display > 4) input_display = 4;
		for(controller = 0; controller < input_display; controller++, t += 56)
		{
			for(i = 0; i < 34;i++)
				for(j = 0; j <9 ; j++)
					t[i+j*256] = (t[i+j*256] & 0x30) | 0xC1;
			for(i = 3; i < 6; i++)
				for(j = 3; j< 6; j++)
					t[i+j*256] = 0xCF;
			c = cur_input_display >> (controller * 8);

			// This doesn't work in anything except windows for now.
			// It doesn't get set anywhere in other ports.
#if defined(WIN32) && !defined(DINGUX)
			if (!oldInputDisplay) ci = FCEUMOV_Mode(MOVIEMODE_PLAY) ? 0:GetGamepadPressedImmediate() >> (controller * 8);
			else ci = 0;

			if (!oldInputDisplay && !FCEUMOV_Mode(MOVIEMODE_PLAY)) held = (JSAutoHeld >> (controller * 8));
			else held = 0;
#else
			// Put other port info here
			ci = 0;
			held = 0;
#endif

			//adelikat: I apologize to anyone who ever sifts through this color assignment
			//A
			if (held&1)	{ //If auto-hold
				if (!(ci&1) ) color = ahold;
				else
					color = (c&1) ? on : off; //If the button is pressed down (immediate) that negates auto hold, however it is only off if the previous frame the button wasn't pressed!
			}
			else {
				if (c&1) color = (ci&1) ? blend : on;	//If immedaite buttons are pressed and they match the previous frame, blend the colors
				else color = (ci&1) ? oni : off;
			}
			for(i=0; i < 4; i++)
			{
				for(j = 0; j < 4; j++)
				{
					if(i%3==0 && j %3 == 0)
						continue;
					t[30+4*256+i+j*256] = color;
				}
			}
			//B
			if (held&2)	{ //If auto-hold
				if (!(ci&2) ) color = ahold;
				else
					color = (c&2) ? on : off; //If the button is pressed down (immediate) that negates auto hold, however it is only off if the previous frame the button wasn't pressed!
			}
			else {
				if (c&2) color = (ci&2) ? blend : on;	//If immedaite buttons are pressed and they match the previous frame, blend the colors
				else color = (ci&2) ? oni : off;
			}
			for(i=0; i < 4; i++)
			{
				for(j = 0; j < 4; j++)
				{
					if(i%3==0 && j %3 == 0)
						continue;
					t[24+4*256+i+j*256] = color;
				}
			}
			//Select
			if (held&4)	{ //If auto-hold
				if (!(ci&4) ) color = ahold;
				else
					color = (c&4) ? on : off; //If the button is pressed down (immediate) that negates auto hold, however it is only off if the previous frame the button wasn't pressed!
			}
			else {
				if (c&4) color = (ci&4) ? blend : on;	//If immedaite buttons are pressed and they match the previous frame, blend the colors
				else color = (ci&4) ? oni : off;
			}
			for(i = 0; i < 4; i++)
			{
				t[11+5*256+i] = color;
				t[11+6*256+i] = color;
			}
			//Start
			if (held&8)	{ //If auto-hold
				if (!(ci&8) ) color = ahold;
				else
					color = (c&8) ? on : off; //If the button is pressed down (immediate) that negates auto hold, however it is only off if the previous frame the button wasn't pressed!
			}
			else {
				if (c&8) color = (ci&8) ? blend : on;	//If immedaite buttons are pressed and they match the previous frame, blend the colors
				else color = (ci&8) ? oni : off;
			}
			for(i = 0; i < 4; i++)
			{
				t[17+5*256+i] = color;
				t[17+6*256+i] = color;
			}
			//Up
			if (held&16)	{ //If auto-hold
				if (!(ci&16) ) color = ahold;
				else
					color = (c&16) ? on : off; //If the button is pressed down (immediate) that negates auto hold, however it is only off if the previous frame the button wasn't pressed!
			}
			else {
				if (c&16) color = (ci&16) ? blend : on;	//If immedaite buttons are pressed and they match the previous frame, blend the colors
				else color = (ci&16) ? oni : off;
			}
			for(i = 0; i < 3; i++)
			{
				for(j = 0; j < 3; j++)
				{
					t[3+i+256*j] = color;
				}
			}
			//Down
			if (held&32)	{ //If auto-hold
				if (!(ci&32) ) color = ahold;
				else
					color = (c&32) ? on : off; //If the button is pressed down (immediate) that negates auto hold, however it is only off if the previous frame the button wasn't pressed!
			}
			else {
				if (c&32) color = (ci&32) ? blend : on;	//If immedaite buttons are pressed and they match the previous frame, blend the colors
				else color = (ci&32) ? oni : off;
			}
			for(i = 0; i < 3; i++)
			{
				for(j = 0; j < 3; j++)
				{
					t[3+i+256*j+6*256] = color;
				}
			}
			//Left
			if (held&64)	{ //If auto-hold
				if (!(ci&64) ) color = ahold;
				else
					color = (c&64) ? on : off; //If the button is pressed down (immediate) that negates auto hold, however it is only off if the previous frame the button wasn't pressed!
			}
			else {
				if (c&64) color = (ci&64) ? blend : on;	//If immedaite buttons are pressed and they match the previous frame, blend the colors
				else color = (ci&64) ? oni : off;
			}
			for(i = 0; i < 3; i++)
			{
				for(j = 0; j < 3; j++)
				{
					t[3*256+i+256*j] = color;
				}
			}
			//Right
			if (held&128)	{ //If auto-hold
				if (!(ci&128) ) color = ahold;
				else
					color = (c&128) ? on : off; //If the button is pressed down (immediate) that negates auto hold, however it is only off if the previous frame the button wasn't pressed!
			}
			else {
				if (c&128) color = (ci&128) ? blend : on;	//If immedaite buttons are pressed and they match the previous frame, blend the colors
				else color = (ci&128) ? oni : off;
			}
			for(i = 0; i < 3; i++)
			{
				for(j = 0; j < 3; j++)
				{
					t[6+3*256+i+256*j] = color;
				}
			}
		}
Beispiel #11
0
/**
 * Update the video, audio, and input subsystems with the provided
 * video (XBuf) and audio (Buffer) information.
 */
void
FCEUD_Update(uint8 *XBuf,
			 int32 *Buffer,
			 int Count)
{
	extern int FCEUDnetplay;

	#ifdef CREATE_AVI
	if(LoggingEnabled == 2 || (eoptions&EO_NOTHROTTLE))
	{
	  if(LoggingEnabled == 2)
	  {
		int16* MonoBuf = new int16[Count];
		int n;
		for(n=0; n<Count; ++n)
			MonoBuf[n] = Buffer[n] & 0xFFFF;
		NESVideoLoggingAudio
		 (
		  MonoBuf, 
		  FSettings.SndRate, 16, 1,
		  Count
		 );
		delete [] MonoBuf;
	  }
	  Count /= 2;
	  if(inited & 1)
	  {
		if(Count > GetWriteSound()) Count = GetWriteSound();
		if (!mutecapture)
		  if(Count > 0 && Buffer) WriteSound(Buffer,Count);   
	  }
	  if(inited & 2)
		FCEUD_UpdateInput();
	  if(XBuf && (inited & 4)) BlitScreen(XBuf);
	  
	  //SpeedThrottle();
		return;
	 }
	#endif
	
	int ocount = Count;
	// apply frame scaling to Count
	Count = (int)(Count / g_fpsScale);
	if(Count) {
		int32 can=GetWriteSound();
		static int uflow=0;
		int32 tmpcan;

		// don't underflow when scaling fps
		if(can >= GetMaxSound() && g_fpsScale==1.0) uflow=1;	/* Go into massive underflow mode. */

		if(can > Count) can=Count;
		else uflow=0;

		#ifdef CREATE_AVI
		if (!mutecapture)
		#endif
		  WriteSound(Buffer,can);

		//if(uflow) puts("Underflow");
		tmpcan = GetWriteSound();
		// don't underflow when scaling fps
		if(g_fpsScale>1.0 || ((tmpcan < Count*0.90) && !uflow)) {
			if(XBuf && (inited&4) && !(NoWaiting & 2))
				BlitScreen(XBuf);
			Buffer+=can;
			Count-=can;
			if(Count) {
				if(NoWaiting) {
					can=GetWriteSound();
					if(Count>can) Count=can;
					#ifdef CREATE_AVI
					if (!mutecapture)
					#endif
					  WriteSound(Buffer,Count);
				} else {
					while(Count>0) {
						#ifdef CREATE_AVI
						if (!mutecapture)
						#endif
						  WriteSound(Buffer,(Count<ocount) ? Count : ocount);
						Count -= ocount;
					}
				}
			}
		} //else puts("Skipped");
		else if(!NoWaiting && FCEUDnetplay && (uflow || tmpcan >= (Count * 1.8))) {
			if(Count > tmpcan) Count=tmpcan;
			while(tmpcan > 0) {
				//	printf("Overwrite: %d\n", (Count <= tmpcan)?Count : tmpcan);
				#ifdef CREATE_AVI
				if (!mutecapture)
				#endif
				  WriteSound(Buffer, (Count <= tmpcan)?Count : tmpcan);
				tmpcan -= Count;
			}
		}

	} else {
		if(!NoWaiting && (!(eoptions&EO_NOTHROTTLE) || FCEUI_EmulationPaused()))
		while (SpeedThrottle())
		{
			FCEUD_UpdateInput();
		}
		if(XBuf && (inited&4)) {
			BlitScreen(XBuf);
		}
	}
	FCEUD_UpdateInput();
	//if(!Count && !NoWaiting && !(eoptions&EO_NOTHROTTLE))
	// SpeedThrottle();
	//if(XBuf && (inited&4))
	//{
	// BlitScreen(XBuf);
	//}
	//if(Count)
	// WriteSound(Buffer,Count,NoWaiting);
	//FCEUD_UpdateInput();
}
Beispiel #12
0
void PLAYBACK::update()
{
	// controls:
	// update < and > buttons
	rewindButtonOldState = rewindButtonState;
	rewindButtonState = ((Button_GetState(hwndRewind) & BST_PUSHED) != 0 || mustRewindNow);
	if (rewindButtonState)
	{
		if (!rewindButtonOldState)
		{
			buttonHoldTimer = clock();
			handleRewindFrame();
		} else if (buttonHoldTimer + BUTTON_HOLD_REPEAT_DELAY < clock())
		{
			handleRewindFrame();
		}
	}
	forwardButtonOldState = forwardButtonState;
	forwardButtonState = (Button_GetState(hwndForward) & BST_PUSHED) != 0;
	if (forwardButtonState && !rewindButtonState)
	{
		if (!forwardButtonOldState)
		{
			buttonHoldTimer = clock();
			handleForwardFrame();
		} else if (buttonHoldTimer + BUTTON_HOLD_REPEAT_DELAY < clock())
		{
			handleForwardFrame();
		}
	}
	// update << and >> buttons
	rewindFullButtonOldState = rewindFullButtonState;
	rewindFullButtonState = ((Button_GetState(hwndRewindFull) & BST_PUSHED) != 0);
	if (rewindFullButtonState && !rewindButtonState && !forwardButtonState)
	{
		if (!rewindFullButtonOldState)
		{
			buttonHoldTimer = clock();
			handleRewindFull();
		} else if (buttonHoldTimer + BUTTON_HOLD_REPEAT_DELAY < clock())
		{
			handleRewindFull();
		}
	}
	forwardFullButtonOldState = forwardFullButtonState;
	forwardFullButtonState = (Button_GetState(hwndForwardFull) & BST_PUSHED) != 0;
	if (forwardFullButtonState && !rewindButtonState && !forwardButtonState && !rewindFullButtonState)
	{
		if (!forwardFullButtonOldState)
		{
			buttonHoldTimer = clock();
			handleForwardFull();
		} else if (buttonHoldTimer + BUTTON_HOLD_REPEAT_DELAY < clock())
		{
			handleForwardFull();
		}
	}

	// update the Playback cursor
	if (currFrameCounter != lastCursorPos)
	{
		// update gfx of the old and new rows
		pianoRoll.redrawRow(lastCursorPos);
		bookmarks.redrawChangedBookmarks(lastCursorPos);
		pianoRoll.redrawRow(currFrameCounter);
		bookmarks.redrawChangedBookmarks(currFrameCounter);
		lastCursorPos = currFrameCounter;
		// follow the Playback cursor, but in case of seeking don't follow it
		pianoRoll.followPlaybackCursorIfNeeded(false);	//pianoRoll.updatePlaybackCursorPositionInPianoRoll();	// an unfinished experiment
		// enforce redrawing now
		UpdateWindow(pianoRoll.hwndList);
		// lazy update of "Playback's Marker text"
		int current_marker = markersManager.getMarkerAboveFrame(currFrameCounter);
		if (displayedMarkerNumber != current_marker)
		{
			markersManager.updateEditedMarkerNote();
			displayedMarkerNumber = current_marker;
			redrawMarkerData();
			mustFindCurrentMarker = false;
		}
	}
	// [non-lazy] update "Playback's Marker text" if needed
	if (mustFindCurrentMarker)
	{
		markersManager.updateEditedMarkerNote();
		displayedMarkerNumber = markersManager.getMarkerAboveFrame(currFrameCounter);
		redrawMarkerData();
		mustFindCurrentMarker = false;
	}

	// pause when seeking hits pause_frame
	if (pauseFrame && currFrameCounter + 1 >= pauseFrame)
		stopSeeking();
	else if (currFrameCounter >= getLastPosition() && currFrameCounter >= currMovieData.getNumRecords() - 1 && mustAutopauseAtTheEnd && taseditorConfig.autopauseAtTheEndOfMovie && !isTaseditorRecording())
		// pause at the end of the movie
		pauseEmulation();

	// update flashing pauseframe
	if (oldPauseFrame != pauseFrame && oldPauseFrame)
	{
		// pause_frame was changed, clear old_pauseframe gfx
		pianoRoll.redrawRow(oldPauseFrame-1);
		bookmarks.redrawChangedBookmarks(oldPauseFrame-1);
	}
	oldPauseFrame = pauseFrame;
	oldStateOfShowPauseFrame = showPauseFrame;
	if (pauseFrame)
	{
		if (emuPausedState)
			showPauseFrame = (int)(clock() / PAUSEFRAME_BLINKING_PERIOD_WHEN_PAUSED) & 1;
		else
			showPauseFrame = (int)(clock() / PAUSEFRAME_BLINKING_PERIOD_WHEN_SEEKING) & 1;
	} else showPauseFrame = false;
	if (oldStateOfShowPauseFrame != showPauseFrame)
	{
		// update pauseframe gfx
		pianoRoll.redrawRow(pauseFrame - 1);
		bookmarks.redrawChangedBookmarks(pauseFrame - 1);
	}

	// update seeking progressbar
	emuPausedOldState = emuPausedState;
	emuPausedState = (FCEUI_EmulationPaused() != 0);
	if (pauseFrame)
	{
		if (oldStateOfShowPauseFrame != showPauseFrame)		// update progressbar from time to time
			// display seeking progress
			setProgressbar(currFrameCounter - seekingBeginningFrame, pauseFrame - seekingBeginningFrame);
	} else if (emuPausedOldState != emuPausedState)
	{
		// emulator got paused/unpaused externally
		if (emuPausedOldState && !emuPausedState)
		{
			// externally unpaused - show empty progressbar
			setProgressbar(0, 1);
		} else
		{
			// externally paused - progressbar should be full
			setProgressbar(1, 1);
		}
	}

	// prepare to stop at the end of the movie in case user unpauses emulator
	if (emuPausedState)
	{
		if (currFrameCounter < currMovieData.getNumRecords() - 1)
			mustAutopauseAtTheEnd = true;
		else
			mustAutopauseAtTheEnd = false;
	}

	// this little statement is very important for adequate work of the "green arrow" and "Restore last position"
	if (!emuPausedState)
		// when emulating, lost_position_frame becomes unstable (which means that it's probably not equal to the end of current segment anymore)
		lastPositionIsStable = false;
}