Exemple #1
0
//Main Event driven tick
void ULeapController::InterfaceEventTick(float DeltaTime)
{
	//This is our tick event that is forwarded from the delegate, check validity
	if (!_private->interfaceDelegate) return;

	//Pointers
	Leap::Frame frame = _private->leap.frame();
	Leap::Frame pastFrame = _private->leap.frame(1);

	//-Hands-

	//Hand Count
	int handCount = frame.hands().count();

	if (_private->pastState.handCount != handCount)
	{
		ILeapEventInterface::Execute_HandCountChanged(_private->interfaceDelegate, handCount);
		
		//Zero our input mapping orientations (akin to letting go of a joystick)
		if (handCount == 0)
		{
			EmitAnalogInputEventForKey(EKeysLeap::LeapLeftPalmPitch, 0, 0, 0);
			EmitAnalogInputEventForKey(EKeysLeap::LeapLeftPalmYaw, 0, 0, 0);
			EmitAnalogInputEventForKey(EKeysLeap::LeapLeftPalmRoll, 0, 0, 0);
			EmitAnalogInputEventForKey(EKeysLeap::LeapRightPalmPitch, 0, 0, 0);
			EmitAnalogInputEventForKey(EKeysLeap::LeapRightPalmYaw, 0, 0, 0);
			EmitAnalogInputEventForKey(EKeysLeap::LeapRightPalmRoll, 0, 0, 0);
		}
	}

	//Cycle through each hand
	for (int i = 0; i < handCount; i++)
	{
		Leap::Hand hand = frame.hands()[i];
		LeapHandStateData pastHandState = _private->pastState.stateForId(hand.id());		//we use a custom class to hold reliable state tracking based on id's

		//Make a ULeapHand
		if (_private->eventHand == NULL)
		{
			_private->eventHand = NewObject<ULeapHand>(this);
			_private->eventHand->SetFlags(RF_RootSet);
		}
		_private->eventHand->setHand(hand);

		//Emit hand
		ILeapEventInterface::Execute_LeapHandMoved(_private->interfaceDelegate, _private->eventHand);

		//Left/Right hand forwarding
		if (hand.isRight())
		{
			ILeapEventInterface::Execute_LeapRightHandMoved(_private->interfaceDelegate, _private->eventHand);
			//Input Mapping
			FRotator palmOrientation = _private->eventHand->PalmOrientation;
			EmitAnalogInputEventForKey(EKeysLeap::LeapRightPalmPitch, palmOrientation.Pitch * LEAP_IM_SCALE, 0, 0);
			EmitAnalogInputEventForKey(EKeysLeap::LeapRightPalmYaw, palmOrientation.Yaw * LEAP_IM_SCALE, 0, 0);
			EmitAnalogInputEventForKey(EKeysLeap::LeapRightPalmRoll, palmOrientation.Roll * LEAP_IM_SCALE, 0, 0);
		} else if (hand.isLeft())
		{
			ILeapEventInterface::Execute_LeapLeftHandMoved(_private->interfaceDelegate, _private->eventHand);
			//Input Mapping
			FRotator palmOrientation = _private->eventHand->PalmOrientation;
			EmitAnalogInputEventForKey(EKeysLeap::LeapLeftPalmPitch, palmOrientation.Pitch * LEAP_IM_SCALE, 0, 0);
			EmitAnalogInputEventForKey(EKeysLeap::LeapLeftPalmYaw, palmOrientation.Yaw * LEAP_IM_SCALE, 0, 0);
			EmitAnalogInputEventForKey(EKeysLeap::LeapLeftPalmRoll, palmOrientation.Roll * LEAP_IM_SCALE, 0, 0);
		}

		//Grabbing
		float grabStrength = hand.grabStrength();
		bool grabbed = handClosed(grabStrength);

		if (grabbed)
			ILeapEventInterface::Execute_LeapHandGrabbing(_private->interfaceDelegate, grabStrength, _private->eventHand);

		if (grabbed && !pastHandState.grabbed)
		{
			ILeapEventInterface::Execute_LeapHandGrabbed(_private->interfaceDelegate, grabStrength, _private->eventHand);
			
			//input mapping
			if (_private->eventHand->HandType == LeapHandType::HAND_LEFT)
				EmitKeyDownEventForKey(EKeysLeap::LeapLeftGrab, 0, 0);
			else
				EmitKeyDownEventForKey(EKeysLeap::LeapRightGrab, 0, 0);
		}else if (!grabbed && pastHandState.grabbed)
		{
			ILeapEventInterface::Execute_LeapHandReleased(_private->interfaceDelegate, grabStrength, _private->eventHand);

			//input mapping
			if (_private->eventHand->HandType == LeapHandType::HAND_LEFT)
				EmitKeyUpEventForKey(EKeysLeap::LeapLeftGrab, 0, 0);
			else
				EmitKeyUpEventForKey(EKeysLeap::LeapRightGrab, 0, 0);
		}

		//Pinching
		float pinchStrength = hand.pinchStrength();
		bool pinched = handPinched(pinchStrength);

		//While grabbing disable pinching detection, this helps to reduce spam as pose confidence plummets
		if (grabbed) pinched = pastHandState.pinched;
		else
		{
			if (pinched)
				ILeapEventInterface::Execute_LeapHandPinching(_private->interfaceDelegate, pinchStrength, _private->eventHand);

			if (pinched && !pastHandState.pinched)
			{
				ILeapEventInterface::Execute_LeapHandPinched(_private->interfaceDelegate, pinchStrength, _private->eventHand);
				//input mapping
				if (_private->eventHand->HandType == LeapHandType::HAND_LEFT)
					EmitKeyDownEventForKey(EKeysLeap::LeapLeftPinch, 0, 0);
				else
					EmitKeyDownEventForKey(EKeysLeap::LeapRightPinch, 0, 0);
			}
			else if (!pinched && pastHandState.pinched)
			{
				ILeapEventInterface::Execute_LeapHandUnpinched(_private->interfaceDelegate, pinchStrength, _private->eventHand);
				//input mapping
				if (_private->eventHand->HandType == LeapHandType::HAND_LEFT)
					EmitKeyUpEventForKey(EKeysLeap::LeapLeftPinch, 0, 0);
				else
					EmitKeyUpEventForKey(EKeysLeap::LeapRightPinch, 0, 0);
			}
		}

		//-Fingers-
		Leap::FingerList fingers = hand.fingers();

		//Count
		int fingerCount = fingers.count();
		if ((pastHandState.fingerCount != fingerCount))
			ILeapEventInterface::Execute_FingerCountChanged(_private->interfaceDelegate, fingerCount);

		if (_private->eventFinger == NULL)
		{
			_private->eventFinger = NewObject<ULeapFinger>(this);
			_private->eventFinger->SetFlags(RF_RootSet);
		}

		Leap::Finger finger;

		//Cycle through each finger
		for (int j = 0; j < fingerCount; j++)
		{
			finger = fingers[j];
			_private->eventFinger->setFinger(finger);

			//Finger Moved
			if (finger.isValid())
				ILeapEventInterface::Execute_LeapFingerMoved(_private->interfaceDelegate, _private->eventFinger);
		}

		//Do these last so we can easily override debug shapes

		//Leftmost
		finger = fingers.leftmost();
		_private->eventFinger->setFinger(finger);
		ILeapEventInterface::Execute_LeapLeftMostFingerMoved(_private->interfaceDelegate, _private->eventFinger);

		//Rightmost
		finger = fingers.rightmost();
		_private->eventFinger->setFinger(finger);
		ILeapEventInterface::Execute_LeapRightMostFingerMoved(_private->interfaceDelegate, _private->eventFinger);

		//Frontmost
		finger = fingers.frontmost();
		_private->eventFinger->setFinger(finger);
		ILeapEventInterface::Execute_LeapFrontMostFingerMoved(_private->interfaceDelegate, _private->eventFinger);

		//touch only for front-most finger, most common use case
		float touchDistance = finger.touchDistance();
		if (touchDistance <= 0.f)
			ILeapEventInterface::Execute_LeapFrontFingerTouch(_private->interfaceDelegate, _private->eventFinger);

		//Set the state data for next cycle
		pastHandState.grabbed = grabbed;
		pastHandState.pinched = pinched;
		pastHandState.fingerCount = fingerCount;

		_private->pastState.setStateForId(pastHandState, hand.id());
	}

	_private->pastState.handCount = handCount;

	//Gestures
	for (int i = 0; i < frame.gestures().count(); i++)
	{
		Leap::Gesture gesture = frame.gestures()[i];
		Leap::Gesture::Type type = gesture.type();

		switch (type)
		{
		case Leap::Gesture::TYPE_CIRCLE:
			if (_private->eventCircleGesture == NULL){
				_private->eventCircleGesture = NewObject<ULeapCircleGesture>(this);
				_private->eventCircleGesture->SetFlags(RF_RootSet);
			}
			_private->eventCircleGesture->setGesture(Leap::CircleGesture(gesture));
			ILeapEventInterface::Execute_CircleGestureDetected(_private->interfaceDelegate, _private->eventCircleGesture);
			_private->eventGesture = _private->eventCircleGesture;
			break;
		case Leap::Gesture::TYPE_KEY_TAP:
			if (_private->eventKeyTapGesture == NULL)
			{
				_private->eventKeyTapGesture = NewObject<ULeapKeyTapGesture>(this);
				_private->eventKeyTapGesture->SetFlags(RF_RootSet);
			}
			_private->eventKeyTapGesture->setGesture(Leap::KeyTapGesture(gesture));
			ILeapEventInterface::Execute_KeyTapGestureDetected(_private->interfaceDelegate, _private->eventKeyTapGesture);
			_private->eventGesture = _private->eventKeyTapGesture;
			break;
		case Leap::Gesture::TYPE_SCREEN_TAP:
			if (_private->eventScreenTapGesture == NULL)
			{
				_private->eventScreenTapGesture = NewObject<ULeapScreenTapGesture>(this);
				_private->eventScreenTapGesture->SetFlags(RF_RootSet);
			}
			_private->eventScreenTapGesture->setGesture(Leap::ScreenTapGesture(gesture));
			ILeapEventInterface::Execute_ScreenTapGestureDetected(_private->interfaceDelegate, _private->eventScreenTapGesture);
			_private->eventGesture = _private->eventScreenTapGesture;
			break;
		case Leap::Gesture::TYPE_SWIPE:
			if (_private->eventSwipeGesture == NULL)
			{
				_private->eventSwipeGesture = NewObject<ULeapSwipeGesture>(this);
				_private->eventSwipeGesture->SetFlags(RF_RootSet);
			}
			_private->eventSwipeGesture->setGesture(Leap::SwipeGesture(gesture));
			ILeapEventInterface::Execute_SwipeGestureDetected(_private->interfaceDelegate, _private->eventSwipeGesture);
			_private->eventGesture = _private->eventSwipeGesture;
			break;
		default:
			break;
		}

		//emit gesture
		if (type != Leap::Gesture::TYPE_INVALID)
		{
			ILeapEventInterface::Execute_GestureDetected(_private->interfaceDelegate, _private->eventGesture);
		}
	}

	//Image
	if (_private->allowImages && _private->imageEventsEnabled)
	{
		int imageCount = frame.images().count();
		for (int i = 0; i < imageCount; i++)
		{
			Leap::Image image = frame.images()[i];

			//Loop modification - Only emit 0 and 1, use two different pointers so we can get different images
			if (i == 0)
			{
				if (_private->eventImage1 == NULL)
				{
					_private->eventImage1 = NewObject<ULeapImage>(this);
					_private->eventImage1->SetFlags(RF_RootSet);
				}
				_private->eventImage1->setLeapImage(image);

				ILeapEventInterface::Execute_RawImageReceived(_private->interfaceDelegate, _private->eventImage1->Texture(), _private->eventImage1);
			}
			else if (i == 1)
			{
				if (_private->eventImage2 == NULL)
                {
					_private->eventImage2 = NewObject<ULeapImage>(this);
					_private->eventImage2->SetFlags(RF_RootSet);
				}
				_private->eventImage2->setLeapImage(image);

				ILeapEventInterface::Execute_RawImageReceived(_private->interfaceDelegate, _private->eventImage2->Texture(), _private->eventImage2);
			}
		}
	}
}
void FLeapMotionInputDevice::ParseEvents()
{
	//Optimization: If we don't have any delegates, skip
	if (EventDelegates.Num() == 0)
	{
		return;
	}

	//Pointers
	Leap::Frame Frame = ControllerData.LeapController.frame();
	Leap::Frame PastFrame = ControllerData.LeapController.frame(1);

	//Calculate HMD Timewarp if valid
	if (GEngine->HMDDevice.IsValid() && ControllerData.bTimeWarpEnabled) {
		LeapHMDSnapshot ThenSnapshot = HMDSamples->HMDSampleClosestToTimestamp(Frame.timestamp());
		LeapHMDSnapshot NowSnapShot = HMDSamples->CurrentHMDSample();

		LeapHMDSnapshot HistorySnapshot = HMDSamples->LastHMDSample();	//reduce jitter
		//ControllerData.TimeWarpSnapshot = NowSnapShot.Difference(ThenSnapshot, ControllerData.TimeWarpFactor);// * ControllerData.TimeWarpFactor;

		FQuat WarpQuat = NowSnapShot.Orientation;//FQuat::Slerp(NowSnapShot.Orientation, HistorySnapshot.Orientation, ControllerData.TimeWarpTween);
		FQuat ThenTweened = FQuat::Slerp(ThenSnapshot.Orientation, HistorySnapshot.Orientation, ControllerData.TimeWarpTween);

		ControllerData.TimeWarpSnapshot.Orientation = (WarpQuat.Inverse() * ControllerData.TimeWarpFactor) * ThenTweened;

		ControllerData.TimeWarpAmountMs = (ControllerData.TimeWarpSnapshot.Timestamp) / 1000.f;
	}

	//-Hands-

	//Hand Count
	int HandCount = Frame.hands().count();

	if (PastState->HandCount != HandCount)
	{
		CallFunctionOnDelegates([&](UObject* EventDelegate)
		{
			ILeapEventInterface::Execute_HandCountChanged(EventDelegate, HandCount);
		});
		//Zero our input mapping orientations (akin to letting go of a joystick)
		if (HandCount == 0)
		{
			EmitAnalogInputEventForKey(EKeysLeap::LeapLeftPalmPitch, 0, 0, 0);
			EmitAnalogInputEventForKey(EKeysLeap::LeapLeftPalmYaw, 0, 0, 0);
			EmitAnalogInputEventForKey(EKeysLeap::LeapLeftPalmRoll, 0, 0, 0);
			EmitAnalogInputEventForKey(EKeysLeap::LeapRightPalmPitch, 0, 0, 0);
			EmitAnalogInputEventForKey(EKeysLeap::LeapRightPalmYaw, 0, 0, 0);
			EmitAnalogInputEventForKey(EKeysLeap::LeapRightPalmRoll, 0, 0, 0);
		}
	}

	//Cycle through each hand
	for (int i = 0; i < HandCount; i++)
	{
		Leap::Hand Hand = Frame.hands()[i];
		LeapHandStateData PastHandState = PastState->StateForId(Hand.id());		//we use a custom class to hold reliable state tracking based on id's

																				//Make a ULeapHand
		if (PEventHand == nullptr)
		{
			PEventHand = NewObject<ULeapHand>();
			PEventHand->AddToRoot();
		}
		PEventHand->SetHand(Hand);

		//Emit hand
		CallFunctionOnDelegates([&](UObject* EventDelegate)
		{
			ILeapEventInterface::Execute_LeapHandMoved(EventDelegate, PEventHand);
		});


		//Left/Right hand forwarding
		if (Hand.isRight())
		{
			CallFunctionOnDelegates([&](UObject* EventDelegate)
			{
				ILeapEventInterface::Execute_LeapRightHandMoved(EventDelegate, PEventHand);
			});

			//Input Mapping
			FRotator PalmOrientation = PEventHand->PalmOrientation;
			EmitAnalogInputEventForKey(EKeysLeap::LeapRightPalmPitch, PalmOrientation.Pitch * LEAP_IM_SCALE, 0, 0);
			EmitAnalogInputEventForKey(EKeysLeap::LeapRightPalmYaw, PalmOrientation.Yaw * LEAP_IM_SCALE, 0, 0);
			EmitAnalogInputEventForKey(EKeysLeap::LeapRightPalmRoll, PalmOrientation.Roll * LEAP_IM_SCALE, 0, 0);
		}
		else if (Hand.isLeft())
		{
			CallFunctionOnDelegates([&](UObject* EventDelegate)
			{
				ILeapEventInterface::Execute_LeapLeftHandMoved(EventDelegate, PEventHand);
			});

			//Input Mapping
			FRotator PalmOrientation = PEventHand->PalmOrientation;
			EmitAnalogInputEventForKey(EKeysLeap::LeapLeftPalmPitch, PalmOrientation.Pitch * LEAP_IM_SCALE, 0, 0);
			EmitAnalogInputEventForKey(EKeysLeap::LeapLeftPalmYaw, PalmOrientation.Yaw * LEAP_IM_SCALE, 0, 0);
			EmitAnalogInputEventForKey(EKeysLeap::LeapLeftPalmRoll, PalmOrientation.Roll * LEAP_IM_SCALE, 0, 0);
		}

		//Grabbing
		float GrabStrength = Hand.grabStrength();
		bool Grabbed = HandClosed(GrabStrength);

		if (Grabbed)
		{
			CallFunctionOnDelegates([&](UObject* EventDelegate)
			{
				ILeapEventInterface::Execute_LeapHandGrabbing(EventDelegate, GrabStrength, PEventHand);
			});

		}

		if (Grabbed && !PastHandState.Grabbed)
		{
			CallFunctionOnDelegates([&](UObject* EventDelegate)
			{
				ILeapEventInterface::Execute_LeapHandGrabbed(EventDelegate, GrabStrength, PEventHand);
			});

			//input mapping
			if (PEventHand->HandType == LeapHandType::HAND_LEFT)
			{
				EmitKeyDownEventForKey(EKeysLeap::LeapLeftGrab, 0, 0);
			}
			else
			{
				EmitKeyDownEventForKey(EKeysLeap::LeapRightGrab, 0, 0);
			}
		}
		else if (!Grabbed && PastHandState.Grabbed)
		{
			CallFunctionOnDelegates([&](UObject* EventDelegate)
			{
				ILeapEventInterface::Execute_LeapHandReleased(EventDelegate, GrabStrength, PEventHand);
			});

			//input mapping
			if (PEventHand->HandType == LeapHandType::HAND_LEFT)
			{
				EmitKeyUpEventForKey(EKeysLeap::LeapLeftGrab, 0, 0);
			}
			else
			{
				EmitKeyUpEventForKey(EKeysLeap::LeapRightGrab, 0, 0);
			}
		}

		//Pinching
		float PinchStrength = Hand.pinchStrength();
		bool Pinched = HandPinched(PinchStrength);

		//While grabbing disable pinching detection, this helps to reduce spam as pose confidence plummets
		if (Grabbed)
		{
			Pinched = PastHandState.Pinched;
		}
		else
		{
			if (Pinched)
			{
				CallFunctionOnDelegates([&](UObject* EventDelegate)
				{
					ILeapEventInterface::Execute_LeapHandPinching(EventDelegate, PinchStrength, PEventHand);
				});
			}
			if (Pinched && !PastHandState.Pinched)
			{
				CallFunctionOnDelegates([&](UObject* EventDelegate)
				{
					ILeapEventInterface::Execute_LeapHandPinched(EventDelegate, PinchStrength, PEventHand);
				});
				//input mapping
				if (PEventHand->HandType == LeapHandType::HAND_LEFT)
				{
					EmitKeyDownEventForKey(EKeysLeap::LeapLeftPinch, 0, 0);
				}
				else
				{
					EmitKeyDownEventForKey(EKeysLeap::LeapRightPinch, 0, 0);
				}
			}
			else if (!Pinched && PastHandState.Pinched)
			{
				CallFunctionOnDelegates([&](UObject* EventDelegate)
				{
					ILeapEventInterface::Execute_LeapHandUnpinched(EventDelegate, PinchStrength, PEventHand);
				});
				//input mapping
				if (PEventHand->HandType == LeapHandType::HAND_LEFT)
				{
					EmitKeyUpEventForKey(EKeysLeap::LeapLeftPinch, 0, 0);
				}
				else
				{
					EmitKeyUpEventForKey(EKeysLeap::LeapRightPinch, 0, 0);
				}
			}
		}

		//-Fingers-
		Leap::FingerList Fingers = Hand.fingers();

		//Count
		int FingerCount = Fingers.count();
		if ((PastHandState.FingerCount != FingerCount))
		{
			CallFunctionOnDelegates([&](UObject* EventDelegate)
			{
				ILeapEventInterface::Execute_FingerCountChanged(EventDelegate, FingerCount);
			});
		}
		if (PEventFinger == nullptr)
		{
			PEventFinger = NewObject<ULeapFinger>();
			PEventFinger->AddToRoot();
		}

		Leap::Finger Finger;

		//Cycle through each finger
		for (int j = 0; j < FingerCount; j++)
		{
			Finger = Fingers[j];
			PEventFinger->SetFinger(Finger);

			//Finger Moved
			if (Finger.isValid())
			{
				CallFunctionOnDelegates([&](UObject* EventDelegate)
				{
					ILeapEventInterface::Execute_LeapFingerMoved(EventDelegate, PEventFinger);
				});
			}
		}

		//Do these last so we can easily override debug shapes

		//Leftmost
		Finger = Fingers.leftmost();
		PEventFinger->SetFinger(Finger);
		CallFunctionOnDelegates([&](UObject* EventDelegate)
		{
			ILeapEventInterface::Execute_LeapLeftMostFingerMoved(EventDelegate, PEventFinger);
		});

		//Rightmost
		Finger = Fingers.rightmost();
		PEventFinger->SetFinger(Finger);
		CallFunctionOnDelegates([&](UObject* EventDelegate)
		{
			ILeapEventInterface::Execute_LeapRightMostFingerMoved(EventDelegate, PEventFinger);
		});

		//Frontmost
		Finger = Fingers.frontmost();
		PEventFinger->SetFinger(Finger);
		CallFunctionOnDelegates([&](UObject* EventDelegate)
		{
			ILeapEventInterface::Execute_LeapFrontMostFingerMoved(EventDelegate, PEventFinger);
		});

		//touch only for front-most finger, most common use case
		float touchDistance = Finger.touchDistance();
		if (touchDistance <= 0.f)
		{
			CallFunctionOnDelegates([&](UObject* EventDelegate)
			{
				ILeapEventInterface::Execute_LeapFrontFingerTouch(EventDelegate, PEventFinger);
			});
		}

		//Set the state data for next cycle
		PastHandState.Grabbed = Grabbed;
		PastHandState.Pinched = Pinched;
		PastHandState.FingerCount = FingerCount;

		PastState->SetStateForId(PastHandState, Hand.id());
	}

	PastState->HandCount = HandCount;

	//Gestures
	for (int i = 0; i < Frame.gestures().count(); i++)
	{
		Leap::Gesture Gesture = Frame.gestures()[i];
		Leap::Gesture::Type Type = Gesture.type();

		switch (Type)
		{
		case Leap::Gesture::TYPE_CIRCLE:
			if (PEventCircleGesture == nullptr)
			{
				PEventCircleGesture = NewObject<ULeapCircleGesture>();
				PEventCircleGesture->AddToRoot();
			}
			PEventCircleGesture->SetGesture(Leap::CircleGesture(Gesture));
			CallFunctionOnDelegates([&](UObject* EventDelegate)
			{
				ILeapEventInterface::Execute_CircleGestureDetected(EventDelegate, PEventCircleGesture);
			});
			PEventGesture = PEventCircleGesture;
			break;
		case Leap::Gesture::TYPE_KEY_TAP:
			if (PEventKeyTapGesture == nullptr)
			{
				PEventKeyTapGesture = NewObject<ULeapKeyTapGesture>();
				PEventKeyTapGesture->AddToRoot();
			}
			PEventKeyTapGesture->SetGesture(Leap::KeyTapGesture(Gesture));
			CallFunctionOnDelegates([&](UObject* EventDelegate)
			{
				ILeapEventInterface::Execute_KeyTapGestureDetected(EventDelegate, PEventKeyTapGesture);
			});
			PEventGesture = PEventKeyTapGesture;
			break;
		case Leap::Gesture::TYPE_SCREEN_TAP:
			if (PEventScreenTapGesture == nullptr)
			{
				PEventScreenTapGesture = NewObject<ULeapScreenTapGesture>();
				PEventScreenTapGesture->AddToRoot();
			}
			PEventScreenTapGesture->SetGesture(Leap::ScreenTapGesture(Gesture));
			CallFunctionOnDelegates([&](UObject* EventDelegate)
			{
				ILeapEventInterface::Execute_ScreenTapGestureDetected(EventDelegate, PEventScreenTapGesture);
			});
			PEventGesture = PEventScreenTapGesture;
			break;
		case Leap::Gesture::TYPE_SWIPE:
			if (PEventSwipeGesture == nullptr)
			{
				PEventSwipeGesture = NewObject<ULeapSwipeGesture>();
				PEventSwipeGesture->AddToRoot();
			}
			PEventSwipeGesture->SetGesture(Leap::SwipeGesture(Gesture));
			CallFunctionOnDelegates([&](UObject* EventDelegate)
			{
				ILeapEventInterface::Execute_SwipeGestureDetected(EventDelegate, PEventSwipeGesture);
			});
			PEventGesture = PEventSwipeGesture;
			break;
		default:
			break;
		}

		//emit gesture
		if (Type != Leap::Gesture::TYPE_INVALID)
		{
			CallFunctionOnDelegates([&](UObject* EventDelegate)
			{
				ILeapEventInterface::Execute_GestureDetected(EventDelegate, PEventGesture);
			});
		}
	}

	//Image
	if (ControllerData.bAllowImageEvents && ControllerData.bImageEventsEnabled)
	{
		int ImageCount = Frame.images().count();

		//We only support getting both images
		if (ImageCount >= 2)
		{
			Leap::Image Image1 = Frame.images()[0];
			if (PEventImage1 == nullptr)
			{
				PEventImage1 = NewObject<ULeapImage>();
				PEventImage1->AddToRoot();
			}
			PEventImage1->UseGammaCorrection = ControllerData.bUseGammaCorrection;
			PEventImage1->SetLeapImage(Image1);

			CallFunctionOnDelegates([&](UObject* EventDelegate)
			{
				ILeapEventInterface::Execute_RawImageReceived(EventDelegate, PEventImage1->Texture(), PEventImage1);
			});

			Leap::Image Image2 = Frame.images()[1];
			if (PEventImage2 == nullptr)
			{
				PEventImage2 = NewObject<ULeapImage>();
				PEventImage2->AddToRoot();
			}
			PEventImage2->UseGammaCorrection = ControllerData.bUseGammaCorrection;
			PEventImage2->SetLeapImage(Image2);

			CallFunctionOnDelegates([&](UObject* EventDelegate)
			{
				ILeapEventInterface::Execute_RawImageReceived(EventDelegate, PEventImage2->Texture(), PEventImage2);
			});
		}
	}
}