123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320 |
- // Copyright 2017 The Chromium Authors. All rights reserved.
- // Use of this source code is governed by a BSD-style license that can be
- // found in the LICENSE file.
- #if !defined(__has_feature) || !__has_feature(objc_arc)
- #error "This file requires ARC support."
- #endif
- #import "remoting/ios/client_gestures.h"
- #import "remoting/ios/session/remoting_client.h"
- #include "remoting/client/gesture_interpreter.h"
- static remoting::GestureInterpreter::GestureState toGestureState(
- UIGestureRecognizerState state) {
- switch (state) {
- case UIGestureRecognizerStateBegan:
- return remoting::GestureInterpreter::GESTURE_BEGAN;
- case UIGestureRecognizerStateChanged:
- return remoting::GestureInterpreter::GESTURE_CHANGED;
- default:
- return remoting::GestureInterpreter::GESTURE_ENDED;
- }
- }
- @interface ClientGestures ()<UIGestureRecognizerDelegate> {
- @private
- UILongPressGestureRecognizer* _longPressRecognizer;
- UIPanGestureRecognizer* _panRecognizer;
- UIPanGestureRecognizer* _flingRecognizer;
- UIPanGestureRecognizer* _scrollRecognizer;
- // TODO(yuweih): Commented out because this makes two-finger gestures not
- // quite responsive. Clean these up if it's really unnecessary.
- // UIPanGestureRecognizer* _threeFingerPanRecognizer;
- UIPinchGestureRecognizer* _pinchRecognizer;
- UITapGestureRecognizer* _singleTapRecognizer;
- UITapGestureRecognizer* _twoFingerTapRecognizer;
- UITapGestureRecognizer* _threeFingerTapRecognizer;
- UITapGestureRecognizer* _fourFingerTapRecognizer;
- __weak UIView* _view;
- base::WeakPtr<remoting::GestureInterpreter> _gestureInterpreter;
- }
- @end
- @implementation ClientGestures
- @synthesize delegate = _delegate;
- - (instancetype)initWithView:(UIView*)view client:(RemotingClient*)client {
- _view = view;
- _gestureInterpreter = client.gestureInterpreter->GetWeakPtr();
- _longPressRecognizer = [[UILongPressGestureRecognizer alloc]
- initWithTarget:self
- action:@selector(longPressGestureTriggered:)];
- _longPressRecognizer.delegate = self;
- [view addGestureRecognizer:_longPressRecognizer];
- _panRecognizer = [[UIPanGestureRecognizer alloc]
- initWithTarget:self
- action:@selector(panGestureTriggered:)];
- _panRecognizer.minimumNumberOfTouches = 1;
- _panRecognizer.maximumNumberOfTouches = 2;
- _panRecognizer.delegate = self;
- [view addGestureRecognizer:_panRecognizer];
- _flingRecognizer = [[UIPanGestureRecognizer alloc]
- initWithTarget:self
- action:@selector(flingGestureTriggered:)];
- _flingRecognizer.minimumNumberOfTouches = 1;
- _flingRecognizer.maximumNumberOfTouches = 1;
- _flingRecognizer.delegate = self;
- [view addGestureRecognizer:_flingRecognizer];
- _scrollRecognizer = [[UIPanGestureRecognizer alloc]
- initWithTarget:self
- action:@selector(scrollGestureTriggered:)];
- _scrollRecognizer.minimumNumberOfTouches = 2;
- _scrollRecognizer.maximumNumberOfTouches = 2;
- _scrollRecognizer.delegate = self;
- [view addGestureRecognizer:_scrollRecognizer];
- // _threeFingerPanRecognizer = [[UIPanGestureRecognizer alloc]
- // initWithTarget:self
- // action:@selector(threeFingerPanGestureTriggered:)];
- // _threeFingerPanRecognizer.minimumNumberOfTouches = 3;
- // _threeFingerPanRecognizer.maximumNumberOfTouches = 3;
- // _threeFingerPanRecognizer.delegate = self;
- // [view addGestureRecognizer:_threeFingerPanRecognizer];
- _pinchRecognizer = [[UIPinchGestureRecognizer alloc]
- initWithTarget:self
- action:@selector(pinchGestureTriggered:)];
- _pinchRecognizer.delegate = self;
- [view addGestureRecognizer:_pinchRecognizer];
- _singleTapRecognizer = [[UITapGestureRecognizer alloc]
- initWithTarget:self
- action:@selector(tapGestureTriggered:)];
- _singleTapRecognizer.delegate = self;
- [view addGestureRecognizer:_singleTapRecognizer];
- _twoFingerTapRecognizer = [[UITapGestureRecognizer alloc]
- initWithTarget:self
- action:@selector(twoFingerTapGestureTriggered:)];
- _twoFingerTapRecognizer.numberOfTouchesRequired = 2;
- _twoFingerTapRecognizer.delegate = self;
- [view addGestureRecognizer:_twoFingerTapRecognizer];
- _threeFingerTapRecognizer = [[UITapGestureRecognizer alloc]
- initWithTarget:self
- action:@selector(threeFingerTapGestureTriggered:)];
- _threeFingerTapRecognizer.numberOfTouchesRequired = 3;
- _threeFingerTapRecognizer.delegate = self;
- [view addGestureRecognizer:_threeFingerTapRecognizer];
- _fourFingerTapRecognizer = [[UITapGestureRecognizer alloc]
- initWithTarget:self
- action:@selector(fourFingerTapGestureTriggered:)];
- _fourFingerTapRecognizer.numberOfTouchesRequired = 4;
- _fourFingerTapRecognizer.delegate = self;
- [view addGestureRecognizer:_fourFingerTapRecognizer];
- [_singleTapRecognizer requireGestureRecognizerToFail:_twoFingerTapRecognizer];
- [_twoFingerTapRecognizer
- requireGestureRecognizerToFail:_threeFingerTapRecognizer];
- [_pinchRecognizer requireGestureRecognizerToFail:_singleTapRecognizer];
- // [_pinchRecognizer
- // requireGestureRecognizerToFail:_threeFingerPanRecognizer];
- [_panRecognizer requireGestureRecognizerToFail:_singleTapRecognizer];
- // [_threeFingerPanRecognizer
- // requireGestureRecognizerToFail:_threeFingerTapRecognizer];
- [_panRecognizer requireGestureRecognizerToFail:_scrollRecognizer];
- return self;
- }
- // Resize the view of the desktop - Zoom in/out. This can occur during a Pan.
- - (IBAction)pinchGestureTriggered:(UIPinchGestureRecognizer*)sender {
- if (!_gestureInterpreter) {
- return;
- }
- CGPoint pivot = [sender locationInView:_view];
- _gestureInterpreter->Zoom(pivot.x, pivot.y, sender.scale,
- toGestureState([sender state]));
- sender.scale = 1.0; // reset scale so next iteration is a relative ratio
- }
- - (IBAction)tapGestureTriggered:(UITapGestureRecognizer*)sender {
- if (!_gestureInterpreter) {
- return;
- }
- CGPoint touchPoint = [sender locationInView:_view];
- _gestureInterpreter->Tap(touchPoint.x, touchPoint.y);
- }
- // Change position of the viewport. This can occur during a pinch or long press.
- - (IBAction)panGestureTriggered:(UIPanGestureRecognizer*)sender {
- if (!_gestureInterpreter) {
- return;
- }
- if ([sender state] == UIGestureRecognizerStateChanged) {
- CGPoint translation = [sender translationInView:_view];
- _gestureInterpreter->Pan(translation.x, translation.y);
- // Reset translation so next iteration is relative
- [sender setTranslation:CGPointZero inView:_view];
- }
- }
- // Do fling on the viewport. This will happen at the end of the one-finger
- // panning.
- - (IBAction)flingGestureTriggered:(UIPanGestureRecognizer*)sender {
- if (!_gestureInterpreter) {
- return;
- }
- if ([sender state] == UIGestureRecognizerStateEnded) {
- CGPoint velocity = [sender velocityInView:_view];
- if (velocity.x != 0 || velocity.y != 0) {
- _gestureInterpreter->OneFingerFling(velocity.x, velocity.y);
- }
- }
- }
- // Handles the two finger scrolling gesture.
- - (IBAction)scrollGestureTriggered:(UIPanGestureRecognizer*)sender {
- if (!_gestureInterpreter) {
- return;
- }
- if ([sender state] == UIGestureRecognizerStateEnded) {
- CGPoint velocity = [sender velocityInView:_view];
- _gestureInterpreter->ScrollWithVelocity(velocity.x, velocity.y);
- return;
- }
- CGPoint scrollPoint = [sender locationInView:_view];
- CGPoint translation = [sender translationInView:_view];
- _gestureInterpreter->Scroll(scrollPoint.x, scrollPoint.y, translation.x,
- translation.y);
- // Reset translation so next iteration is relative
- [sender setTranslation:CGPointZero inView:_view];
- }
- // Click-Drag mouse operation. This can occur during a Pan.
- - (IBAction)longPressGestureTriggered:(UILongPressGestureRecognizer*)sender {
- if (!_gestureInterpreter) {
- return;
- }
- CGPoint touchPoint = [sender locationInView:_view];
- _gestureInterpreter->Drag(touchPoint.x, touchPoint.y,
- toGestureState([sender state]));
- }
- - (IBAction)twoFingerTapGestureTriggered:(UITapGestureRecognizer*)sender {
- if (!_gestureInterpreter) {
- return;
- }
- CGPoint touchPoint = [sender locationInView:_view];
- _gestureInterpreter->TwoFingerTap(touchPoint.x, touchPoint.y);
- }
- - (IBAction)threeFingerTapGestureTriggered:(UITapGestureRecognizer*)sender {
- if (!_gestureInterpreter) {
- return;
- }
- CGPoint touchPoint = [sender locationInView:_view];
- _gestureInterpreter->ThreeFingerTap(touchPoint.x, touchPoint.y);
- }
- - (IBAction)threeFingerPanGestureTriggered:(UIPanGestureRecognizer*)sender {
- if (!_gestureInterpreter) {
- return;
- }
- if ([sender state] != UIGestureRecognizerStateEnded) {
- return;
- }
- CGPoint translation = [sender translationInView:_view];
- if (translation.y > 0) {
- // Swiped down - hide keyboard (for now)
- [_delegate keyboardShouldHide];
- } else if (translation.y < 0) {
- // Swiped up - show keyboard
- [_delegate keyboardShouldShow];
- }
- }
- // To trigger the menu.
- - (IBAction)fourFingerTapGestureTriggered:
- (UILongPressGestureRecognizer*)sender {
- if (!_gestureInterpreter) {
- return;
- }
- [_delegate menuShouldShow];
- }
- #pragma mark - UIGestureRecognizerDelegate
- // Allow panning and zooming to occur simultaneously.
- // Allow panning and long press to occur simultaneously.
- // Pinch requires 2 touches, and long press requires a single touch, so they are
- // mutually exclusive regardless of if panning is the initiating gesture.
- // Pinch and Scroll are both two-finger gestures. They are mutually exclusive
- // and whatever comes first should disable the other gesture recognizer.
- - (BOOL)gestureRecognizer:(UIGestureRecognizer*)gestureRecognizer
- shouldRecognizeSimultaneouslyWithGestureRecognizer:
- (UIGestureRecognizer*)otherGestureRecognizer {
- if (gestureRecognizer == _pinchRecognizer ||
- (gestureRecognizer == _panRecognizer)) {
- if (otherGestureRecognizer == _pinchRecognizer ||
- otherGestureRecognizer == _panRecognizer) {
- return YES;
- }
- }
- if (gestureRecognizer == _flingRecognizer ||
- (gestureRecognizer == _panRecognizer)) {
- if (otherGestureRecognizer == _flingRecognizer ||
- otherGestureRecognizer == _panRecognizer) {
- return YES;
- }
- }
- if (gestureRecognizer == _longPressRecognizer ||
- gestureRecognizer == _panRecognizer) {
- if (otherGestureRecognizer == _longPressRecognizer ||
- otherGestureRecognizer == _panRecognizer) {
- return YES;
- }
- }
- if (gestureRecognizer == _twoFingerTapRecognizer &&
- otherGestureRecognizer == _longPressRecognizer) {
- return YES;
- }
- // TODO(nicholss): If we return NO here, it dismisses the other recognizers.
- // As we add more types of recognizers, they need to be accounted for in the
- // above logic.
- return NO;
- }
- @end
|