Blame client/iOS/Views/TouchPointerView.m

Packit 1fb8d4
/*
Packit Service 5a9772
 RDP Touch Pointer View
Packit Service 5a9772
Packit 1fb8d4
 Copyright 2013 Thincast Technologies GmbH, Author: Martin Fleisz
Packit Service 5a9772
Packit Service 5a9772
 This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
Packit Service 5a9772
 If a copy of the MPL was not distributed with this file, You can obtain one at
Packit Service 5a9772
 http://mozilla.org/MPL/2.0/.
Packit 1fb8d4
 */
Packit 1fb8d4
Packit 1fb8d4
#import "TouchPointerView.h"
Packit 1fb8d4
#import "Utils.h"
Packit 1fb8d4
Packit 1fb8d4
#define RESET_DEFAULT_POINTER_IMAGE_DELAY 0.15
Packit 1fb8d4
Packit Service 5a9772
#define POINTER_ACTION_CURSOR 0
Packit Service 5a9772
#define POINTER_ACTION_CLOSE 3
Packit Service 5a9772
#define POINTER_ACTION_RCLICK 2
Packit Service 5a9772
#define POINTER_ACTION_LCLICK 4
Packit Service 5a9772
#define POINTER_ACTION_MOVE 4
Packit Service 5a9772
#define POINTER_ACTION_SCROLL 5
Packit 1fb8d4
#define POINTER_ACTION_KEYBOARD 7
Packit 1fb8d4
#define POINTER_ACTION_EXTKEYBOARD 8
Packit 1fb8d4
#define POINTER_ACTION_RESET 6
Packit 1fb8d4
Packit 1fb8d4
@interface TouchPointerView (Private)
Packit Service 5a9772
- (void)setCurrentPointerImage:(UIImage *)image;
Packit Service 5a9772
- (void)displayPointerActionImage:(UIImage *)image;
Packit 1fb8d4
- (BOOL)pointInsidePointer:(CGPoint)point;
Packit 1fb8d4
- (BOOL)pointInsidePointerArea:(int)area point:(CGPoint)point;
Packit 1fb8d4
- (CGPoint)getCursorPosition;
Packit 1fb8d4
- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event;
Packit Service 5a9772
- (void)handleSingleTap:(UITapGestureRecognizer *)gesture;
Packit Service 5a9772
- (void)handlerForGesture:(UIGestureRecognizer *)gesture sendClick:(BOOL)sendClick;
Packit 1fb8d4
@end
Packit 1fb8d4
Packit 1fb8d4
@implementation TouchPointerView
Packit 1fb8d4
Packit 1fb8d4
@synthesize delegate = _delegate;
Packit 1fb8d4
Packit 1fb8d4
- (void)awakeFromNib
Packit 1fb8d4
{
Packit Service 5a9772
	[super awakeFromNib];
Packit Service 5a9772
Packit Service 5a9772
	// set content mode when rotating (keep aspect ratio)
Packit Service 5a9772
	[self setContentMode:UIViewContentModeTopLeft];
Packit Service 5a9772
Packit Service 5a9772
	// load touchPointerImage
Packit Service 5a9772
	_default_pointer_img = [[UIImage
Packit Service 5a9772
	    imageWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"touch_pointer_default"
Packit Service 5a9772
	                                                            ofType:@"png"]] retain];
Packit Service 5a9772
	_active_pointer_img = [[UIImage
Packit Service 5a9772
	    imageWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"touch_pointer_active"
Packit Service 5a9772
	                                                            ofType:@"png"]] retain];
Packit Service 5a9772
	_lclick_pointer_img = [[UIImage
Packit Service 5a9772
	    imageWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"touch_pointer_lclick"
Packit Service 5a9772
	                                                            ofType:@"png"]] retain];
Packit Service 5a9772
	_rclick_pointer_img = [[UIImage
Packit Service 5a9772
	    imageWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"touch_pointer_rclick"
Packit Service 5a9772
	                                                            ofType:@"png"]] retain];
Packit Service 5a9772
	_scroll_pointer_img = [[UIImage
Packit Service 5a9772
	    imageWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"touch_pointer_scroll"
Packit Service 5a9772
	                                                            ofType:@"png"]] retain];
Packit Service 5a9772
	_extkeyboard_pointer_img = [[UIImage
Packit Service 5a9772
	    imageWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"touch_pointer_ext_keyboard"
Packit Service 5a9772
	                                                            ofType:@"png"]] retain];
Packit Service 5a9772
	_keyboard_pointer_img = [[UIImage
Packit Service 5a9772
	    imageWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"touch_pointer_keyboard"
Packit Service 5a9772
	                                                            ofType:@"png"]] retain];
Packit Service 5a9772
	_reset_pointer_img = [[UIImage
Packit Service 5a9772
	    imageWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"touch_pointer_reset"
Packit Service 5a9772
	                                                            ofType:@"png"]] retain];
Packit Service 5a9772
	_cur_pointer_img = _default_pointer_img;
Packit Service 5a9772
	_pointer_transformation = CGAffineTransformMake(1, 0, 0, 1, 0, 0);
Packit Service 5a9772
Packit Service 5a9772
	// init flags
Packit Service 5a9772
	_pointer_moving = NO;
Packit Service 5a9772
	_pointer_scrolling = NO;
Packit Service 5a9772
Packit Service 5a9772
	// create areas array
Packit Service 5a9772
	int i, j;
Packit Service 5a9772
	CGFloat area_width = [_cur_pointer_img size].width / 3.0f;
Packit Service 5a9772
	CGFloat area_height = [_cur_pointer_img size].height / 3.0f;
Packit Service 5a9772
	for (i = 0; i < 3; i++)
Packit Service 5a9772
	{
Packit Service 5a9772
		for (j = 0; j < 3; j++)
Packit Service 5a9772
		{
Packit Service 5a9772
			_pointer_areas[j + i * 3] =
Packit Service 5a9772
			    CGRectMake(j * area_width, i * area_height, area_width, area_height);
Packit Service 5a9772
		}
Packit Service 5a9772
	}
Packit Service 5a9772
Packit Service 5a9772
	// init gesture recognizers
Packit Service 5a9772
	UITapGestureRecognizer *singleTapRecognizer =
Packit Service 5a9772
	    [[[UITapGestureRecognizer alloc] initWithTarget:self
Packit Service 5a9772
	                                             action:@selector(handleSingleTap:)] autorelease];
Packit Service 5a9772
	[singleTapRecognizer setNumberOfTouchesRequired:1];
Packit Service 5a9772
	[singleTapRecognizer setNumberOfTapsRequired:1];
Packit Service 5a9772
Packit Service 5a9772
	UILongPressGestureRecognizer *dragDropRecognizer = [[[UILongPressGestureRecognizer alloc]
Packit Service 5a9772
	    initWithTarget:self
Packit Service 5a9772
	            action:@selector(handleDragDrop:)] autorelease];
Packit Service 5a9772
	dragDropRecognizer.minimumPressDuration = 0.4;
Packit Service 5a9772
	//        dragDropRecognizer.allowableMovement = 1000.0;
Packit Service 5a9772
Packit Service 5a9772
	UILongPressGestureRecognizer *pointerMoveScrollRecognizer =
Packit Service 5a9772
	    [[[UILongPressGestureRecognizer alloc] initWithTarget:self
Packit Service 5a9772
	                                                   action:@selector(handlePointerMoveScroll:)]
Packit Service 5a9772
	        autorelease];
Packit Service 5a9772
	pointerMoveScrollRecognizer.minimumPressDuration = 0.15;
Packit Service 5a9772
	pointerMoveScrollRecognizer.allowableMovement = 1000.0;
Packit Service 5a9772
	[pointerMoveScrollRecognizer requireGestureRecognizerToFail:dragDropRecognizer];
Packit Service 5a9772
Packit Service 5a9772
	[self addGestureRecognizer:singleTapRecognizer];
Packit Service 5a9772
	[self addGestureRecognizer:dragDropRecognizer];
Packit Service 5a9772
	[self addGestureRecognizer:pointerMoveScrollRecognizer];
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
- (void)dealloc
Packit 1fb8d4
{
Packit Service 5a9772
	[super dealloc];
Packit Service 5a9772
	[_default_pointer_img autorelease];
Packit Service 5a9772
	[_active_pointer_img autorelease];
Packit Service 5a9772
	[_lclick_pointer_img autorelease];
Packit Service 5a9772
	[_rclick_pointer_img autorelease];
Packit Service 5a9772
	[_scroll_pointer_img autorelease];
Packit Service 5a9772
	[_extkeyboard_pointer_img autorelease];
Packit Service 5a9772
	[_keyboard_pointer_img autorelease];
Packit Service 5a9772
	[_reset_pointer_img autorelease];
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
#pragma mark - Public interface
Packit 1fb8d4
Packit 1fb8d4
// positions the pointer on screen if it got offscreen after an orentation change
Packit Service 5a9772
- (void)ensurePointerIsVisible
Packit 1fb8d4
{
Packit Service 5a9772
	CGRect bounds = [self bounds];
Packit Service 5a9772
	if (_pointer_transformation.tx > (bounds.size.width - _cur_pointer_img.size.width))
Packit Service 5a9772
		_pointer_transformation.tx = bounds.size.width - _cur_pointer_img.size.width;
Packit Service 5a9772
	if (_pointer_transformation.ty > (bounds.size.height - _cur_pointer_img.size.height))
Packit Service 5a9772
		_pointer_transformation.ty = bounds.size.height - _cur_pointer_img.size.height;
Packit Service 5a9772
	[self setNeedsDisplay];
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
// show/hides the touch pointer
Packit Service 5a9772
- (void)setHidden:(BOOL)hidden
Packit Service 5a9772
{
Packit Service 5a9772
	[super setHidden:hidden];
Packit Service 5a9772
Packit Service 5a9772
	// if shown center pointer in view
Packit Service 5a9772
	if (!hidden)
Packit Service 5a9772
	{
Packit Service 5a9772
		_pointer_transformation = CGAffineTransformMakeTranslation(
Packit Service 5a9772
		    ([self bounds].size.width - [_cur_pointer_img size].width) / 2,
Packit Service 5a9772
		    ([self bounds].size.height - [_cur_pointer_img size].height) / 2);
Packit Service 5a9772
		[self setNeedsDisplay];
Packit Service 5a9772
	}
Packit 1fb8d4
}
Packit 1fb8d4
Packit Service 5a9772
- (UIEdgeInsets)getEdgeInsets
Packit 1fb8d4
{
Packit Service 5a9772
	return UIEdgeInsetsMake(0, 0, [_cur_pointer_img size].width, [_cur_pointer_img size].height);
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
- (CGPoint)getPointerPosition
Packit 1fb8d4
{
Packit Service 5a9772
	return CGPointMake(_pointer_transformation.tx, _pointer_transformation.ty);
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
- (int)getPointerWidth
Packit 1fb8d4
{
Packit Service 5a9772
	return [_cur_pointer_img size].width;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
- (int)getPointerHeight
Packit 1fb8d4
{
Packit Service 5a9772
	return [_cur_pointer_img size].height;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
@end
Packit 1fb8d4
Packit 1fb8d4
@implementation TouchPointerView (Private)
Packit 1fb8d4
Packit Service 5a9772
- (void)setCurrentPointerImage:(UIImage *)image
Packit 1fb8d4
{
Packit Service 5a9772
	_cur_pointer_img = image;
Packit Service 5a9772
	[self setNeedsDisplay];
Packit 1fb8d4
}
Packit 1fb8d4
Packit Service 5a9772
- (void)displayPointerActionImage:(UIImage *)image
Packit 1fb8d4
{
Packit Service 5a9772
	[self setCurrentPointerImage:image];
Packit Service 5a9772
	[self performSelector:@selector(setCurrentPointerImage:)
Packit Service 5a9772
	           withObject:_default_pointer_img
Packit Service 5a9772
	           afterDelay:RESET_DEFAULT_POINTER_IMAGE_DELAY];
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
// Only override drawRect: if you perform custom drawing.
Packit 1fb8d4
// An empty implementation adversely affects performance during animation.
Packit 1fb8d4
- (void)drawRect:(CGRect)rect
Packit 1fb8d4
{
Packit Service 5a9772
	// Drawing code
Packit Service 5a9772
	CGContextRef context = UIGraphicsGetCurrentContext();
Packit Service 5a9772
	CGContextSaveGState(context);
Packit Service 5a9772
	CGContextConcatCTM(context, _pointer_transformation);
Packit Service 5a9772
	CGContextDrawImage(
Packit Service 5a9772
	    context, CGRectMake(0, 0, [_cur_pointer_img size].width, [_cur_pointer_img size].height),
Packit Service 5a9772
	    [_cur_pointer_img CGImage]);
Packit Service 5a9772
	CGContextRestoreGState(context);
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
// helper that returns YES if the given point is within the pointer
Packit Service 5a9772
- (BOOL)pointInsidePointer:(CGPoint)point
Packit 1fb8d4
{
Packit Service 5a9772
	CGRect rec = CGRectMake(0, 0, [_cur_pointer_img size].width, [_cur_pointer_img size].height);
Packit Service 5a9772
	return CGRectContainsPoint(CGRectApplyAffineTransform(rec, _pointer_transformation), point);
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
// helper that returns YES if the given point is within the given pointer area
Packit Service 5a9772
- (BOOL)pointInsidePointerArea:(int)area point:(CGPoint)point
Packit 1fb8d4
{
Packit Service 5a9772
	CGRect rec = _pointer_areas[area];
Packit Service 5a9772
	return CGRectContainsPoint(CGRectApplyAffineTransform(rec, _pointer_transformation), point);
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
// returns the position of the cursor
Packit Service 5a9772
- (CGPoint)getCursorPosition
Packit 1fb8d4
{
Packit Service 5a9772
	CGRect transPointerArea =
Packit Service 5a9772
	    CGRectApplyAffineTransform(_pointer_areas[POINTER_ACTION_CURSOR], _pointer_transformation);
Packit Service 5a9772
	return CGPointMake(CGRectGetMidX(transPointerArea), CGRectGetMidY(transPointerArea));
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
// this filters events - if the pointer was clicked the scrollview won't get any events
Packit Service 5a9772
- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event
Packit 1fb8d4
{
Packit Service 5a9772
	return [self pointInsidePointer:point];
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
#pragma mark - Action handlers
Packit 1fb8d4
Packit 1fb8d4
// handles single tap gestures, returns YES if the event was handled by the pointer, NO otherwise
Packit Service 5a9772
- (void)handleSingleTap:(UITapGestureRecognizer *)gesture
Packit 1fb8d4
{
Packit Service 5a9772
	// get touch position within our view
Packit Service 5a9772
	CGPoint touchPos = [gesture locationInView:self];
Packit Service 5a9772
Packit Service 5a9772
	// look if pointer was in one of our action areas
Packit Service 5a9772
	if ([self pointInsidePointerArea:POINTER_ACTION_CLOSE point:touchPos])
Packit Service 5a9772
		[[self delegate] touchPointerClose];
Packit Service 5a9772
	else if ([self pointInsidePointerArea:POINTER_ACTION_LCLICK point:touchPos])
Packit Service 5a9772
	{
Packit Service 5a9772
		[self displayPointerActionImage:_lclick_pointer_img];
Packit Service 5a9772
		[[self delegate] touchPointerLeftClick:[self getCursorPosition] down:YES];
Packit Service 5a9772
		[[self delegate] touchPointerLeftClick:[self getCursorPosition] down:NO];
Packit Service 5a9772
	}
Packit Service 5a9772
	else if ([self pointInsidePointerArea:POINTER_ACTION_RCLICK point:touchPos])
Packit Service 5a9772
	{
Packit Service 5a9772
		[self displayPointerActionImage:_rclick_pointer_img];
Packit Service 5a9772
		[[self delegate] touchPointerRightClick:[self getCursorPosition] down:YES];
Packit Service 5a9772
		[[self delegate] touchPointerRightClick:[self getCursorPosition] down:NO];
Packit Service 5a9772
	}
Packit Service 5a9772
	else if ([self pointInsidePointerArea:POINTER_ACTION_KEYBOARD point:touchPos])
Packit Service 5a9772
	{
Packit Service 5a9772
		[self displayPointerActionImage:_keyboard_pointer_img];
Packit Service 5a9772
		[[self delegate] touchPointerToggleKeyboard];
Packit Service 5a9772
	}
Packit Service 5a9772
	else if ([self pointInsidePointerArea:POINTER_ACTION_EXTKEYBOARD point:touchPos])
Packit Service 5a9772
	{
Packit Service 5a9772
		[self displayPointerActionImage:_extkeyboard_pointer_img];
Packit Service 5a9772
		[[self delegate] touchPointerToggleExtendedKeyboard];
Packit Service 5a9772
	}
Packit Service 5a9772
	else if ([self pointInsidePointerArea:POINTER_ACTION_RESET point:touchPos])
Packit Service 5a9772
	{
Packit Service 5a9772
		[self displayPointerActionImage:_reset_pointer_img];
Packit Service 5a9772
		[[self delegate] touchPointerResetSessionView];
Packit Service 5a9772
	}
Packit 1fb8d4
}
Packit 1fb8d4
Packit Service 5a9772
- (void)handlerForGesture:(UIGestureRecognizer *)gesture sendClick:(BOOL)sendClick
Packit 1fb8d4
{
Packit Service 5a9772
	if ([gesture state] == UIGestureRecognizerStateBegan)
Packit Service 5a9772
	{
Packit Service 5a9772
		CGPoint touchPos = [gesture locationInView:self];
Packit Service 5a9772
		if ([self pointInsidePointerArea:POINTER_ACTION_LCLICK point:touchPos])
Packit Service 5a9772
		{
Packit Service 5a9772
			_prev_touch_location = touchPos;
Packit Service 5a9772
			_pointer_moving = YES;
Packit Service 5a9772
			if (sendClick == YES)
Packit Service 5a9772
			{
Packit Service 5a9772
				[[self delegate] touchPointerLeftClick:[self getCursorPosition] down:YES];
Packit Service 5a9772
				[self setCurrentPointerImage:_active_pointer_img];
Packit Service 5a9772
			}
Packit Service 5a9772
		}
Packit Service 5a9772
		else if ([self pointInsidePointerArea:POINTER_ACTION_SCROLL point:touchPos])
Packit Service 5a9772
		{
Packit Service 5a9772
			[self setCurrentPointerImage:_scroll_pointer_img];
Packit Service 5a9772
			_prev_touch_location = touchPos;
Packit Service 5a9772
			_pointer_scrolling = YES;
Packit Service 5a9772
		}
Packit Service 5a9772
	}
Packit Service 5a9772
	else if ([gesture state] == UIGestureRecognizerStateChanged)
Packit Service 5a9772
	{
Packit Service 5a9772
		if (_pointer_moving)
Packit Service 5a9772
		{
Packit Service 5a9772
			CGPoint touchPos = [gesture locationInView:self];
Packit Service 5a9772
			_pointer_transformation = CGAffineTransformTranslate(
Packit Service 5a9772
			    _pointer_transformation, touchPos.x - _prev_touch_location.x,
Packit Service 5a9772
			    touchPos.y - _prev_touch_location.y);
Packit Service 5a9772
			[[self delegate] touchPointerMove:[self getCursorPosition]];
Packit Service 5a9772
			_prev_touch_location = touchPos;
Packit Service 5a9772
			[self setNeedsDisplay];
Packit Service 5a9772
		}
Packit Service 5a9772
		else if (_pointer_scrolling)
Packit Service 5a9772
		{
Packit Service 5a9772
			CGPoint touchPos = [gesture locationInView:self];
Packit Service 5a9772
			float delta = touchPos.y - _prev_touch_location.y;
Packit Service 5a9772
			if (delta > GetScrollGestureDelta())
Packit Service 5a9772
			{
Packit Service 5a9772
				[[self delegate] touchPointerScrollDown:YES];
Packit Service 5a9772
				_prev_touch_location = touchPos;
Packit Service 5a9772
			}
Packit Service 5a9772
			else if (delta < -GetScrollGestureDelta())
Packit Service 5a9772
			{
Packit Service 5a9772
				[[self delegate] touchPointerScrollDown:NO];
Packit Service 5a9772
				_prev_touch_location = touchPos;
Packit Service 5a9772
			}
Packit Service 5a9772
		}
Packit Service 5a9772
	}
Packit Service 5a9772
	else if ([gesture state] == UIGestureRecognizerStateEnded)
Packit Service 5a9772
	{
Packit Service 5a9772
		if (_pointer_moving)
Packit Service 5a9772
		{
Packit Service 5a9772
			if (sendClick == YES)
Packit Service 5a9772
				[[self delegate] touchPointerLeftClick:[self getCursorPosition] down:NO];
Packit Service 5a9772
			_pointer_moving = NO;
Packit Service 5a9772
			[self setCurrentPointerImage:_default_pointer_img];
Packit Service 5a9772
		}
Packit Service 5a9772
Packit Service 5a9772
		if (_pointer_scrolling)
Packit Service 5a9772
		{
Packit Service 5a9772
			[self setCurrentPointerImage:_default_pointer_img];
Packit Service 5a9772
			_pointer_scrolling = NO;
Packit Service 5a9772
		}
Packit Service 5a9772
	}
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
// handles long press gestures
Packit Service 5a9772
- (void)handleDragDrop:(UILongPressGestureRecognizer *)gesture
Packit 1fb8d4
{
Packit Service 5a9772
	[self handlerForGesture:gesture sendClick:YES];
Packit 1fb8d4
}
Packit 1fb8d4
Packit Service 5a9772
- (void)handlePointerMoveScroll:(UILongPressGestureRecognizer *)gesture
Packit 1fb8d4
{
Packit Service 5a9772
	[self handlerForGesture:gesture sendClick:NO];
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
@end