11#import <QuartzCore/QuartzCore.h> 
   12#import "RDPSessionViewController.h" 
   13#import "RDPKeyboard.h" 
   15#import "Toast+UIView.h" 
   16#import "ConnectionParams.h" 
   17#import "CredentialsInputController.h" 
   18#import "VerifyCertificateController.h" 
   19#import "BlockAlertView.h" 
   21#define TOOLBAR_HEIGHT 30 
   23#define AUTOSCROLLDISTANCE 20 
   24#define AUTOSCROLLTIMEOUT 0.05 
   26@interface RDPSessionViewController (Private)
 
   27- (void)showSessionToolbar:(BOOL)show;
 
   28- (UIToolbar *)keyboardToolbar;
 
   29- (void)initGestureRecognizers;
 
   30- (void)suspendSession;
 
   31- (NSDictionary *)eventDescriptorForMouseEvent:(
int)event position:(CGPoint)position;
 
   32- (void)handleMouseMoveForPosition:(CGPoint)position;
 
   37#pragma mark class methods 
   39- (id)initWithNibName:(NSString *)nibNameOrNil
 
   40               bundle:(NSBundle *)nibBundleOrNil
 
   43  self = [
super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
 
   46    _session = [session retain];
 
   47    [_session setDelegate:self];
 
   48    _session_initilized = NO;
 
   50    _mouse_move_events_skipped = 0;
 
   51    _mouse_move_event_timer = nil;
 
   53    _advanced_keyboard_view = nil;
 
   54    _advanced_keyboard_visible = NO;
 
   55    _requesting_advanced_keyboard = NO;
 
   56    _keyboard_last_height = 0;
 
   58    _session_toolbar_visible = NO;
 
   60    _toggle_mouse_button = NO;
 
   62    _autoscroll_with_touchpointer =
 
   63        [[NSUserDefaults standardUserDefaults] boolForKey:@"ui.auto_scroll_touchpointer"];
 
   64    _is_autoscrolling = NO;
 
   66    [UIView setAnimationDelegate:self];
 
   67    [UIView setAnimationDidStopSelector:@selector(animationStopped:finished:context:)];
 
   80  _keyboard_visible = NO;
 
   83  _keyboard_toolbar = [[
self keyboardToolbar] retain];
 
   84  [_dummy_textfield setInputAccessoryView:_keyboard_toolbar];
 
   87  [
self initGestureRecognizers];
 
   91      setFrame:CGRectMake(0.0, -TOOLBAR_HEIGHT, [[
self view] bounds].size.width, TOOLBAR_HEIGHT)];
 
  100- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
 
  105- (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation
 
  107  if (![_touchpointer_view isHidden])
 
  108    [_touchpointer_view ensurePointerIsVisible];
 
  111- (void)didReceiveMemoryWarning
 
  114  [
super didReceiveMemoryWarning];
 
  121  [
super viewDidUnload];
 
  126- (void)viewWillAppear:(BOOL)animated
 
  128  [
super viewWillAppear:animated];
 
  131  if ([[NSUserDefaults standardUserDefaults] boolForKey:
@"ui.hide_status_bar"])
 
  134      [[UIApplication sharedApplication] setStatusBarHidden:YES
 
  135                                              withAnimation:UIStatusBarAnimationSlide];
 
  137      [[UIApplication sharedApplication] setStatusBarHidden:YES
 
  138                                              withAnimation:UIStatusBarAnimationNone];
 
  140  [[
self navigationController] setNavigationBarHidden:YES animated:animated];
 
  143  if ([_session isSuspended])
 
  144    [
self sessionBitmapContextWillChange:_session];
 
  147  [[
RDPKeyboard getSharedRDPKeyboard] initWithSession:_session delegate:self];
 
  150- (void)viewDidAppear:(BOOL)animated
 
  152  [
super viewDidAppear:animated];
 
  154  if (!_session_initilized)
 
  156    if ([_session isSuspended])
 
  159      [
self sessionBitmapContextDidChange:_session];
 
  160      [_session_view setNeedsDisplay];
 
  165    _session_initilized = YES;
 
  169- (void)viewWillDisappear:(BOOL)animated
 
  171  [
super viewWillDisappear:animated];
 
  175    [[UIApplication sharedApplication] setStatusBarHidden:NO
 
  176                                            withAnimation:UIStatusBarAnimationSlide];
 
  178    [[UIApplication sharedApplication] setStatusBarHidden:NO
 
  179                                            withAnimation:UIStatusBarAnimationNone];
 
  180  [[
self navigationController] setNavigationBarHidden:NO animated:animated];
 
  186  [
self showSessionToolbar:NO];
 
  187  [_dummy_textfield resignFirstResponder];
 
  193  [[NSNotificationCenter defaultCenter] removeObserver:self];
 
  196  [_session setDelegate:nil];
 
  198  [_advanced_keyboard_view release];
 
  199  [_keyboard_toolbar release];
 
  205#pragma mark ScrollView delegate methods 
  207- (UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView
 
  209  return _session_view;
 
  212- (void)scrollViewDidEndZooming:(UIScrollView *)scrollView
 
  213                       withView:(UIView *)view
 
  216  NSLog(
@"New zoom scale: %f", scale);
 
  217  [_session_view setNeedsDisplay];
 
  221#pragma mark TextField delegate methods 
  222- (BOOL)textFieldShouldBeginEditing:(UITextField *)textField
 
  224  _keyboard_visible = YES;
 
  225  _advanced_keyboard_visible = NO;
 
  229- (BOOL)textFieldShouldEndEditing:(UITextField *)textField
 
  231  _keyboard_visible = NO;
 
  232  _advanced_keyboard_visible = NO;
 
  236- (BOOL)textField:(UITextField *)textField
 
  237    shouldChangeCharactersInRange:(NSRange)range
 
  238                replacementString:(NSString *)string
 
  240  if ([
string length] > 0)
 
  242    for (
int i = 0; i < [string length]; i++)
 
  244      unichar curChar = [string characterAtIndex:i];
 
  248        [[
RDPKeyboard getSharedRDPKeyboard] sendEnterKeyStroke];
 
  250        [[
RDPKeyboard getSharedRDPKeyboard] sendUnicode:curChar];
 
  255    [[
RDPKeyboard getSharedRDPKeyboard] sendBackspaceKeyStroke];
 
  262#pragma mark AdvancedKeyboardDelegate functions 
  263- (void)advancedKeyPressedVKey:(
int)key
 
  265  [[
RDPKeyboard getSharedRDPKeyboard] sendVirtualKeyCode:key];
 
  268- (void)advancedKeyPressedUnicode:(
int)key
 
  270  [[
RDPKeyboard getSharedRDPKeyboard] sendUnicode:key];
 
  273#pragma mark - RDP keyboard handler 
  275- (void)modifiersChangedForKeyboard:(
RDPKeyboard *)keyboard
 
  277  UIBarButtonItem *curItem;
 
  284    curItem = (UIBarButtonItem *)[[_keyboard_toolbar items] objectAtIndex:objectIdx];
 
  285    [curItem setStyle:[keyboard shiftPressed] ? UIBarButtonItemStyleDone
 
  286                                              : UIBarButtonItemStyleBordered];
 
  291  curItem = (UIBarButtonItem *)[[_keyboard_toolbar items] objectAtIndex:objectIdx];
 
  293      setStyle:[keyboard ctrlPressed] ? UIBarButtonItemStyleDone : UIBarButtonItemStyleBordered];
 
  297  curItem = (UIBarButtonItem *)[[_keyboard_toolbar items] objectAtIndex:objectIdx];
 
  299      setStyle:[keyboard winPressed] ? UIBarButtonItemStyleDone : UIBarButtonItemStyleBordered];
 
  303  curItem = (UIBarButtonItem *)[[_keyboard_toolbar items] objectAtIndex:objectIdx];
 
  305      setStyle:[keyboard altPressed] ? UIBarButtonItemStyleDone : UIBarButtonItemStyleBordered];
 
  309#pragma mark RDPSessionDelegate functions 
  311- (void)session:(
RDPSession *)session didFailToConnect:(
int)reason
 
  314  [_connecting_indicator_view stopAnimating];
 
  315  [_connecting_view removeFromSuperview];
 
  316  [_connecting_view autorelease];
 
  319  [[
self navigationController] popViewControllerAnimated:YES];
 
  322- (void)sessionWillConnect:(
RDPSession *)session
 
  325  [[NSBundle mainBundle] loadNibNamed:@"RDPConnectingView" owner:self options:nil];
 
  328  [_lbl_connecting setText:NSLocalizedString(@"Connecting", @"Connecting progress view - label")];
 
  329  [_cancel_connect_button setTitle:NSLocalizedString(@"Cancel", @"Cancel Button")
 
  330                          forState:UIControlStateNormal];
 
  333  [_connecting_view setCenter:[[
self view] center]];
 
  334  [[_connecting_view layer] setCornerRadius:10];
 
  337  [[
self view] addSubview:_connecting_view];
 
  338  [_connecting_indicator_view startAnimating];
 
  341- (void)sessionDidConnect:(
RDPSession *)session
 
  344  [[NSNotificationCenter defaultCenter] addObserver:self
 
  345                                           selector:@selector(keyboardWillShow:)
 
  346                                               name:UIKeyboardWillShowNotification
 
  348  [[NSNotificationCenter defaultCenter] addObserver:self
 
  349                                           selector:@selector(keyboardDidShow:)
 
  350                                               name:UIKeyboardDidShowNotification
 
  352  [[NSNotificationCenter defaultCenter] addObserver:self
 
  353                                           selector:@selector(keyboardWillHide:)
 
  354                                               name:UIKeyboardWillHideNotification
 
  356  [[NSNotificationCenter defaultCenter] addObserver:self
 
  357                                           selector:@selector(keyboardDidHide:)
 
  358                                               name:UIKeyboardDidHideNotification
 
  362  [_connecting_indicator_view stopAnimating];
 
  363  [_connecting_view removeFromSuperview];
 
  364  [_connecting_view autorelease];
 
  370  rdpSettings *sess_params = [session getSessionParams];
 
  371  if (([orig_params intForKey:
@"width"] != sess_params->DesktopWidth &&
 
  372       [orig_params intForKey:
@"width"] != (sess_params->DesktopWidth + 1)) ||
 
  373      [orig_params intForKey:
@"height"] != sess_params->DesktopHeight ||
 
  374      [orig_params intForKey:
@"colors"] != sess_params->ColorDepth)
 
  378        [NSString stringWithFormat:NSLocalizedString(
 
  379                                       @"The server changed the screen settings to %dx%dx%d",
 
  380                                       @"Screen settings not supported message with width, "
 
  381                                       @"height and colors parameter"),
 
  382                                   sess_params->DesktopWidth, sess_params->DesktopHeight,
 
  383                                   sess_params->ColorDepth];
 
  384    [[
self view] makeToast:message duration:ToastDurationNormal position:@"bottom"];
 
  388- (void)sessionWillDisconnect:(
RDPSession *)session
 
  392- (void)sessionDidDisconnect:(
RDPSession *)session
 
  395  [[
self navigationController] popViewControllerAnimated:YES];
 
  398- (void)sessionBitmapContextWillChange:(
RDPSession *)session
 
  401  rdpSettings *sess_params = [session getSessionParams];
 
  402  CGRect view_rect = CGRectMake(0, 0, sess_params->DesktopWidth, sess_params->DesktopHeight);
 
  405  [_session_scrollview setZoomScale:1.0];
 
  406  [_session_scrollview setContentSize:view_rect.size];
 
  409  [_session_view setFrame:view_rect];
 
  413      setToolbarVisible:![[NSUserDefaults standardUserDefaults] boolForKey:@"ui.hide_tool_bar"]];
 
  414  [
self showSessionToolbar:[_session toolbarVisible]];
 
  417- (void)sessionBitmapContextDidChange:(
RDPSession *)session
 
  420  [_session_view setSession:session];
 
  423  [_session_view setNeedsDisplay];
 
  426- (void)session:(
RDPSession *)session needsRedrawInRect:(CGRect)rect
 
  428  [_session_view setNeedsDisplayInRect:rect];
 
  431- (void)session:(
RDPSession *)session requestsAuthenticationWithParams:(NSMutableDictionary *)params
 
  437                                                    params:params] autorelease];
 
  438  [
self presentModalViewController:view_controller animated:YES];
 
  441- (void)session:(
RDPSession *)session verifyCertificateWithParams:(NSMutableDictionary *)params
 
  447                                                     params:params] autorelease];
 
  448  [
self presentModalViewController:view_controller animated:YES];
 
  451- (CGSize)sizeForFitScreenForSession:(
RDPSession *)session
 
  454    return [
self view].bounds.size;
 
  458    CGSize size = [
self view].bounds.size;
 
  459    CGFloat maxSize = (size.width > size.height) ? size.width : size.height;
 
  460    return CGSizeMake(maxSize * 1.6f, maxSize);
 
  464#pragma mark - Keyboard Toolbar Handlers 
  466- (void)showAdvancedKeyboardAnimated
 
  469  CGRect rect = [[_keyboard_toolbar superview] bounds];
 
  470  rect.origin.y = [_keyboard_toolbar bounds].size.height;
 
  471  rect.size.height -= rect.origin.y;
 
  475      initWithFrame:CGRectMake(rect.origin.x, [[_keyboard_toolbar superview] bounds].size.height,
 
  476                               rect.size.width, rect.size.height)
 
  478  [[_keyboard_toolbar superview] addSubview:_advanced_keyboard_view];
 
  481  [[_keyboard_toolbar superview] setAutoresizesSubviews:YES];
 
  484  [UIView beginAnimations:nil context:NULL];
 
  485  [_advanced_keyboard_view setFrame:rect];
 
  486  [UIView commitAnimations];
 
  489- (IBAction)toggleKeyboardWhenOtherVisible:(
id)sender
 
  491  if (_advanced_keyboard_visible == NO)
 
  493    [
self showAdvancedKeyboardAnimated];
 
  498    [UIView beginAnimations:@"hide_advanced_keyboard_view" context:NULL];
 
  499    CGRect rect = [_advanced_keyboard_view frame];
 
  500    rect.origin.y = [[_keyboard_toolbar superview] bounds].size.height;
 
  501    [_advanced_keyboard_view setFrame:rect];
 
  502    [UIView commitAnimations];
 
  508  _advanced_keyboard_visible = !_advanced_keyboard_visible;
 
  511- (IBAction)toggleWinKey:(
id)sender
 
  516- (IBAction)toggleShiftKey:(
id)sender
 
  518  [[
RDPKeyboard getSharedRDPKeyboard] toggleShiftKey];
 
  521- (IBAction)toggleCtrlKey:(
id)sender
 
  523  [[
RDPKeyboard getSharedRDPKeyboard] toggleCtrlKey];
 
  526- (IBAction)toggleAltKey:(
id)sender
 
  531- (IBAction)pressEscKey:(
id)sender
 
  533  [[
RDPKeyboard getSharedRDPKeyboard] sendEscapeKeyStroke];
 
  537#pragma mark event handlers 
  539- (void)animationStopped:(NSString *)animationID
 
  540                finished:(NSNumber *)finished
 
  541                 context:(
void *)context
 
  543  if ([animationID isEqualToString:
@"hide_advanced_keyboard_view"])
 
  546    [_advanced_keyboard_view removeFromSuperview];
 
  547    [_advanced_keyboard_view autorelease];
 
  548    _advanced_keyboard_view = nil;
 
  552- (IBAction)switchSession:(
id)sender
 
  554  [
self suspendSession];
 
  557- (IBAction)toggleKeyboard:(
id)sender
 
  559  if (!_keyboard_visible)
 
  560    [_dummy_textfield becomeFirstResponder];
 
  562    [_dummy_textfield resignFirstResponder];
 
  565- (IBAction)toggleExtKeyboard:(
id)sender
 
  568  if (_keyboard_visible && !_advanced_keyboard_visible)
 
  569    [
self toggleKeyboardWhenOtherVisible:nil];
 
  573    if (_advanced_keyboard_visible == NO)
 
  574      _requesting_advanced_keyboard = YES;
 
  575    [
self toggleKeyboard:nil];
 
  579- (IBAction)toggleTouchPointer:(
id)sender
 
  581  BOOL toggle_visibilty = ![_touchpointer_view isHidden];
 
  582  [_touchpointer_view setHidden:toggle_visibilty];
 
  583  if (toggle_visibilty)
 
  584    [_session_scrollview setContentInset:UIEdgeInsetsZero];
 
  586    [_session_scrollview setContentInset:[_touchpointer_view getEdgeInsets]];
 
  589- (IBAction)disconnectSession:(
id)sender
 
  591  [_session disconnect];
 
  594- (IBAction)cancelButtonPressed:(
id)sender
 
  596  [_session disconnect];
 
  600#pragma mark iOS Keyboard Notification Handlers 
  606  UIInterfaceOrientation ori = [[UIApplication sharedApplication] statusBarOrientation];
 
  607  return (ori == UIInterfaceOrientationLandscapeLeft ||
 
  608          ori == UIInterfaceOrientationLandscapeRight);
 
  611- (void)shiftKeyboard:(NSNotification *)notification
 
  614  CGRect keyboardEndFrame =
 
  615      [[[notification userInfo] objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue];
 
  617  CGFloat previousHeight = _keyboard_last_height;
 
  619  if ([
self isLandscape])
 
  622    _keyboard_last_height = keyboardEndFrame.size.width + keyboardEndFrame.origin.x;
 
  627    CGFloat height = [[UIScreen mainScreen] bounds].size.height;
 
  628    _keyboard_last_height = height - keyboardEndFrame.origin.y;
 
  631  CGFloat shiftHeight = _keyboard_last_height - previousHeight;
 
  633  [UIView beginAnimations:nil context:NULL];
 
  634  [UIView setAnimationCurve:[[[notification userInfo]
 
  635                                objectForKey:UIKeyboardAnimationCurveUserInfoKey] intValue]];
 
  637      setAnimationDuration:[[[notification userInfo]
 
  638                               objectForKey:UIKeyboardAnimationDurationUserInfoKey] doubleValue]];
 
  639  CGRect frame = [_session_scrollview frame];
 
  640  frame.size.height -= shiftHeight;
 
  641  [_session_scrollview setFrame:frame];
 
  642  [_touchpointer_view setFrame:frame];
 
  643  [UIView commitAnimations];
 
  646- (void)keyboardWillShow:(NSNotification *)notification
 
  648  [
self shiftKeyboard:notification];
 
  650  [_touchpointer_view ensurePointerIsVisible];
 
  653- (void)keyboardDidShow:(NSNotification *)notification
 
  655  if (_requesting_advanced_keyboard)
 
  657    [
self showAdvancedKeyboardAnimated];
 
  658    _advanced_keyboard_visible = YES;
 
  659    _requesting_advanced_keyboard = NO;
 
  663- (void)keyboardWillHide:(NSNotification *)notification
 
  666  [
self shiftKeyboard:notification];
 
  669- (void)keyboardDidHide:(NSNotification *)notification
 
  672  if (_advanced_keyboard_visible == YES)
 
  674    _advanced_keyboard_visible = NO;
 
  675    [_advanced_keyboard_view removeFromSuperview];
 
  676    [_advanced_keyboard_view autorelease];
 
  677    _advanced_keyboard_view = nil;
 
  682#pragma mark Gesture handlers 
  684- (void)handleSingleTap:(UITapGestureRecognizer *)gesture
 
  686  CGPoint pos = [gesture locationInView:_session_view];
 
  687  if (_toggle_mouse_button)
 
  690        sendInputEvent:[
self eventDescriptorForMouseEvent:GetRightMouseButtonClickEvent(YES)
 
  693        sendInputEvent:[
self eventDescriptorForMouseEvent:GetRightMouseButtonClickEvent(NO)
 
  699        sendInputEvent:[
self eventDescriptorForMouseEvent:GetLeftMouseButtonClickEvent(YES)
 
  701    [_session sendInputEvent:[
self eventDescriptorForMouseEvent:GetLeftMouseButtonClickEvent(NO)
 
  705  _toggle_mouse_button = NO;
 
  708- (void)handleDoubleTap:(UITapGestureRecognizer *)gesture
 
  710  CGPoint pos = [gesture locationInView:_session_view];
 
  711  [_session sendInputEvent:[
self eventDescriptorForMouseEvent:GetLeftMouseButtonClickEvent(YES)
 
  713  [_session sendInputEvent:[
self eventDescriptorForMouseEvent:GetLeftMouseButtonClickEvent(NO)
 
  715  [_session sendInputEvent:[
self eventDescriptorForMouseEvent:GetLeftMouseButtonClickEvent(YES)
 
  717  [_session sendInputEvent:[
self eventDescriptorForMouseEvent:GetLeftMouseButtonClickEvent(NO)
 
  719  _toggle_mouse_button = NO;
 
  722- (void)handleLongPress:(UILongPressGestureRecognizer *)gesture
 
  724  CGPoint pos = [gesture locationInView:_session_view];
 
  726  if ([gesture state] == UIGestureRecognizerStateBegan)
 
  728        sendInputEvent:[
self eventDescriptorForMouseEvent:GetLeftMouseButtonClickEvent(YES)
 
  730  else if ([gesture state] == UIGestureRecognizerStateChanged)
 
  731    [
self handleMouseMoveForPosition:pos];
 
  732  else if ([gesture state] == UIGestureRecognizerStateEnded)
 
  733    [_session sendInputEvent:[
self eventDescriptorForMouseEvent:GetLeftMouseButtonClickEvent(NO)
 
  737- (void)handleDoubleLongPress:(UILongPressGestureRecognizer *)gesture
 
  741  CGPoint pos = [gesture locationInView:_session_scrollview];
 
  743  if ([gesture state] == UIGestureRecognizerStateBegan)
 
  744    _prev_long_press_position = pos;
 
  745  else if ([gesture state] == UIGestureRecognizerStateChanged)
 
  747    int delta = _prev_long_press_position.y - pos.y;
 
  749    if (delta > GetScrollGestureDelta())
 
  751      [_session sendInputEvent:[
self eventDescriptorForMouseEvent:GetMouseWheelEvent(YES)
 
  753      _prev_long_press_position = pos;
 
  755    else if (delta < -GetScrollGestureDelta())
 
  757      [_session sendInputEvent:[
self eventDescriptorForMouseEvent:GetMouseWheelEvent(NO)
 
  759      _prev_long_press_position = pos;
 
  764- (void)handleSingle2FingersTap:(UITapGestureRecognizer *)gesture
 
  766  _toggle_mouse_button = !_toggle_mouse_button;
 
  769- (void)handleSingle3FingersTap:(UITapGestureRecognizer *)gesture
 
  771  [_session setToolbarVisible:![_session toolbarVisible]];
 
  772  [
self showSessionToolbar:[_session toolbarVisible]];
 
  776#pragma mark Touch Pointer delegates 
  778- (void)touchPointerClose
 
  780  [
self toggleTouchPointer:nil];
 
  784- (void)touchPointerLeftClick:(CGPoint)pos down:(BOOL)down
 
  786  CGPoint session_view_pos = [_touchpointer_view convertPoint:pos toView:_session_view];
 
  787  [_session sendInputEvent:[
self eventDescriptorForMouseEvent:GetLeftMouseButtonClickEvent(down)
 
  788                                                     position:session_view_pos]];
 
  792- (void)touchPointerRightClick:(CGPoint)pos down:(BOOL)down
 
  794  CGPoint session_view_pos = [_touchpointer_view convertPoint:pos toView:_session_view];
 
  795  [_session sendInputEvent:[
self eventDescriptorForMouseEvent:GetRightMouseButtonClickEvent(down)
 
  796                                                     position:session_view_pos]];
 
  799- (void)doAutoScrolling
 
  803  CGPoint curPointerPos = [_touchpointer_view getPointerPosition];
 
  804  CGRect viewBounds = [_touchpointer_view bounds];
 
  805  CGRect scrollBounds = [_session_view bounds];
 
  808  scrollBounds.size.width += [_session_scrollview contentInset].right;
 
  809  scrollBounds.size.height += [_session_scrollview contentInset].bottom;
 
  812  scrollBounds.size.width *= [_session_scrollview zoomScale];
 
  813  scrollBounds.size.height *= [_session_scrollview zoomScale];
 
  815  if (curPointerPos.x > (viewBounds.size.width - [_touchpointer_view getPointerWidth]))
 
  816    scrollX = AUTOSCROLLDISTANCE;
 
  817  else if (curPointerPos.x < 0)
 
  818    scrollX = -AUTOSCROLLDISTANCE;
 
  820  if (curPointerPos.y > (viewBounds.size.height - [_touchpointer_view getPointerHeight]))
 
  821    scrollY = AUTOSCROLLDISTANCE;
 
  822  else if (curPointerPos.y < (_session_toolbar_visible ? TOOLBAR_HEIGHT : 0))
 
  823    scrollY = -AUTOSCROLLDISTANCE;
 
  825  CGPoint newOffset = [_session_scrollview contentOffset];
 
  826  newOffset.x += scrollX;
 
  827  newOffset.y += scrollY;
 
  835  else if (newOffset.x > (scrollBounds.size.width - viewBounds.size.width))
 
  838    newOffset.x = MAX(scrollBounds.size.width - viewBounds.size.width, 0);
 
  845  else if (newOffset.y > (scrollBounds.size.height - viewBounds.size.height))
 
  848    newOffset.y = MAX(scrollBounds.size.height - viewBounds.size.height, 0);
 
  852  [_session_scrollview setContentOffset:newOffset];
 
  855  if (scrollX != 0 || scrollY != 0)
 
  856    [
self performSelector:@selector(doAutoScrolling)
 
  858               afterDelay:AUTOSCROLLTIMEOUT];
 
  860    _is_autoscrolling = NO;
 
  864- (void)touchPointerMove:(CGPoint)pos
 
  866  CGPoint session_view_pos = [_touchpointer_view convertPoint:pos toView:_session_view];
 
  867  [
self handleMouseMoveForPosition:session_view_pos];
 
  869  if (_autoscroll_with_touchpointer && !_is_autoscrolling)
 
  871    _is_autoscrolling = YES;
 
  872    [
self performSelector:@selector(doAutoScrolling)
 
  874               afterDelay:AUTOSCROLLTIMEOUT];
 
  879- (void)touchPointerScrollDown:(BOOL)down
 
  881  [_session sendInputEvent:[
self eventDescriptorForMouseEvent:GetMouseWheelEvent(down)
 
  882                                                     position:CGPointZero]];
 
  886- (void)touchPointerToggleKeyboard
 
  888  if (_advanced_keyboard_visible)
 
  889    [
self toggleKeyboardWhenOtherVisible:nil];
 
  891    [
self toggleKeyboard:nil];
 
  895- (void)touchPointerToggleExtendedKeyboard
 
  897  [
self toggleExtKeyboard:nil];
 
  901- (void)touchPointerResetSessionView
 
  903  [_session_scrollview setZoomScale:1.0 animated:YES];
 
  908@implementation RDPSessionViewController (Private)
 
  911#pragma mark Helper functions 
  913- (void)showSessionToolbar:(BOOL)show
 
  916  if (_session_toolbar_visible == show)
 
  921    [UIView beginAnimations:@"showToolbar" context:nil];
 
  922    [UIView setAnimationDuration:.4];
 
  923    [UIView setAnimationCurve:UIViewAnimationCurveLinear];
 
  925        setFrame:CGRectMake(0.0, 0.0, [[
self view] bounds].size.width, TOOLBAR_HEIGHT)];
 
  926    [UIView commitAnimations];
 
  927    _session_toolbar_visible = YES;
 
  931    [UIView beginAnimations:@"hideToolbar" context:nil];
 
  932    [UIView setAnimationDuration:.4];
 
  933    [UIView setAnimationCurve:UIViewAnimationCurveLinear];
 
  934    [_session_toolbar setFrame:CGRectMake(0.0, -TOOLBAR_HEIGHT, [[
self view] bounds].size.width,
 
  936    [UIView commitAnimations];
 
  937    _session_toolbar_visible = NO;
 
  941- (UIToolbar *)keyboardToolbar
 
  943  UIToolbar *keyboard_toolbar = [[[UIToolbar alloc] initWithFrame:CGRectNull] autorelease];
 
  944  [keyboard_toolbar setBarStyle:UIBarStyleBlackOpaque];
 
  946  UIBarButtonItem *esc_btn =
 
  947      [[[UIBarButtonItem alloc] initWithTitle:@"Esc"
 
  948                                        style:UIBarButtonItemStyleBordered
 
  950                                       action:@selector(pressEscKey:)] autorelease];
 
  952      [UIImage imageWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"toolbar_icon_win"
 
  954  UIBarButtonItem *win_btn =
 
  955      [[[UIBarButtonItem alloc] initWithImage:win_icon
 
  956                                        style:UIBarButtonItemStyleBordered
 
  958                                       action:@selector(toggleWinKey:)] autorelease];
 
  959  UIBarButtonItem *ctrl_btn =
 
  960      [[[UIBarButtonItem alloc] initWithTitle:@"Ctrl"
 
  961                                        style:UIBarButtonItemStyleBordered
 
  963                                       action:@selector(toggleCtrlKey:)] autorelease];
 
  964  UIBarButtonItem *alt_btn =
 
  965      [[[UIBarButtonItem alloc] initWithTitle:@"Alt"
 
  966                                        style:UIBarButtonItemStyleBordered
 
  968                                       action:@selector(toggleAltKey:)] autorelease];
 
  969  UIBarButtonItem *ext_btn = [[[UIBarButtonItem alloc]
 
  971              style:UIBarButtonItemStyleBordered
 
  973             action:@selector(toggleKeyboardWhenOtherVisible:)] autorelease];
 
  974  UIBarButtonItem *done_btn = [[[UIBarButtonItem alloc]
 
  975      initWithBarButtonSystemItem:UIBarButtonSystemItemDone
 
  977                           action:@selector(toggleKeyboard:)] autorelease];
 
  978  UIBarButtonItem *flex_spacer =
 
  979      [[[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace
 
  981                                                     action:nil] autorelease];
 
  987    UIBarButtonItem *shift_btn =
 
  988        [[[UIBarButtonItem alloc] initWithTitle:@"Shift"
 
  989                                          style:UIBarButtonItemStyleBordered
 
  991                                         action:@selector(toggleShiftKey:)] autorelease];
 
  992    items = [NSArray arrayWithObjects:esc_btn, flex_spacer, shift_btn, flex_spacer, ctrl_btn,
 
  993                                      flex_spacer, win_btn, flex_spacer, alt_btn, flex_spacer,
 
  994                                      ext_btn, flex_spacer, done_btn, nil];
 
  998    items = [NSArray arrayWithObjects:esc_btn, flex_spacer, ctrl_btn, flex_spacer, win_btn,
 
  999                                      flex_spacer, alt_btn, flex_spacer, ext_btn, flex_spacer,
 
 1003  [keyboard_toolbar setItems:items];
 
 1004  [keyboard_toolbar sizeToFit];
 
 1005  return keyboard_toolbar;
 
 1008- (void)initGestureRecognizers
 
 1011  UITapGestureRecognizer *doubleTapRecognizer =
 
 1012      [[[UITapGestureRecognizer alloc] initWithTarget:self
 
 1013                                               action:@selector(handleDoubleTap:)] autorelease];
 
 1014  [doubleTapRecognizer setNumberOfTouchesRequired:1];
 
 1015  [doubleTapRecognizer setNumberOfTapsRequired:2];
 
 1017  UITapGestureRecognizer *singleTapRecognizer =
 
 1018      [[[UITapGestureRecognizer alloc] initWithTarget:self
 
 1019                                               action:@selector(handleSingleTap:)] autorelease];
 
 1020  [singleTapRecognizer requireGestureRecognizerToFail:doubleTapRecognizer];
 
 1021  [singleTapRecognizer setNumberOfTouchesRequired:1];
 
 1022  [singleTapRecognizer setNumberOfTapsRequired:1];
 
 1025  UITapGestureRecognizer *single2FingersTapRecognizer = [[[UITapGestureRecognizer alloc]
 
 1027              action:@selector(handleSingle2FingersTap:)] autorelease];
 
 1028  [single2FingersTapRecognizer setNumberOfTouchesRequired:2];
 
 1029  [single2FingersTapRecognizer setNumberOfTapsRequired:1];
 
 1032  UILongPressGestureRecognizer *longPressRecognizer = [[[UILongPressGestureRecognizer alloc]
 
 1034              action:@selector(handleLongPress:)] autorelease];
 
 1035  [longPressRecognizer setMinimumPressDuration:0.5];
 
 1038  UILongPressGestureRecognizer *doubleLongPressRecognizer = [[[UILongPressGestureRecognizer alloc]
 
 1040              action:@selector(handleDoubleLongPress:)] autorelease];
 
 1041  [doubleLongPressRecognizer setNumberOfTouchesRequired:2];
 
 1042  [doubleLongPressRecognizer setMinimumPressDuration:0.5];
 
 1045  UITapGestureRecognizer *single3FingersTapRecognizer = [[[UITapGestureRecognizer alloc]
 
 1047              action:@selector(handleSingle3FingersTap:)] autorelease];
 
 1048  [single3FingersTapRecognizer setNumberOfTapsRequired:1];
 
 1049  [single3FingersTapRecognizer setNumberOfTouchesRequired:3];
 
 1052  [_session_scrollview addGestureRecognizer:singleTapRecognizer];
 
 1053  [_session_scrollview addGestureRecognizer:doubleTapRecognizer];
 
 1054  [_session_scrollview addGestureRecognizer:single2FingersTapRecognizer];
 
 1055  [_session_scrollview addGestureRecognizer:longPressRecognizer];
 
 1056  [_session_scrollview addGestureRecognizer:doubleLongPressRecognizer];
 
 1057  [_session_scrollview addGestureRecognizer:single3FingersTapRecognizer];
 
 1060- (void)suspendSession
 
 1066  [[
self navigationController] popViewControllerAnimated:YES];
 
 1069- (NSDictionary *)eventDescriptorForMouseEvent:(
int)event position:(CGPoint)position
 
 1071  return [NSDictionary
 
 1072      dictionaryWithObjectsAndKeys:@"mouse", @"type", [NSNumber numberWithUnsignedShort:event],
 
 1074                                   [NSNumber numberWithUnsignedShort:lrintf(position.x)],
 
 1076                                   [NSNumber numberWithUnsignedShort:lrintf(position.y)],
 
 1080- (void)sendDelayedMouseEventWithTimer:(NSTimer *)timer
 
 1082  _mouse_move_event_timer = nil;
 
 1083  NSDictionary *
event = [timer userInfo];
 
 1084  [_session sendInputEvent:event];
 
 1085  [timer autorelease];
 
 1088- (void)handleMouseMoveForPosition:(CGPoint)position
 
 1090  NSDictionary *
event = [
self eventDescriptorForMouseEvent:PTR_FLAGS_MOVE position:position];
 
 1093  [_mouse_move_event_timer invalidate];
 
 1094  _mouse_move_events_skipped++;
 
 1096  if (_mouse_move_events_skipped >= 5)
 
 1098    [_session sendInputEvent:event];
 
 1099    _mouse_move_events_skipped = 0;
 
 1103    [_mouse_move_event_timer autorelease];
 
 1104    _mouse_move_event_timer =
 
 1105        [[NSTimer scheduledTimerWithTimeInterval:0.05
 
 1107                                        selector:@selector(sendDelayedMouseEventWithTimer:)
 
 1109                                         repeats:NO] retain];