 				image: @touchPointerImage
 				opacity: 0
 	
+	# Event handlers
+
+	keydown: (event) =>
+
+		if event.keyCode is @keyPinchCode	
+			@isPinchKeyDown = true
+			@startPoint = @centerPoint = null
+			@showTouchCursor()
+			@touchPointLayer.midX = @point.x
+			@touchPointLayer.midY = @point.y
+			@wrap(document).addEventListener("keyup", @keyup, true)
+			@wrap(document).addEventListener("mousemove", @mousemove, true)
+			
+		if event.keyCode is @keyPanCode
+			@isPanKeyDown = true
+			cancelEvent(event)
+			
+	keyup: (event) =>
+	
+		if event.keyCode is @keyPinchCode
+			cancelEvent(event)	
+			@isPinchKeyDown = false
+			@hideTouchCursor()
+			
+			@wrap(document).removeEventListener("mousemove", @mousemove, true)
+		
+		if event.keyCode is @keyPanCode
+			cancelEvent(event)
+			if @touchPoint and @point
+				@centerPoint = Utils.pointCenter(@touchPoint, @point)
+				@isPanKeyDown = false
+			
+
+	mousedown: (event) =>
+	
+		cancelEvent(event)
+		
+		@isMouseDown = true
+		@target = event.target
+			
+		@wrap(document).addEventListener("mousemove", @mousemove, true)
+		@wrap(document).addEventListener("mouseup", @mouseup, true)
+
+		if @isPinchKeyDown
+			dispatchTouchEvent("touchstart", @target, event, @touchPointDelta)
+		else
+			dispatchTouchEvent("touchstart", @target, event)
+		
+		@touchPointLayer.image = @touchPointerImageActive
+	
+	mousemove: (event) =>
+		
+		cancelEvent(event)
+
+		@point =
+			x: event.pageX
+			y: event.pageY
+
+		@startPoint ?= @point 
+		@centerPoint ?= @point
+		
+		if @isPinchKeyDown and not @isPanKeyDown
+			if @touchPointerInitialOffset and @centerPoint
+				@touchPoint = Utils.pointAdd(@touchPointerInitialOffset, @pinchPoint(@point, @centerPoint))
+				@touchPointDelta = Utils.pointSubtract(@point, @touchPoint)
+			
+		if @isPinchKeyDown and @isPanKeyDown
+			if @touchPoint and @touchPointDelta
+				@touchPoint = @panPoint(@point, @touchPointDelta)
+
+		if @isPinchKeyDown or @isPanKeyDown
+			if @touchPoint
+				@touchPointLayer.visible = true
+				@touchPointLayer.midX = @touchPoint.x
+				@touchPointLayer.midY = @touchPoint.y
+	
+		if (@isPinchKeyDown or @isPanKeyDown) and @touchPointDelta
+			dispatchTouchEvent("touchmove", @target, event, @touchPointDelta)
+		else
+			dispatchTouchEvent("touchmove", @target, event)
+
+	mouseup: (event) =>
+			
+		cancelEvent(event)
+
+		if @isPinchKeyDown or @isPanKeyDown
+			dispatchTouchEvent("touchend", @target, event, @touchPointDelta)
+		else
+			dispatchTouchEvent("touchend", @target, event)
+
+		@endMultiTouch()
+	
+	mouseout: (event) =>
+
+		fromElement = event.relatedTarget or event.toElement
+
+		if not fromElement or fromElement.nodeName is "HTML"
+			@endMultiTouch()
+
+	# Utilities
+
 	showTouchCursor: ->
 		@touchPointLayer.animateStop()
 		@touchPointLayer.midX = @point.x

				opacity: 0
				scale: 1.2
			time: 0.08
	
	keydown: (event) =>

		if event.keyCode is @keyPinchCode	
			@isPinchKeyDown = true
			@startPoint = @centerPoint = null
			@showTouchCursor()
			@touchPointLayer.midX = @point.x
			@touchPointLayer.midY = @point.y
			@wrap(document).addEventListener("keyup", @keyup, true)
			@wrap(document).addEventListener("mousemove", @mousemove, true)
			
		if event.keyCode is @keyPanCode
			@isPanKeyDown = true
			cancelEvent(event)
			
	keyup: (event) =>
	
		if event.keyCode is @keyPinchCode
			cancelEvent(event)	
			@isPinchKeyDown = false
			@hideTouchCursor()
			
			@wrap(document).removeEventListener("mousemove", @mousemove, true)
		
		if event.keyCode is @keyPanCode
			cancelEvent(event)
			if @touchPoint and @point
				@centerPoint = Utils.pointCenter(@touchPoint, @point)
				@isPanKeyDown = false
			

	mousedown: (event) =>
	
		cancelEvent(event)
		
		@isMouseDown = true
		@target = event.target
			
		@wrap(document).addEventListener("mousemove", @mousemove, true)
		@wrap(document).addEventListener("mouseup", @mouseup, true)

		if @isPinchKeyDown
			dispatchTouchEvent("touchstart", @target, event, @touchPointDelta)
		else
			dispatchTouchEvent("touchstart", @target, event)
		
		@touchPointLayer.image = @touchPointerImageActive

	mousemovePosition: (event) =>
		@point =
			x: event.pageX
			y: event.pageY
	
	mousemove: (event) =>
		
		cancelEvent(event)

		@point =
			x: event.pageX
			y: event.pageY

		@startPoint ?= @point 
		@centerPoint ?= @point
		
		if @isPinchKeyDown and not @isPanKeyDown
			if @touchPointerInitialOffset and @centerPoint
				@touchPoint = Utils.pointAdd(@touchPointerInitialOffset, @pinchPoint(@point, @centerPoint))
				@touchPointDelta = Utils.pointSubtract(@point, @touchPoint)
			
		if @isPinchKeyDown and @isPanKeyDown
			if @touchPoint and @touchPointDelta
				@touchPoint = @panPoint(@point, @touchPointDelta)

		if @isPinchKeyDown or @isPanKeyDown
			if @touchPoint
				@touchPointLayer.visible = true
				@touchPointLayer.midX = @touchPoint.x
				@touchPointLayer.midY = @touchPoint.y
	
		if (@isPinchKeyDown or @isPanKeyDown) and @touchPointDelta
			dispatchTouchEvent("touchmove", @target, event, @touchPointDelta)
		else
			dispatchTouchEvent("touchmove", @target, event)

	mouseup: (event) =>
		
		@isMouseDown = false
		
		cancelEvent(event)
		
		@wrap(document).removeEventListener("mousemove", @mousemove, true)
		@wrap(document).removeEventListener("mouseup", @mouseup, true)

		if @isPinchKeyDown or @isPanKeyDown
			dispatchTouchEvent("touchend", @target, event, @touchPointDelta)
		else
			dispatchTouchEvent("touchend", @target, event)
	
		@touchPointLayer.image = @touchPointerImage
		@hideTouchCursor()
	

		@wrap(document).addEventListener("mousedown", @mousedown, true)
		@wrap(document).addEventListener("mousemove", @mousemovePosition, true)
		@wrap(document).addEventListener("keydown", @keydown, true)
		@wrap(document).addEventListener("mouseout", @mouseout, true)
		
		@isMouseDown = false
		@isPinchKeyDown = false
