Ejemplo n.º 1
0
void MenuItemPosition2D::ListUpdate(bool selected)
{
	if(selected)
	{
		MFVector t = *pData;
		float input;

		if(MFInput_WasPressed(Button_XB_B, IDD_Gamepad)) *pData = defaultValue;
		if(MFInput_WasPressed(Button_XB_X, IDD_Gamepad)) *pData = MakeVector(0.0f, 0.0f, 0.0f);

		if((input = MFInput_Read(Axis_RX, IDD_Gamepad)))
		{
			input = input < 0.0f ? -(input*input) : input*input;
			pData->x += input*increment*MFTimeDelta();
		}

		if((input = MFInput_Read(Axis_RY, IDD_Gamepad)))
		{
			input = input < 0.0f ? -(input*input) : input*input;
			pData->y -= input*increment*MFTimeDelta();
		}

		if(pCallback && t != *pData)
			pCallback(this, pUserData);
	}
}
Ejemplo n.º 2
0
void Game_Update()
{
	MFCALLSTACK;

	MFDebug_Message(MFStr("Time is %f- %f FPS\t", gSystemTimer.GetSecondsF(), gSystemTimer.GetFPS()));
	MFDebug_Message(MFStr("Left (%1.4f, %1.4f) ", MFInput_Read(Axis_LX, IDD_Gamepad), MFInput_Read(Axis_LY, IDD_Gamepad)));
	MFDebug_Message(MFStr("Right (%1.4f, %1.4f) ", MFInput_Read(Axis_RX, IDD_Gamepad), MFInput_Read(Axis_RY, IDD_Gamepad)));

	CHK_BUTTON(Button_P2_Cross);
	CHK_BUTTON(Button_P2_Circle);
	CHK_BUTTON(Button_P2_Box);
	CHK_BUTTON(Button_P2_Triangle);

	CHK_BUTTON(Button_P2_L1);
	CHK_BUTTON(Button_P2_R1);
	CHK_BUTTON(Button_P2_L2);
	CHK_BUTTON(Button_P2_R2);

	CHK_BUTTON(Button_P2_Start);
	CHK_BUTTON(Button_P2_Select);

	CHK_BUTTON(Button_P2_L3);
	CHK_BUTTON(Button_P2_R3);

	CHK_BUTTON(Button_DUp);
	CHK_BUTTON(Button_DDown);
	CHK_BUTTON(Button_DLeft);
	CHK_BUTTON(Button_DRight);
}
Ejemplo n.º 3
0
void MenuItemFloat::ListUpdate(bool selected)
{
	if(selected)
	{
		float t = *pData;
		float input;

		if(MFInput_WasPressed(Button_XB_B, IDD_Gamepad)) *pData = defaultValue;
		if(MFInput_WasPressed(Button_XB_X, IDD_Gamepad)) *pData = 0.0f;

		if(MFInput_WasPressed(Button_DLeft, IDD_Gamepad))
		{
			*pData -= increment;
		}
		else if(MFInput_WasPressed(Button_DRight, IDD_Gamepad))
		{
			*pData += increment;
		}

		if((input = MFInput_Read(Axis_RX, IDD_Gamepad)))
		{
			input = input < 0.0f ? -(input*input) : input*input;
			*pData += input*increment*MFTimeDelta();
		}

		if(*pData < minimumValue) *pData = maximumValue+(*pData-minimumValue);
		if(*pData > maximumValue) *pData = minimumValue+(*pData-maximumValue);

		if(pCallback && t != *pData)
			pCallback(this, pUserData);
	}
}
Ejemplo n.º 4
0
MF_API MFVector MFInput_ReadMouseDelta(int mouseID)
{
	MFVector delta = MFVector::zero;

	if(mouseID < 0)
	{
		for(int a=0; a<MFInput_MaxInputID; a++)
		{
			MFDebug_Assert(false, "Reading any mouse delta not written");
		}
	}
	else
	{
		delta.x = MFInput_Read(Mouse_XDelta, IDD_Mouse, mouseID);
		delta.y = MFInput_Read(Mouse_YDelta, IDD_Mouse, mouseID);
		delta.z = 0.0f;
	}

	return delta;
}
Ejemplo n.º 5
0
MF_API MFVector MFInput_ReadMousePos(int mouseID)
{
	MFVector pos = MFVector::identity;

	if(mouseID < 0)
	{
		for(int a=0; a<MFInput_MaxInputID; a++)
		{
			MFDebug_Assert(false, "Reading any mouse not written");
		}
	}
	else
	{
		pos.x = MFInput_Read(Mouse_XPos, IDD_Mouse, mouseID);
		pos.y = MFInput_Read(Mouse_YPos, IDD_Mouse, mouseID);
		pos.z = 0.0f;
	}

	return pos;
}
Ejemplo n.º 6
0
void DebugMenu_Draw()
{
	if(MFInput_Read(Button_XB_RTrig, IDD_Gamepad)) return;

	MFView_Push();
	MFView_SetOrtho();

	if(debugMenuEnabled)
		pCurrentMenu->Draw();

	MFView_Pop();
}
Ejemplo n.º 7
0
void Menu::Update()
{
	static int gMenuHeld = 0;
	static float gHoldTimeout = 0.3f;

	// test controls and move cursor
	if(MFInput_WasPressed(Button_DUp, IDD_Gamepad) || (gMenuHeld == Button_DUp && gHoldTimeout<=0.0f))
	{
		selection = selection > 0 ? selection-1 : numChildren-1;

		if(gMenuHeld)
			gHoldTimeout += 0.1f;
		else
			gMenuHeld = Button_DUp;
	}

	if(MFInput_WasPressed(Button_DDown, IDD_Gamepad) || (gMenuHeld == Button_DDown && gHoldTimeout<=0.0f))
	{
		selection = selection < numChildren-1 ? selection+1 : 0;

		if(gMenuHeld)
			gHoldTimeout += 0.1f;
		else
			gMenuHeld = Button_DDown;
	}

	if(gMenuHeld)
	{
		gHoldTimeout -= MFTimeDelta();

		if(!MFInput_Read(gMenuHeld, IDD_Gamepad))
		{
			gMenuHeld = 0;
			gHoldTimeout = 0.3f;
		}
	}

	if(MFInput_WasPressed(Button_XB_Y, IDD_Gamepad) && pParent)
		pCurrentMenu = pParent;

	for(int a=0; a<numChildren; a++)
	{
		pChildren[a]->ListUpdate(a == selection);
	}
}
Ejemplo n.º 8
0
void DebugMenu_Update()
{
#if defined(_PSP)
	if(!buttonsDown && MFInput_Read(Button_PP_Start, IDD_Gamepad) && MFInput_Read(Button_PP_Select, IDD_Gamepad))
#else
	if(!buttonsDown && MFInput_Read(Button_XB_LThumb, IDD_Gamepad) && MFInput_Read(Button_XB_RThumb, IDD_Gamepad))
#endif
	{
		debugMenuEnabled = !debugMenuEnabled;
		buttonsDown = true;
	}

#if defined(_PSP)
	if(buttonsDown && (!MFInput_Read(Button_PP_Start, IDD_Gamepad) || !MFInput_Read(Button_PP_Select, IDD_Gamepad)))
#else
	if(buttonsDown && (!MFInput_Read(Button_XB_LThumb, IDD_Gamepad) || !MFInput_Read(Button_XB_RThumb, IDD_Gamepad)))
#endif
	{
		buttonsDown = false;
	}

	if(debugMenuEnabled)
		pCurrentMenu->Update();
}
Ejemplo n.º 9
0
MF_API float MFInput_Read(int button, int device, int deviceID, float *pPrevState)
{
	MFDebug_Assert(device >= 0 && device < IDD_Max, "Invalid Input Device");
	MFDebug_Assert(deviceID >= -1 && deviceID < MFInput_MaxInputID, "Invalid DeviceID");

	if(deviceID == -1)
	{
		float value = 0.0f;

		for(int a=0; a<MFInput_MaxInputID && !value; a++)
		{
			value = MFInput_Read(button, device, a);
		}

		return value;
	}

	switch(device)
	{
		case IDD_Gamepad:
		{
			if(pPrevState)
				*pPrevState = gPrevGamepadStates[deviceID].values[button];

			return gGamepadStates[deviceID].values[button];
		}
		case IDD_Mouse:
			if(button < Mouse_MaxAxis)
			{
				if(pPrevState)
					*pPrevState = gPrevMouseStates[deviceID].values[button];

				return gMouseStates[deviceID].values[button];
			}
			else if(button < Mouse_Max)
			{
				if(pPrevState)
					*pPrevState = gPrevMouseStates[deviceID].buttonState[button - Mouse_MaxAxis] ? 1.0f : 0.0f;

				return gMouseStates[deviceID].buttonState[button - Mouse_MaxAxis] ? 1.0f : 0.0f;
			}
			break;
		case IDD_Keyboard:
			if(pPrevState)
				*pPrevState = gPrevKeyStates[deviceID].keys[button] ? 1.0f : 0.0f;

			return gKeyStates[deviceID].keys[button] ? 1.0f : 0.0f;
		case IDD_Accelerometer:
			if(button < Acc_XDelta)
			{
				if(pPrevState)
					*pPrevState = gPrevAccelerometerStates[deviceID].values[button];
			
				return gAccelerometerStates[deviceID].values[button];
			}
			return gAccelerometerStates[deviceID].values[button] - gAccelerometerStates[deviceID].values[button - Acc_XDelta];
		case IDD_TouchPanel:
		{
			if(button >= Touch_Shake)
			{
				switch(button)
				{
					case Touch_Shake:
						return gTouchPanelStates[deviceID].bDidShake ? 1.f : 0.f;
				}
			}

			int contact = button / Touch_Contact1_XPos;
			int control = button % Touch_Contact1_XPos;
			switch(control)
			{
				case Touch_Contact0_XPos:
					return (float)gTouchPanelStates[deviceID].contacts[contact].x;
				case Touch_Contact0_YPos:
					return (float)gTouchPanelStates[deviceID].contacts[contact].y;
				case Touch_Contact0_XDelta:
					return (float)(gTouchPanelStates[deviceID].contacts[contact].x - gPrevTouchPanelStates[deviceID].contacts[contact].x);
				case Touch_Contact0_YDelta:
					return (float)(gTouchPanelStates[deviceID].contacts[contact].y - gPrevTouchPanelStates[deviceID].contacts[contact].y);
			}
		}
		default:
			break;
	}

	if(pPrevState)
		*pPrevState = 0.0f;

	return 0.0f;
}
Ejemplo n.º 10
0
void Game_Draw()
{
	MFView_SetOrtho();

	const char *pText;
	float x, y;
	int a, b;

	x = 30.0f;
	for(a=0; a<MFInput_GetNumGamepads(); a++)
	{
		if(MFInput_IsAvailable(IDD_Gamepad, a))
		{
			MFFont_DrawText2(MFFont_GetDebugFont(), x-10.0f, 15.0f, 15.0f, MFVector::one, MFStr("%s (%d):", MFInput_GetDeviceName(IDD_Gamepad,a), a));

			if(MFInput_IsReady(IDD_Gamepad, a))
			{
				y = 30.0f;
				for(b=0; b<GamepadType_Max; b++)
				{
					float value = MFInput_Read(b, IDD_Gamepad, a);
//					int ival = (int)(value * 255.f);
//					MFFont_DrawText2(MFFont_GetDebugFont(), x, y, 15.0f, MFVector::one, MFStr("%s: %.3g - %d (0x%02X)", MFInput_EnumerateString(b, IDD_Gamepad, a), value, ival, ival));
					MFFont_DrawText2(MFFont_GetDebugFont(), x, y, 15.0f, MFVector::one, MFStr("%s: %.3g", MFInput_EnumerateString(b, IDD_Gamepad, a), value));
					y += 15.0f;
				}
			}
			else
			{
				MFFont_DrawText2(MFFont_GetDebugFont(), x, 30.0f, 15.0f, MakeVector(1.0f, 0.0f, 0.0f, 1.0f), "Disconnected...");
			}

			x += 170.0f;
		}
	}

	int numMouses = MFInput_GetNumPointers();

	x = 80.0f;
	for(a=0; a<numMouses; a++)
	{
		MFFont_DrawText2(MFFont_GetDebugFont(), x, 355.0f, 15.0f, MFVector::one, MFStr("Mouse Pos: %g, %g", MFInput_Read(Mouse_XPos, IDD_Mouse, a), MFInput_Read(Mouse_YPos, IDD_Mouse, a)));
		MFFont_DrawText2(MFFont_GetDebugFont(), x, 370.0f, 15.0f, MFVector::one, MFStr("Mouse Delta: %g, %g", MFInput_Read(Mouse_XDelta, IDD_Mouse, a), MFInput_Read(Mouse_YDelta, IDD_Mouse, a)));
		MFFont_DrawText2(MFFont_GetDebugFont(), x, 385.0f, 15.0f, MFVector::one, MFStr("Mouse Wheel: %g, %g", MFInput_Read(Mouse_Wheel, IDD_Mouse, a), MFInput_Read(Mouse_Wheel2, IDD_Mouse, a)));
		pText = "Mouse Buttons:";
		for(b=Mouse_MaxAxis; b<Mouse_Max; b++)
		{
			if(MFInput_Read(b, IDD_Mouse, a))
			{
				pText = MFStr("%s %s", pText, MFInput_EnumerateString(b, IDD_Mouse, a));
			}
		}
		MFFont_DrawText2(MFFont_GetDebugFont(), x, 400.0f, 15.0f, MFVector::one, pText);

		x += 170.0f;
	}

	pText = "Keys:";
	for(a=0; a<Key_Max; a++)
	{
		if(MFInput_Read(a, IDD_Keyboard, 0))
		{
			pText = MFStr("%s %s", pText, MFInput_EnumerateString(a, IDD_Keyboard, 0));
		}
	}
	MFFont_DrawText2(MFFont_GetDebugFont(), 80.0f, 430.0f, 15.0f, MFVector::one, pText);
}
Ejemplo n.º 11
0
void UpdateEditor()
{
	static GHEvent *pHold[8] = { (GHEvent*)(size_t)-1, (GHEvent*)(size_t)-1, (GHEvent*)(size_t)-1, (GHEvent*)(size_t)-1, (GHEvent*)(size_t)-1, (GHEvent*)(size_t)-1, (GHEvent*)(size_t)-1, (GHEvent*)(size_t)-1 };

	bool ctrlState = MFInput_Read(Key_LControl, IDD_Keyboard) || MFInput_Read(Key_RControl, IDD_Keyboard);
	bool shiftState = MFInput_Read(Key_LShift, IDD_Keyboard) || MFInput_Read(Key_LShift, IDD_Keyboard);
	bool altState = MFInput_Read(Key_LAlt, IDD_Keyboard) || MFInput_Read(Key_RAlt, IDD_Keyboard);

	int res = gEditor.pSong->GetRes();

	if(TestControl(dBCtrl_Edit_Save, GHCT_Once))
	{
		gEditor.pSong->SaveChart();
		MFVoice *pVoice = MFSound_Play(gEditor.pSaveSound, MFPF_BeginPaused);
		MFSound_SetVolume(pVoice, gConfig.sound.fxLevel);
		MFSound_Pause(pVoice, false);

		if(gConfig.editor.saveAction[0])
			system(gConfig.editor.saveAction);
	}

	if(TestControl(dBCtrl_Edit_Event, GHCT_Once))
		PlaceEvent();
	else if(TestControl(dBCtrl_Edit_TrackEvent, GHCT_Once))
		PlaceTrackEvent();
	else if(TestControl(dBCtrl_Edit_Section, GHCT_Once))
		PlaceSection();
	else if(TestControl(dBCtrl_Edit_Quantise, GHCT_Once))
		gpStringBox->Show(MFTranslation_GetString(pStrings, MENU_SETQUANTISE), "", SetCustomQuantisation);
	else if(TestControl(dBCtrl_Edit_Mixer, GHCT_Once))
		((EditorScreen*)dBScreen::GetCurrent())->gMixer.Push();

	// check selection
	if(bSelecting && !TestControl(dBCtrl_Edit_RangeSelect, GHCT_Hold))
	{
		gEditor.selectEnd = gEditor.offset;
		bSelecting = false;
	}
	else if(!bSelecting && TestControl(dBCtrl_Edit_RangeSelect, GHCT_Hold))
	{
		gEditor.selectStart = gEditor.selectEnd = gEditor.offset;
		bSelecting = true;
	}

	if(TestControl(dBCtrl_Edit_Cut, GHCT_Once) || TestControl(dBCtrl_Edit_Copy, GHCT_Once))
	{
		if(gEditor.selectStart != gEditor.selectEnd)
		{
			gEditor.copyLen = gEditor.selectEnd - gEditor.selectStart;

			gEditor.selectEvents.Clear();

			GHEventManager &noteStream = gEditor.pSong->notes[gEditor.currentStream[gEditor.selectedStream]];
			GHEvent *pEv = noteStream.GetNextEvent(gEditor.selectStart);

			while(pEv && pEv->tick < gEditor.selectEnd)
			{
				// copy the next pointer incase we cut the note.
				GHEvent *pNext = pEv->Next();

				// just cut/copy notes
				if(pEv->event == GHE_Note)
				{
					// copy to clipboard
					gEditor.selectEvents.AddEvent(pEv->event, pEv->tick - gEditor.selectStart, pEv->key, pEv->parameter);

					// if we cut
					if(TestControl(dBCtrl_Edit_Cut, GHCT_Once))
						pNext = noteStream.RemoveEvent(pEv);
				}

				pEv = pNext;
			}
		}
	}
	else if(TestControl(dBCtrl_Edit_Paste, GHCT_Once))
	{
		GHEvent *pEv = gEditor.selectEvents.First();

		if(pEv)
		{
			int curStream = gEditor.currentStream[gEditor.selectedStream];
			GHEventManager &noteStream = gEditor.pSong->notes[curStream];

			// delete notes in paste range
			GHEvent *pDel = noteStream.GetNextEvent(gEditor.offset);
			while(pDel && pDel->tick < gEditor.offset + gEditor.copyLen)
			{
				if(pDel->event == GHE_Note)
					pDel = noteStream.RemoveEvent(pDel);
				else
					pDel = pDel->Next();
			}

			// paste notes
			while(pEv)
			{
				noteStream.AddEvent(pEv->event, pEv->tick + gEditor.offset, pEv->key, pEv->parameter);
				pEv = pEv->Next();
			}

			gEditor.pSong->CalculateNoteTimes(curStream, gEditor.offset);
		}
	}

	if(TestControl(dBCtrl_Edit_Delete, GHCT_Once))
	{
		GHEventManager &notes = gEditor.pSong->notes[gEditor.currentStream[gEditor.selectedStream]];
		if(gEditor.selectStart != gEditor.selectEnd)
		{
			// delete notes in selected range
			GHEvent *pDel = notes.GetNextEvent(gEditor.selectStart);
			while(pDel && pDel->tick < gEditor.selectEnd)
			{
				if(pDel->event == GHE_Note)
					pDel = notes.RemoveEvent(pDel);
				else
					pDel = pDel->Next();
			}
		}
		else
		{
			int numEvents = 0;
			uint32 eventTypes = 0;

			// find note events
			GHEvent *pEvent = notes.GetNextEvent(gEditor.offset);
			while(pEvent && pEvent->tick == gEditor.offset)
			{
				uint32 bit = 1 << pEvent->event;
				if(!(eventTypes & bit))
				{
					++numEvents;
					eventTypes |= bit;
				}
				pEvent = pEvent->Next();
			}

			// find sync events
			if(gEditor.offset > 0)
			{
				pEvent = gEditor.pSong->sync.GetNextEvent(gEditor.offset);
				while(pEvent && pEvent->tick == gEditor.offset)
				{
					uint32 bit = 1 << pEvent->event;
					if(!(eventTypes & bit))
					{
						++numEvents;
						eventTypes |= bit;
					}
					pEvent = pEvent->Next();
				}
			}

			// find global events
			pEvent = gEditor.pSong->events.GetNextEvent(gEditor.offset);
			while(pEvent && pEvent->tick == gEditor.offset)
			{
				uint32 bit = 1 << pEvent->event;
				if(!(eventTypes & bit))
				{
					++numEvents;
					eventTypes |= bit;
				}
				pEvent = pEvent->Next();
			}

			// if there are multiple event types to remove, show a list box
			if(numEvents > 1)
				gpListBox->Show(MFTranslation_GetString(pStrings, SELECT_EVENT_REMOVE), RemoveEventCallback, 200.0f, 100.0f);

			for(int a=0; a<GHE_Max; ++a)
			{
				if(eventTypes & (1 << a))
				{
					if(numEvents > 1)
						gpListBox->AddItem(MFTranslation_GetString(pStrings, EVENT_TYPE_UNKNOWN+a), (void*)(size_t)a);
					else
						RemoveEventCallback(false, 0, NULL, (void*)(size_t)a);
				}
			}
		}
	}

	// shift notes left or right
	int selStart, selEnd;

	if(gEditor.selectStart != gEditor.selectEnd)
	{
		selStart = gEditor.selectStart;
		selEnd = gEditor.selectEnd;
	}
	else
	{
		selStart = gEditor.offset;
		selEnd = gEditor.pSong->GetLastNoteTick();
	}

	if(TestControl(dBCtrl_Edit_ShiftForwards, GHCT_Delay))
	{
		int offset = 4*res / gEditor.quantisation;

		// TODO: gotta remove notes after the selection that will be overwritten as the selection shifts..

		if(altState)
		{
			// shift events, sync and other tracks too
			GHEvent *pEv = gEditor.pSong->sync.GetNextEvent(selStart);
			while(pEv && pEv->tick < selEnd)
			{
				if(pEv->tick != 0)
					pEv->tick += offset;
				pEv = pEv->Next();
			}

			pEv = gEditor.pSong->events.GetNextEvent(selStart);
			while(pEv && pEv->tick < selEnd)
			{
				pEv->tick += offset;
				pEv = pEv->Next();
			}

			for(int i=0; i<GHS_Max; ++i)
			{
				pEv = gEditor.pSong->notes[i].GetNextEvent(selStart);
				while(pEv && pEv->tick < selEnd)
				{
					pEv->tick += offset;
					pEv = pEv->Next();
				}
			}
		}
		else
		{
			GHEvent *pEv = gEditor.pSong->notes[gEditor.currentStream[gEditor.selectedStream]].GetNextEvent(selStart);
			while(pEv && pEv->tick < selEnd)
			{
				pEv->tick += offset;
				pEv = pEv->Next();
			}
		}

		gEditor.selectStart += offset;
		gEditor.selectEnd += offset;
		gEditor.offset += offset;

		gEditor.pSong->CalculateNoteTimes(gEditor.currentStream[gEditor.selectedStream], gEditor.offset);
	}
	if(TestControl(dBCtrl_Edit_ShiftBackwards, GHCT_Delay))
	{
		int offset = MFMin(4*res / gEditor.quantisation, gEditor.selectStart);

		// TODO: gotta remove notes before the selection that will be overwritten as the selection shifts..

		if(altState)
		{
			// shift events, sync and other tracks too
			GHEvent *pEv = gEditor.pSong->sync.GetNextEvent(selStart);
			while(pEv && pEv->tick < selEnd)
			{
				if(pEv->tick != 0)
					pEv->tick -= offset;
				pEv = pEv->Next();
			}

			pEv = gEditor.pSong->events.GetNextEvent(selStart);
			while(pEv && pEv->tick < selEnd)
			{
				pEv->tick -= offset;
				pEv = pEv->Next();
			}

			for(int i=0; i<GHS_Max; ++i)
			{
				pEv = gEditor.pSong->notes[i].GetNextEvent(selStart);
				while(pEv && pEv->tick < selEnd)
				{
					pEv->tick -= offset;
					pEv = pEv->Next();
				}
			}
		}
		else
		{
			GHEvent *pEv = gEditor.pSong->notes[gEditor.currentStream[gEditor.selectedStream]].GetNextEvent(selStart);
			while(pEv && pEv->tick < selEnd)
			{
				pEv->tick -= offset;
				pEv = pEv->Next();
			}
		}

		gEditor.selectStart -= offset;
		gEditor.selectEnd -= offset;
		gEditor.offset -= offset;

		gEditor.pSong->CalculateNoteTimes(gEditor.currentStream[gEditor.selectedStream], gEditor.offset);
	}
	if(TestControl(dBCtrl_Edit_ShiftLeft, GHCT_Once))
	{
		GHEvent *pEv = gEditor.pSong->notes[gEditor.currentStream[gEditor.selectedStream]].GetNextEvent(selStart);

		while(pEv && pEv->tick < selEnd)
		{
			if(pEv->event == GHE_Note)
				pEv->key = MFMax(0, pEv->key - 1);

			pEv = pEv->Next();
		}
	}
	if(TestControl(dBCtrl_Edit_ShiftRight, GHCT_Once))
	{
		GHEvent *pEv = gEditor.pSong->notes[gEditor.currentStream[gEditor.selectedStream]].GetNextEvent(selStart);

		while(pEv && pEv->tick < selEnd)
		{
			if(pEv->event == GHE_Note)
				pEv->key = MFMin(4, pEv->key + 1);

			pEv = pEv->Next();
		}
	}

	// change quantisation
	if(TestControl(dBCtrl_Edit_QuantiseDown, GHCT_Delay))
	{
		gEditor.quantiseStep = MFMax(0, gEditor.quantiseStep-1);
		gEditor.quantisation = gQuantiseSteps[gEditor.quantiseStep];
		OffsetToMeasureAndBeat(gEditor.offset, &gEditor.measure, &gEditor.beat);

		MFVoice *pVoice = MFSound_Play(gEditor.pChangeSound, MFPF_BeginPaused);
		MFSound_SetVolume(pVoice, gConfig.sound.fxLevel);
		MFSound_Pause(pVoice, false);
	}
	if(TestControl(dBCtrl_Edit_QuantiseUp, GHCT_Delay))
	{
		gEditor.quantiseStep = MFMin((int)(sizeof(gQuantiseSteps)/sizeof(gQuantiseSteps[0]))-1, gEditor.quantiseStep+1);
		gEditor.quantisation = gQuantiseSteps[gEditor.quantiseStep];
		OffsetToMeasureAndBeat(gEditor.offset, &gEditor.measure, &gEditor.beat);

		MFVoice *pVoice = MFSound_Play(gEditor.pChangeSound, MFPF_BeginPaused);
		MFSound_SetVolume(pVoice, gConfig.sound.fxLevel);
		MFSound_Pause(pVoice, false);
	}

	// move the track
	if(TestControl(dBCtrl_Edit_Forward, GHCT_Delay))
	{
		// forward one step
		++gEditor.beat;
		if(gEditor.beat == gEditor.quantisation)
		{
			++gEditor.measure;
			gEditor.beat = 0;
		}
	}
	if(TestControl(dBCtrl_Edit_Back, GHCT_Delay))
	{
		// back one step
		if(gEditor.measure || gEditor.beat)
		{
			--gEditor.beat;
			if(gEditor.beat < 0)
			{
				--gEditor.measure;
				gEditor.beat += gEditor.quantisation;
			}
		}
	}
	if(TestControl(dBCtrl_Edit_Start, GHCT_Once))
	{
		// go to start
		gEditor.measure = gEditor.beat = 0;
	}
	if(TestControl(dBCtrl_Edit_End, GHCT_Once))
	{
		// go to the last note...
		OffsetToMeasureAndBeat(gEditor.pSong->GetLastNoteTick(), &gEditor.measure, &gEditor.beat);
	}
	if(TestControl(dBCtrl_Edit_UpMeasure, GHCT_Delay))
	{
		// forward one measure
		// TODO: consider bar lengths while moving
		++gEditor.measure;
	}
	if(TestControl(dBCtrl_Edit_DownMeasure, GHCT_Delay))
	{
		// back one measure
		// TODO: consider bar lengths while moving
		if(gEditor.measure < 1)
			gEditor.measure = gEditor.beat = 0;
		else
			--gEditor.measure;
	}
	if(TestControl(dBCtrl_Edit_NextSection, GHCT_Delay))
	{
		GHEvent *pEv = gEditor.pSong->events.GetNextEvent(gEditor.offset);

		while(pEv)
		{
			if(pEv->tick >= gEditor.offset + gEditor.pSong->resolution*4 / gEditor.quantisation && !MFString_CompareN(pEv->GetString(), "section ", 8))
			{
				OffsetToMeasureAndBeat(pEv->tick, &gEditor.measure, &gEditor.beat);
				break;
			}

			pEv = pEv->Next();
		}

		if(!pEv)
			OffsetToMeasureAndBeat(gEditor.pSong->GetLastNoteTick(), &gEditor.measure, &gEditor.beat);
	}
	if(TestControl(dBCtrl_Edit_PrevSection, GHCT_Delay))
	{
		GHEvent *pMostRecent = NULL;
		GHEvent *pEv = gEditor.pSong->events.First();

		while(pEv && pEv->tick < gEditor.offset)
		{
			if(!MFString_CompareN(pEv->GetString(), "section ", 8))
				pMostRecent = pEv;

			pEv = pEv->Next();
		}

		if(pMostRecent)
			OffsetToMeasureAndBeat(pMostRecent->tick, &gEditor.measure, &gEditor.beat);
		else
			gEditor.measure = gEditor.beat = 0;
	}

	int newOffset = MeasureAndBeatToOffset(gEditor.measure, gEditor.beat);
	int shift = newOffset - gEditor.offset;
	shift = MFMax(gEditor.offset + shift, 0) - gEditor.offset;

	if(shift)
	{
		// update BPM if applicable
		int shiftStart, shiftEnd;

		if(shift > 0)
		{
			shiftStart = gEditor.offset;
			shiftEnd = gEditor.offset+shift + 1;
		}
		else
		{
			shiftStart = 0;
			shiftEnd = gEditor.offset+shift + 1;
		}

		gEditor.offset += shift;

		if(bSelecting)
			gEditor.selectEnd = gEditor.offset;

		GHEvent *pEv = gEditor.pSong->sync.GetNextEvent(shiftStart);

		while(pEv && pEv->tick < shiftEnd)
		{
			if(pEv->event == GHE_BPM || pEv->event == GHE_Anchor)
				gEditor.currentBPM = pEv->parameter;
			else if(pEv->event == GHE_TimeSignature)
			{
				gEditor.currentTimeSignature = pEv->parameter;
				gEditor.lastTimeSignature = pEv->tick;
			}

			pEv = pEv->Next();
		}

		gEditor.playingTime = gEditor.pSong->CalculateTimeOfTick(gEditor.offset);

		MFVoice *pVoice = MFSound_Play(gEditor.pStepSound, MFPF_BeginPaused);
		if(pVoice)
		{
			MFSound_SetVolume(pVoice, gConfig.sound.fxLevel);
			MFSound_Pause(pVoice, false);
		}
	}

	// increase/decrease BPM
	if(gEditor.currentBPM > 1000 && TestControl(dBCtrl_Edit_DecreaseBPM, GHCT_Delay))
	{
		// reduce BPM
		int inc = 1000;

		if(shiftState)
			inc /= 10;
		if(ctrlState)
			inc /= 100;
		if(altState)
			inc *= 10;

		GHEvent *pEv = gEditor.pSong->sync.FindEvent(GHE_BPM, gEditor.offset, 0);
		if(!pEv) pEv = gEditor.pSong->sync.FindEvent(GHE_Anchor, gEditor.offset, 0);

		if(!pEv)
			pEv = gEditor.pSong->sync.AddEvent(GHE_BPM, gEditor.offset, 0, MFMax(gEditor.currentBPM - inc, 1000));
		else
			pEv->parameter = MFMax(pEv->parameter - inc, 1000);

		gEditor.currentBPM = pEv->parameter;

		// remove this BPM marker if its the same as the previous one..
		if(pEv->event != GHE_Anchor)
		{
			GHEvent *pPrev = gEditor.pSong->sync.GetMostRecentEvent(GHE_BPM, gEditor.offset);
			if(pPrev && pPrev->parameter == pEv->parameter)
				gEditor.pSong->sync.RemoveEvent(pEv);
		}

		// recalculate the note times from this point on
		gEditor.pSong->CalculateNoteTimes(gEditor.currentStream[0], gEditor.offset);
		if(gEditor.currentStream[1] != -1)
			gEditor.pSong->CalculateNoteTimes(gEditor.currentStream[1], gEditor.offset);
	}

	if(gEditor.currentBPM < 9999000 && TestControl(dBCtrl_Edit_IncreaseBPM, GHCT_Delay))
	{
		// increase BPM
		int inc = 1000;

		if(shiftState)
			inc /= 10;
		if(ctrlState)
			inc /= 100;
		if(altState)
			inc *= 10;

		GHEvent *pEv = gEditor.pSong->sync.FindEvent(GHE_BPM, gEditor.offset, 0);
		if(!pEv) pEv = gEditor.pSong->sync.FindEvent(GHE_Anchor, gEditor.offset, 0);

		if(!pEv)
			pEv = gEditor.pSong->sync.AddEvent(GHE_BPM, gEditor.offset, 0, MFMin(gEditor.currentBPM + inc, 9999000));
		else
			pEv->parameter = MFMin(pEv->parameter + inc, 9999000);

		gEditor.currentBPM = pEv->parameter;

		// remove this BPM marker if its the same as the previous one..
		if(pEv->event != GHE_Anchor)
		{
			GHEvent *pPrev = gEditor.pSong->sync.GetMostRecentEvent(GHE_BPM, gEditor.offset);
			if(pEv->event != GHE_Anchor && pPrev && pPrev->parameter == pEv->parameter)
				gEditor.pSong->sync.RemoveEvent(pEv);
		}

		// recalculate the note times from this point on
		gEditor.pSong->CalculateNoteTimes(gEditor.currentStream[0], gEditor.offset);
		if(gEditor.currentStream[1] != -1)
			gEditor.pSong->CalculateNoteTimes(gEditor.currentStream[1], gEditor.offset);
	}

	// place anchor
	if(TestControl(dBCtrl_Edit_Anchor, GHCT_Once) && gEditor.offset > 0)
	{
		GHEvent *pEv = gEditor.pSong->sync.FindEvent(GHE_BPM, gEditor.offset, 0);

		if(pEv)
		{
			pEv->event = GHE_Anchor;
			pEv->time = gEditor.pSong->CalculateTimeOfTick(pEv->tick);
		}
		else
		{
			pEv = gEditor.pSong->sync.FindEvent(GHE_Anchor, gEditor.offset, 0);

			if(!pEv)
			{
				pEv = gEditor.pSong->sync.AddEvent(GHE_Anchor, gEditor.offset, 0, gEditor.currentBPM);
				pEv->time = gEditor.pSong->CalculateTimeOfTick(pEv->tick);
			}
			else
			{
				GHEvent *pLast = gEditor.pSong->sync.GetMostRecentSyncEvent(pEv->tick);

				if(pLast && pLast->parameter == pEv->parameter)
					gEditor.pSong->sync.RemoveEvent(pEv);
				else
					pEv->event = GHE_BPM;
			}
		}

		// recalculate the note times
		gEditor.pSong->CalculateNoteTimes(gEditor.currentStream[0], 0);
		if(gEditor.currentStream[1] != -1)
			gEditor.pSong->CalculateNoteTimes(gEditor.currentStream[1], 0);
	}

	// change time signature
	if(TestControl(dBCtrl_Edit_DecreaseTS, GHCT_Delay) && gEditor.currentTimeSignature > 1)
	{
		int tsTime = gEditor.offset - ((gEditor.offset - gEditor.lastTimeSignature) % (res*gEditor.currentTimeSignature));

		GHEvent *pEv = gEditor.pSong->sync.FindEvent(GHE_TimeSignature, tsTime, 0);

		if(!pEv)
			pEv = gEditor.pSong->sync.AddEvent(GHE_TimeSignature, tsTime, 0, gEditor.currentTimeSignature - 1);
		else
			--pEv->parameter;

		gEditor.currentTimeSignature = pEv->parameter;
		gEditor.lastTimeSignature = tsTime;

		// remove this BPM marker if its the same as the previous one..
		GHEvent *pPrev = gEditor.pSong->sync.GetMostRecentEvent(GHE_TimeSignature, tsTime);
		if(pPrev && pPrev->parameter == pEv->parameter)
		{
			gEditor.lastTimeSignature = pPrev->tick;
			gEditor.pSong->sync.RemoveEvent(pEv);
		}

		// recalculate the note times from this point on
		gEditor.pSong->CalculateNoteTimes(gEditor.currentStream[0], tsTime);
		if(gEditor.currentStream[1] != -1)
			gEditor.pSong->CalculateNoteTimes(gEditor.currentStream[1], tsTime);
	}
	else if(TestControl(dBCtrl_Edit_IncreaseTS, GHCT_Delay) && gEditor.currentTimeSignature < 99)
	{
		int tsTime = gEditor.offset - ((gEditor.offset - gEditor.lastTimeSignature) % (res*gEditor.currentTimeSignature));

		GHEvent *pEv = gEditor.pSong->sync.FindEvent(GHE_TimeSignature, tsTime, 0);

		if(!pEv)
			pEv = gEditor.pSong->sync.AddEvent(GHE_TimeSignature, tsTime, 0, gEditor.currentTimeSignature + 1);
		else
			++pEv->parameter;

		gEditor.currentTimeSignature = pEv->parameter;
		gEditor.lastTimeSignature = tsTime;

		// remove this BPM marker if its the same as the previous one..
		GHEvent *pPrev = gEditor.pSong->sync.GetMostRecentEvent(GHE_TimeSignature, tsTime);
		if(pPrev && pPrev->parameter == pEv->parameter)
		{
			gEditor.lastTimeSignature = pPrev->tick;
			gEditor.pSong->sync.RemoveEvent(pEv);
		}

		// recalculate the note times from this point on
		gEditor.pSong->CalculateNoteTimes(gEditor.currentStream[0], tsTime);
		if(gEditor.currentStream[1] != -1)
			gEditor.pSong->CalculateNoteTimes(gEditor.currentStream[1], tsTime);
	}

	// add/remove notes
	GHEventManager &noteStream = gEditor.pSong->notes[gEditor.currentStream[gEditor.selectedStream]];
	dBControlType keys_righty[] = { dBCtrl_Edit_Note0, dBCtrl_Edit_Note1, dBCtrl_Edit_Note2, dBCtrl_Edit_Note3, dBCtrl_Edit_Note4, dBCtrl_Edit_PS1, dBCtrl_Edit_PS2, dBCtrl_Edit_Note5 };
	dBControlType keys_lefty[] = { dBCtrl_Edit_Note4, dBCtrl_Edit_Note3, dBCtrl_Edit_Note2, dBCtrl_Edit_Note1, dBCtrl_Edit_Note0, dBCtrl_Edit_PS1, dBCtrl_Edit_PS2, dBCtrl_Edit_Note5 };
	dBControlType *keys = gConfig.controls.leftyFlip[0] ? keys_lefty : keys_righty;

	for(int a=0; a<8; a++)
	{
		GHEventType ev = a < 5 ? GHE_Note : GHE_Special;
		int key = a < 5 ? GHEK_Green + a : GHS_Player1 + (a - 5);

		if(TestControl(keys[a], GHCT_Hold))
		{
			if(pHold[a])
			{
				if(pHold[a] != (GHEvent*)(size_t)0xFFFFFFFF)
				{
					pHold[a]->parameter = MFMax(gEditor.offset - pHold[a]->tick, 0);
				}
			}
			else
			{
				GHEvent *pEv = noteStream.FindEvent(ev, gEditor.offset, key);

				if(pEv)
				{
					noteStream.RemoveEvent(pEv);
					pHold[a] = (GHEvent*)(size_t)0xFFFFFFFF;
					for(int i=0; i<8; ++i)
					{
						if(pHold[i] && pHold[i] != (GHEvent*)(size_t)0xFFFFFFFF)
						{
							if(pHold[i] > pEv)
								--pHold[i];
						}
					}
				}
				else
				{
					// check if we are intersecting a hold note
					pEv = noteStream.GetMostRecentEvent(GHE_Note, gEditor.offset);

					if(pEv && pEv->parameter > gEditor.offset - pEv->tick)
					{
						// the last note was a hold note, we'll cut it short...
						do
						{
							pEv->parameter = gEditor.offset - pEv->tick;
							pEv = pEv->Prev();
						}
						while(pEv && pEv->tick == pEv->Next()->tick);
					}

					pEv = noteStream.AddEvent(ev, gEditor.offset, key);
					pEv->time = gEditor.pSong->CalculateTimeOfTick(gEditor.offset);
					pHold[a] = pEv;
				}
			}
		}
		else
		{
			if(a<5)
			{
				// check if we have just released a hold note
				if(pHold[a] && pHold[a] != (GHEvent*)(size_t)0xFFFFFFFF && pHold[a]->parameter != 0)
				{
					// remove any other notes within the hold range
					GHEvent *pEv = gEditor.pSong->notes[gEditor.currentStream[gEditor.selectedStream]].GetNextEvent(pHold[a]->tick);

					while(pEv && pEv->tick < pHold[a]->tick+pHold[a]->parameter)
					{
						GHEvent *pNext = pEv->Next();

						if(pEv->event == GHE_Note)
						{
							// and make sure we dont remove chords
							if(pHold[a]->tick != pEv->tick || pHold[a]->parameter != pEv->parameter)
							{
								pNext = noteStream.RemoveEvent(pEv);
								for(int i=0; i<8; ++i)
								{
									if(pHold[i] && pHold[i] != (GHEvent*)(size_t)0xFFFFFFFF)
									{
										if(pHold[i] > pEv)
											--pHold[i];
									}
								}
							}
						}

						pEv = pNext;
					}
				}
			}
			else
			{
				// remove zero length special events...
				if(pHold[a] && pHold[a] != (GHEvent*)(size_t)0xFFFFFFFF && pHold[a]->parameter == 0)
				{
					noteStream.RemoveEvent(pHold[a]);
				}
			}

			pHold[a] = NULL;
		}
	}
}
Ejemplo n.º 12
0
void Game_Update()
{
	if(!bShowModel)
	{
		if(MFInput_WasPressed(Key_Up, IDD_Keyboard) && menuIndex > 0)
			--menuIndex;
		else if(MFInput_WasPressed(Key_Down, IDD_Keyboard) && menuIndex < (int)models.size()-1)
			++menuIndex;
		else if(MFInput_WasPressed(Key_Return, IDD_Keyboard) && models.size() > 0)
		{
			bShowModel = true;

			// load model
			pModel = MFModel_CreateWithAnimation(models[menuIndex].CStr());
		}
	}
	else
	{
		if(MFInput_WasPressed(Key_Escape, IDD_Keyboard))
		{
			if(pModel)
			{
				MFModel_Destroy(pModel);
				pModel = NULL;
			}

			models.clear();
			Scan("data:");

			if(models.size() <= (size_t)menuIndex)
				menuIndex = models.size() ? (int)models.size() - 1 : 0;
			bShowModel = false;
			return;
		}

		if(pModel)
		{
			if(MFInput_Read(Mouse_LeftButton, IDD_Mouse) > 0.f)
			{
				yaw += -MFInput_Read(Mouse_XDelta, IDD_Mouse) * 0.02f;
				pitch += -MFInput_Read(Mouse_YDelta, IDD_Mouse) * 0.015f;
			}
			if(MFInput_Read(Mouse_MiddleButton, IDD_Mouse) > 0.f)
			{
				zoom *= 1.f + -MFInput_Read(Mouse_YDelta, IDD_Mouse) * 0.02f;
			}

			// calculate a spinning world matrix
			MFMatrix world;
			world.SetTranslation(MakeVector(0, -0.25f, 1) * zoom);
			world.RotateY(yaw);
			world.RotateX(pitch);

			// set world matrix to the model
			MFModel_SetWorldMatrix(pModel, world);

			// advance the animation
			MFAnimation *pAnim = MFModel_GetAnimation(pModel);
			if(pAnim)
			{
				float start, end;
				MFAnimation_GetFrameRange(pAnim, &start, &end);
	
				static float time = 0.f;
				time += MFSystem_TimeDelta();// * 500;
				while(time >= end)
					time -= end;
				MFAnimation_SetFrame(pAnim, time);
			}
		}
	}
}
Ejemplo n.º 13
0
void HKStringEntryLogic::Update()
{
	bool shiftL = !!MFInput_Read(Key_LShift, IDD_Keyboard);
	bool shiftR = !!MFInput_Read(Key_RShift, IDD_Keyboard);
	bool ctrlL = !!MFInput_Read(Key_LControl, IDD_Keyboard);
	bool ctrlR = !!MFInput_Read(Key_RControl, IDD_Keyboard);

	int keyPressed = 0;

	bool shift = shiftL || shiftR;
	bool ctrl = ctrlL || ctrlR;

#if defined(MF_WINDOWS)
	if(ctrl && MFInput_WasPressed(Key_C, IDD_Keyboard) && selectionStart != selectionEnd)
	{
		BOOL opened = OpenClipboard(apphWnd);

		if(opened)
		{
			int selMin = MFMin(selectionStart, selectionEnd);
			int selMax = MFMax(selectionStart, selectionEnd);

			int numChars = selMax-selMin;

			HANDLE hData = GlobalAlloc(GMEM_MOVEABLE, numChars + 1);
			char *pString = (char*)GlobalLock(hData);

			MFString_Copy(pString, GetRenderString().SubStr(selMin, numChars).CStr());

			GlobalUnlock(hData);

			EmptyClipboard();
			SetClipboardData(CF_TEXT, hData);

			CloseClipboard();
		}
	}
	else if(ctrl && MFInput_WasPressed(Key_X, IDD_Keyboard) && selectionStart != selectionEnd)
	{
		BOOL opened = OpenClipboard(apphWnd);

		if(opened)
		{
			int selMin = MFMin(selectionStart, selectionEnd);
			int selMax = MFMax(selectionStart, selectionEnd);

			int numChars = selMax-selMin;

			HANDLE hData = GlobalAlloc(GMEM_MOVEABLE, numChars + 1);
			char *pString = (char*)GlobalLock(hData);

			MFString_Copy(pString, GetRenderString().SubStr(selMin, numChars).CStr());

			GlobalUnlock(hData);

			EmptyClipboard();
			SetClipboardData(CF_TEXT, hData);

			CloseClipboard();

			ClearSelection();
		}
	}
	else if(ctrl && MFInput_WasPressed(Key_V, IDD_Keyboard))
	{
		BOOL opened = OpenClipboard(apphWnd);

		if(opened)
		{
			int selMin = MFMin(selectionStart, selectionEnd);
			int selMax = MFMax(selectionStart, selectionEnd);

			int numChars = selMax-selMin;

			HANDLE hData = GetClipboardData(CF_TEXT);
			MFString paste((const char*)GlobalLock(hData), true);

			buffer.Replace(selMin, numChars, paste);

			GlobalUnlock(hData);

			cursorPos = selMin + paste.NumBytes();
			selectionStart = selectionEnd = cursorPos;

			GlobalUnlock(hData);

			CloseClipboard();

			if((numChars || cursorPos != selMin) && changeCallback)
				changeCallback(buffer.CStr());
		}
	}
	else
#endif
	{
		// check for new keypresses
		for(int a=0; a<255; a++)
		{
			if(MFInput_WasPressed(a, IDD_Keyboard))
			{
				keyPressed = a;
				holdKey = a;
				repeatDelay = gRepeatDelay;
				break;
			}
		}

		// handle repeat keys
		if(holdKey && MFInput_Read(holdKey, IDD_Keyboard))
		{
			repeatDelay -= MFSystem_TimeDelta();
			if(repeatDelay <= 0.f)
			{
				keyPressed = holdKey;
				repeatDelay += gRepeatRate;
			}
		}
		else
			holdKey = 0;

		// if there was a new key press
		if(keyPressed)
		{
			switch(keyPressed)
			{
				case Key_Backspace:
				case Key_Delete:
				{
					if(selectionStart != selectionEnd)
					{
						ClearSelection();
					}
					else
					{
						if(keyPressed == Key_Backspace && cursorPos > 0)
						{
							buffer.ClearRange(--cursorPos, 1);
							selectionStart = selectionEnd = cursorPos;

							if(changeCallback)
								changeCallback(buffer.CStr());
						}
						else if(keyPressed == Key_Delete && cursorPos < buffer.NumBytes())
						{
							buffer.ClearRange(cursorPos, 1);
							selectionStart = selectionEnd = cursorPos;

							if(changeCallback)
								changeCallback(buffer.CStr());
						}
					}
					break;
				}

				case Key_Left:
				case Key_Right:
				case Key_Home:
				case Key_End:
				{
					if(ctrl)
					{
						if(keyPressed == Key_Left)
						{
							while(cursorPos && MFIsWhite(buffer[cursorPos-1]))
								--cursorPos;
							if(MFIsAlphaNumeric(buffer[cursorPos-1]))
							{
								while(cursorPos && MFIsAlphaNumeric(buffer[cursorPos-1]))
									--cursorPos;
							}
							else if(cursorPos)
							{
								--cursorPos;
								while(cursorPos && buffer[cursorPos-1] == buffer[cursorPos])
									--cursorPos;
							}
						}
						else if(keyPressed == Key_Right)
						{
							while(cursorPos < buffer.NumBytes() && MFIsWhite(buffer[cursorPos]))
								++cursorPos;
							if(MFIsAlphaNumeric(buffer[cursorPos]))
							{
								while(cursorPos < buffer.NumBytes() && MFIsAlphaNumeric(buffer[cursorPos]))
									++cursorPos;
							}
							else if(cursorPos < buffer.NumBytes())
							{
								++cursorPos;
								while(cursorPos < buffer.NumBytes() && buffer[cursorPos] == buffer[cursorPos-1])
									++cursorPos;
							}
						}
						else if(keyPressed == Key_Home)
							cursorPos = 0;
						else if(keyPressed == Key_End)
							cursorPos = buffer.NumBytes();
					}
					else
					{
						if(keyPressed == Key_Left)
							cursorPos = (!shift && selectionStart != selectionEnd ? MFMin(selectionStart, selectionEnd) : MFMax(cursorPos-1, 0));
						else if(keyPressed == Key_Right)
							cursorPos = (!shift && selectionStart != selectionEnd ? MFMax(selectionStart, selectionEnd) : MFMin(cursorPos+1, buffer.NumBytes()));
						else if(keyPressed == Key_Home)
							cursorPos = 0;	// TODO: if multiline, go to start of line..
						else if(keyPressed == Key_End)
							cursorPos = buffer.NumBytes();	// TODO: if multiline, go to end of line...
					}

					if(shift)
						selectionEnd = cursorPos;
					else
						selectionStart = selectionEnd = cursorPos;

					break;
				}

				default:
				{
					bool caps = MFInput_GetKeyboardStatusState(KSS_CapsLock);
					int ascii = MFInput_KeyToAscii(keyPressed, shift, caps);

					if(ascii && (!maxLen || buffer.NumBytes() < maxLen-1))
					{
						// check character exclusions
						if(MFIsNewline(ascii) && type != ST_MultiLine)
							break;
						if(ascii == '\t' && type != ST_MultiLine)
							break;
						if(type == ST_Numeric && !MFIsNumeric(ascii))
							break;
						if(include)
						{
							if(include.FindChar(ascii) < 0)
								break;
						}
						if(exclude)
						{
							if(exclude.FindChar(ascii) >= 0)
								break;
						}

						int selMin = MFMin(selectionStart, selectionEnd);
						int selMax = MFMax(selectionStart, selectionEnd);
						int selRange = selMax - selMin;

						const uint16 wstr[] = { (uint16)ascii, 0 };
						char insert[5];
						MFString_CopyUTF16ToUTF8(insert, wstr);
						buffer.Replace(selMin, selRange, insert);
						cursorPos = selMin + 1;

						selectionStart = selectionEnd = cursorPos;

						if(changeCallback)
							changeCallback(buffer.CStr());
					}
					break;
				}
			}
		}
	}
}