Skip to content

Commit

Permalink
Renderer: implemented mouse support
Browse files Browse the repository at this point in the history
  • Loading branch information
osy86 committed Apr 22, 2019
1 parent 93ee5ce commit 2c54a46
Show file tree
Hide file tree
Showing 5 changed files with 94 additions and 41 deletions.
5 changes: 2 additions & 3 deletions CocoaSpice/CSInput.h
Original file line number Diff line number Diff line change
Expand Up @@ -46,15 +46,14 @@ NS_ASSUME_NONNULL_BEGIN
@property (nonatomic, readonly, assign) NSInteger monitorID;
@property (nonatomic, readonly, assign) BOOL serverModeCursor;
@property (nonatomic, assign) BOOL disableInputs;
@property (nonatomic, assign) CGFloat scale;

- (void)sendKey:(SendKeyType)type code:(int)scancode;
- (void)sendPause:(SendKeyType)type;
- (void)releaseKeys;

- (void)sendMouseMotion:(SendButtonType)button x:(CGFloat)x y:(CGFloat)y;
- (void)sendMouseMotion:(SendButtonType)button point:(CGPoint)point;
- (void)sendMouseScroll:(SendScrollType)type button:(SendButtonType)button dy:(CGFloat)dy;
- (void)sendMouseButton:(SendButtonType)button pressed:(BOOL)pressed x:(CGFloat)x y:(CGFloat)y;
- (void)sendMouseButton:(SendButtonType)button pressed:(BOOL)pressed point:(CGPoint)point;
- (void)mouseMode:(BOOL)server;

- (id)initWithSession:(nonnull SpiceSession *)session channelID:(NSInteger)channelID monitorID:(NSInteger)monitorID;
Expand Down
31 changes: 5 additions & 26 deletions CocoaSpice/CSInput.m
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,6 @@ @implementation CSInput {

int _mouse_grab_active;
bool _mouse_have_pointer;
int _mouse_last_x;
int _mouse_last_y;
int _mouse_guest_x;
int _mouse_guest_y;
BOOL _show_cursor;
Expand Down Expand Up @@ -313,26 +311,17 @@ static int cs_button_to_spice(SendButtonType button)
return spice;
}

- (void)sendMouseMotion:(SendButtonType)button x:(CGFloat)x y:(CGFloat)y {
- (void)sendMouseMotion:(SendButtonType)button point:(CGPoint)point {
if (!self->_inputs)
return;
if (self.disableInputs)
return;

x = floor(x * self.scale);
y = floor(y * self.scale);

if (self.serverModeCursor) {
gint dx = self->_mouse_last_x != -1 ? x - self->_mouse_last_x : 0;
gint dy = self->_mouse_last_y != -1 ? y - self->_mouse_last_y : 0;

spice_inputs_channel_motion(self->_inputs, dx, dy,
spice_inputs_channel_motion(self->_inputs, point.x, point.y,
cs_button_mask_to_spice(button));

self->_mouse_last_x = x;
self->_mouse_last_y = y;
} else {
spice_inputs_channel_position(self->_inputs, x, y, (int)self.monitorID,
spice_inputs_channel_position(self->_inputs, point.x, point.y, (int)self.monitorID,
cs_button_mask_to_spice(button));
}
}
Expand Down Expand Up @@ -375,17 +364,15 @@ - (void)sendMouseScroll:(SendScrollType)type button:(SendButtonType)button dy:(C
}
}

- (void)sendMouseButton:(SendButtonType)button pressed:(BOOL)pressed x:(CGFloat)x y:(CGFloat)y {
- (void)sendMouseButton:(SendButtonType)button pressed:(BOOL)pressed point:(CGPoint)point {
DISPLAY_DEBUG(self, "%s %s: button %u", __FUNCTION__,
pressed ? "press" : "release",
(unsigned int)button);

if (self.disableInputs)
return;

x = floor(x * self.scale);
y = floor(y * self.scale);
if ((x < 0 || y < 0) &&
if ((point.x < 0 || point.y < 0) &&
!self.serverModeCursor) {
/* rule out clicks in outside region */
return;
Expand Down Expand Up @@ -415,14 +402,6 @@ - (void)mouseMode:(BOOL)server {

#pragma mark - Initializers

- (id)init {
self = [super init];
if (self) {
self.scale = 1.0f;
}
return self;
}

- (id)initWithSession:(nonnull SpiceSession *)session channelID:(NSInteger)channelID monitorID:(NSInteger)monitorID {
self = [self init];
if (self) {
Expand Down
6 changes: 6 additions & 0 deletions Renderer/UTMRenderer.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ Header for renderer class which performs Metal setup and per frame rendering
@import MetalKit;
@import CoreGraphics;

NS_ASSUME_NONNULL_BEGIN

// Our platform independent renderer class
@interface UTMRenderer : NSObject<MTKViewDelegate>

Expand All @@ -18,4 +20,8 @@ Header for renderer class which performs Metal setup and per frame rendering

- (nonnull instancetype)initWithMetalKitView:(nonnull MTKView *)mtkView;

- (IBAction)keyboardDonePressed:(UIButton *)sender;

@end

NS_ASSUME_NONNULL_END
2 changes: 2 additions & 0 deletions Views/VMDisplayMetalViewController.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ NS_ASSUME_NONNULL_BEGIN
@property (weak, nonatomic) IBOutlet MTKView *mtkView;
@property (weak, nonatomic) IBOutlet VMKeyboardView *keyboardView;
@property (weak, nonatomic) IBOutlet UIView *inputAccessoryView;
@property (strong, nonatomic) UISelectionFeedbackGenerator *clickFeedbackGenerator;
@property (strong, nonatomic) UIImpactFeedbackGenerator *resizeFeedbackGenerator;

- (IBAction)gesturePan:(UIPanGestureRecognizer *)sender;
- (IBAction)gestureTwoPan:(UIPanGestureRecognizer *)sender;
Expand Down
91 changes: 79 additions & 12 deletions Views/VMDisplayMetalViewController.m
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ @interface VMDisplayMetalViewController ()
@implementation VMDisplayMetalViewController {
UTMRenderer *_renderer;
CGPoint _lastTwoPanOrigin;
CGPoint _lastCursor;
}

@synthesize vmScreenshot;
Expand Down Expand Up @@ -86,6 +87,10 @@ - (void)viewDidLoad {
[self.view addGestureRecognizer:tap];
[self.view addGestureRecognizer:twoTap];
[self.view addGestureRecognizer:pinch];

// Feedback generator for clicks
self.clickFeedbackGenerator = [[UISelectionFeedbackGenerator alloc] init];
self.resizeFeedbackGenerator = [[UIImpactFeedbackGenerator alloc] init];
}

- (void)viewWillAppear:(BOOL)animated {
Expand Down Expand Up @@ -135,7 +140,7 @@ - (void)virtualMachine:(UTMVirtualMachine *)vm transitionToState:(UTMVMState)sta
}
}

#pragma mark - Helpers
#pragma mark - Converting view points to VM display points

static CGRect CGRectClipToBounds(CGRect rect1, CGRect rect2) {
if (rect2.origin.x < rect1.origin.x) {
Expand All @@ -151,7 +156,40 @@ static CGRect CGRectClipToBounds(CGRect rect1, CGRect rect2) {
return rect2;
}

- (CGPoint)clipPan:(CGPoint)target {
static CGFloat CGPointToPixel(CGFloat point) {
return point * [UIScreen mainScreen].scale; // FIXME: multiple screens?
}

- (CGPoint)clipCursorToDisplay:(CGPoint)pos {
CGSize screenSize = self.mtkView.drawableSize;
CGSize scaledSize = {
self.vmRendering.displaySize.width * _renderer.viewportScale,
self.vmRendering.displaySize.height * _renderer.viewportScale
};
CGRect drawRect = CGRectMake(
_renderer.viewportOrigin.x + screenSize.width/2 - scaledSize.width/2,
_renderer.viewportOrigin.y + screenSize.height/2 - scaledSize.height/2,
scaledSize.width,
scaledSize.height
);
pos.x -= drawRect.origin.x;
pos.y -= drawRect.origin.y;
if (pos.x < 0) {
pos.x = 0;
} else if (pos.x > scaledSize.width) {
pos.x = scaledSize.width;
}
if (pos.y < 0) {
pos.y = 0;
} else if (pos.y > scaledSize.height) {
pos.y = scaledSize.height;
}
pos.x /= _renderer.viewportScale;
pos.y /= _renderer.viewportScale;
return pos;
}

- (CGPoint)clipDisplayToView:(CGPoint)target {
CGSize screenSize = self.mtkView.drawableSize;
CGSize scaledSize = {
self.vmRendering.displaySize.width * _renderer.viewportScale,
Expand Down Expand Up @@ -180,15 +218,24 @@ - (CGPoint)clipPan:(CGPoint)target {
return CGPointMake(clippedRect.origin.x, clippedRect.origin.y);
}

- (CGPoint)translateToDisplay:(CGPoint)pos {
return pos;
}

#pragma mark - Gestures

- (IBAction)gesturePan:(UIPanGestureRecognizer *)sender {
if (self.vm.primaryInput.serverModeCursor) {

CGPoint translation = [sender translationInView:sender.view];
if (sender.state == UIGestureRecognizerStateBegan) {
_lastCursor = translation;
}
if (sender.state != UIGestureRecognizerStateCancelled) {
CGPoint cursor;
cursor.x = CGPointToPixel(translation.x - _lastCursor.x) / _renderer.viewportScale;
cursor.y = CGPointToPixel(translation.y - _lastCursor.y) / _renderer.viewportScale;
_lastCursor = translation;
[self.vm.primaryInput sendMouseMotion:SEND_BUTTON_NONE point:cursor];
}
if (sender.state == UIGestureRecognizerStateEnded) {
// TODO: decelerate
}
}
}

Expand All @@ -199,21 +246,41 @@ - (IBAction)gestureTwoPan:(UIPanGestureRecognizer *)sender {
if (sender.state != UIGestureRecognizerStateCancelled) {
CGPoint translation = [sender translationInView:sender.view];
CGPoint viewport = _renderer.viewportOrigin;
viewport.x = 2*translation.x + _lastTwoPanOrigin.x;
viewport.y = 2*translation.y + _lastTwoPanOrigin.y;
_renderer.viewportOrigin = [self clipPan:viewport];
viewport.x = CGPointToPixel(translation.x) + _lastTwoPanOrigin.x;
viewport.y = CGPointToPixel(translation.y) + _lastTwoPanOrigin.y;
_renderer.viewportOrigin = [self clipDisplayToView:viewport];
}
if (sender.state == UIGestureRecognizerStateEnded) {
// TODO: decelerate
}
}

- (IBAction)gestureTap:(UITapGestureRecognizer *)sender {

if (sender.state == UIGestureRecognizerStateEnded) {
CGPoint translated = [sender locationInView:sender.view];
translated.x = CGPointToPixel(translated.x);
translated.y = CGPointToPixel(translated.y);
translated = [self clipCursorToDisplay:translated];
if (self.vm.primaryInput.serverModeCursor) {
translated = _lastCursor;
}
[self.vm.primaryInput sendMouseButton:SEND_BUTTON_LEFT pressed:YES point:translated];
[self.clickFeedbackGenerator selectionChanged];
}
}

- (IBAction)gestureTwoTap:(UITapGestureRecognizer *)sender {

if (sender.state == UIGestureRecognizerStateEnded) {
CGPoint translated = [sender locationInView:sender.view];
translated.x = CGPointToPixel(translated.x);
translated.y = CGPointToPixel(translated.y);
translated = [self clipCursorToDisplay:translated];
if (self.vm.primaryInput.serverModeCursor) {
translated = _lastCursor;
}
[self.vm.primaryInput sendMouseButton:SEND_BUTTON_RIGHT pressed:YES point:translated];
[self.clickFeedbackGenerator selectionChanged];
}
}

- (IBAction)gesturePinch:(UIPinchGestureRecognizer *)sender {
Expand Down

0 comments on commit 2c54a46

Please sign in to comment.