Skip to content

Commit 19145d1

Browse files
authored
Merge pull request #195 from utmapp/feature/touchscreen-input
Support touchscreen input
2 parents 2760f2f + 8fd9396 commit 19145d1

21 files changed

+388
-180
lines changed

CocoaSpice/CSDisplayMetal.m

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,14 @@
2727
(int)display.monitorID, \
2828
## __VA_ARGS__)
2929

30+
@interface CSDisplayMetal ()
31+
32+
@property (nonatomic, readwrite, nullable) SpiceSession *session;
33+
@property (nonatomic, readwrite, assign) NSInteger channelID;
34+
@property (nonatomic, readwrite, assign) NSInteger monitorID;
35+
36+
@end
37+
3038
@implementation CSDisplayMetal {
3139
SpiceDisplayChannel *_display;
3240

@@ -275,9 +283,9 @@ - (id)initWithSession:(nonnull SpiceSession *)session channelID:(NSInteger)chann
275283
GList *list;
276284
GList *it;
277285

278-
_channelID = channelID;
279-
_monitorID = monitorID;
280-
_session = session;
286+
self.channelID = channelID;
287+
self.monitorID = monitorID;
288+
self.session = session;
281289
_sigsconnected = NO;
282290
g_object_ref(session);
283291

@@ -306,10 +314,10 @@ - (void)dealloc {
306314
cs_channel_destroy(self.session, SPICE_CHANNEL(_display), (__bridge void *)self);
307315
}
308316
NSLog(@"%s:%d", __FUNCTION__, __LINE__);
309-
g_signal_handlers_disconnect_by_func(_session, G_CALLBACK(cs_channel_new), GLIB_OBJC_RELEASE(self));
310-
g_signal_handlers_disconnect_by_func(_session, G_CALLBACK(cs_channel_destroy), GLIB_OBJC_RELEASE(self));
311-
g_object_unref(_session);
312-
_session = NULL;
317+
g_signal_handlers_disconnect_by_func(self.session, G_CALLBACK(cs_channel_new), GLIB_OBJC_RELEASE(self));
318+
g_signal_handlers_disconnect_by_func(self.session, G_CALLBACK(cs_channel_destroy), GLIB_OBJC_RELEASE(self));
319+
g_object_unref(self.session);
320+
self.session = NULL;
313321
}
314322

315323
- (void)updateVisibleAreaWithRect:(CGRect)rect {

CocoaSpice/CSInput.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ NS_ASSUME_NONNULL_BEGIN
5050
@property (nonatomic, assign) BOOL disableInputs;
5151
@property (nonatomic, readonly) CGSize cursorSize;
5252
@property (nonatomic, assign) CGSize displaySize;
53+
@property (nonatomic, assign) BOOL inhibitCursor;
5354

5455
- (void)sendKey:(SendKeyType)type code:(int)scancode;
5556
- (void)sendPause:(SendKeyType)type;
@@ -59,6 +60,7 @@ NS_ASSUME_NONNULL_BEGIN
5960
- (void)sendMouseScroll:(SendScrollType)type button:(SendButtonType)button dy:(CGFloat)dy;
6061
- (void)sendMouseButton:(SendButtonType)button pressed:(BOOL)pressed point:(CGPoint)point;
6162
- (void)requestMouseMode:(BOOL)server;
63+
- (void)forceCursorPosition:(CGPoint)pos;
6264

6365
- (id)initWithSession:(nonnull SpiceSession *)session channelID:(NSInteger)channelID monitorID:(NSInteger)monitorID;
6466

CocoaSpice/CSInput.m

Lines changed: 33 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,17 @@
2121
#import <spice/protocol.h>
2222
#import "UTMShaderTypes.h"
2323

24+
@interface CSInput ()
25+
26+
@property (nonatomic, readwrite, nullable) SpiceSession *session;
27+
@property (nonatomic, readwrite, assign) NSInteger channelID;
28+
@property (nonatomic, readwrite, assign) NSInteger monitorID;
29+
@property (nonatomic, readwrite, assign) BOOL serverModeCursor;
30+
@property (nonatomic, readwrite, assign) BOOL hasCursor;
31+
@property (nonatomic, readwrite) CGSize cursorSize;
32+
33+
@end
34+
2435
@implementation CSInput {
2536
SpiceMainChannel *_main;
2637
SpiceCursorChannel *_cursor;
@@ -37,7 +48,6 @@ @implementation CSInput {
3748
id<MTLBuffer> _vertices;
3849
NSUInteger _numVertices;
3950
dispatch_semaphore_t _drawLock;
40-
CGSize _cursorSize;
4151
BOOL _cursorHidden;
4252
}
4353

@@ -51,7 +61,7 @@ static void cs_update_mouse_mode(SpiceChannel *channel, gpointer data)
5161
g_object_get(channel, "mouse-mode", &mouse_mode, NULL);
5262
DISPLAY_DEBUG(self, "mouse mode %u", mouse_mode);
5363

54-
self->_serverModeCursor = (mouse_mode == SPICE_MOUSE_MODE_SERVER);
64+
self.serverModeCursor = (mouse_mode == SPICE_MOUSE_MODE_SERVER);
5565

5666
if (self.serverModeCursor) {
5767
self->_mouse_guest.x = -1;
@@ -83,7 +93,7 @@ static void cs_cursor_set(SpiceCursorChannel *channel,
8393

8494
CGPoint hotspot = CGPointMake(cursor_shape->hot_spot_x, cursor_shape->hot_spot_y);
8595
CGSize newSize = CGSizeMake(cursor_shape->width, cursor_shape->height);
86-
if (!CGSizeEqualToSize(newSize, self->_cursorSize)) {
96+
if (!CGSizeEqualToSize(newSize, self.cursorSize)) {
8797
[self rebuildTexture:newSize center:hotspot];
8898
}
8999
[self drawCursor:cursor_shape->data];
@@ -141,7 +151,7 @@ static void cs_channel_new(SpiceSession *s, SpiceChannel *channel, gpointer data
141151

142152
if (SPICE_IS_CURSOR_CHANNEL(channel)) {
143153
gpointer cursor_shape;
144-
if (chid != self->_channelID)
154+
if (chid != self.channelID)
145155
return;
146156
self->_cursor = SPICE_CURSOR_CHANNEL(channel);
147157
g_signal_connect(channel, "notify::cursor",
@@ -186,7 +196,7 @@ static void cs_channel_destroy(SpiceSession *s, SpiceChannel *channel, gpointer
186196
}
187197

188198
if (SPICE_IS_CURSOR_CHANNEL(channel)) {
189-
if (chid != self->_channelID)
199+
if (chid != self.channelID)
190200
return;
191201
self->_cursor = NULL;
192202
g_signal_handlers_disconnect_by_func(channel, G_CALLBACK(cs_cursor_set), GLIB_OBJC_RELEASE(self));
@@ -393,6 +403,10 @@ - (void)requestMouseMode:(BOOL)server {
393403
}
394404
}
395405

406+
- (void)forceCursorPosition:(CGPoint)pos {
407+
_mouse_guest = pos;
408+
}
409+
396410
#pragma mark - Initializers
397411

398412
- (id)init {
@@ -411,9 +425,9 @@ - (id)initWithSession:(nonnull SpiceSession *)session channelID:(NSInteger)chann
411425
GList *list;
412426
GList *it;
413427

414-
_channelID = channelID;
415-
_monitorID = monitorID;
416-
_session = session;
428+
self.channelID = channelID;
429+
self.monitorID = monitorID;
430+
self.session = session;
417431
g_object_ref(session);
418432

419433
NSLog(@"%s:%d", __FUNCTION__, __LINE__);
@@ -440,15 +454,14 @@ - (void)dealloc {
440454
cs_channel_destroy(self.session, SPICE_CHANNEL(_main), (__bridge void *)self);
441455
}
442456
NSLog(@"%s:%d", __FUNCTION__, __LINE__);
443-
g_signal_handlers_disconnect_by_func(_session, G_CALLBACK(cs_channel_new), GLIB_OBJC_RELEASE(self));
444-
g_signal_handlers_disconnect_by_func(_session, G_CALLBACK(cs_channel_destroy), GLIB_OBJC_RELEASE(self));
445-
g_object_unref(_session);
446-
_session = NULL;
457+
g_signal_handlers_disconnect_by_func(self.session, G_CALLBACK(cs_channel_new), GLIB_OBJC_RELEASE(self));
458+
g_signal_handlers_disconnect_by_func(self.session, G_CALLBACK(cs_channel_destroy), GLIB_OBJC_RELEASE(self));
459+
g_object_unref(self.session);
460+
self.session = NULL;
447461
}
448462

449463
#pragma mark - Drawing Cursor
450464

451-
@synthesize cursorSize = _cursorSize;
452465
@synthesize device = _device;
453466
@synthesize drawLock = _drawLock;
454467
@synthesize texture = _texture;
@@ -491,8 +504,8 @@ - (void)rebuildTexture:(CGSize)size center:(CGPoint)hotspot {
491504

492505
// Calculate the number of vertices by dividing the byte length by the size of each vertex
493506
_numVertices = sizeof(quadVertices) / sizeof(UTMVertex);
494-
_cursorSize = size;
495-
_hasCursor = YES;
507+
self.cursorSize = size;
508+
self.hasCursor = YES;
496509
dispatch_semaphore_signal(_drawLock);
497510
}
498511

@@ -501,27 +514,27 @@ - (void)destroyTexture {
501514
_numVertices = 0;
502515
_vertices = nil;
503516
_texture = nil;
504-
_cursorSize = CGSizeZero;
505-
_hasCursor = NO;
517+
self.cursorSize = CGSizeZero;
518+
self.hasCursor = NO;
506519
dispatch_semaphore_signal(_drawLock);
507520
}
508521

509522
- (void)drawCursor:(const void *)buffer {
510523
const NSInteger pixelSize = 4;
511524
MTLRegion region = {
512525
{ 0, 0 }, // MTLOrigin
513-
{ _cursorSize.width, _cursorSize.height, 1} // MTLSize
526+
{ self.cursorSize.width, self.cursorSize.height, 1} // MTLSize
514527
};
515528
dispatch_semaphore_wait(_drawLock, DISPATCH_TIME_FOREVER);
516529
[_texture replaceRegion:region
517530
mipmapLevel:0
518531
withBytes:buffer
519-
bytesPerRow:_cursorSize.width*pixelSize];
532+
bytesPerRow:self.cursorSize.width*pixelSize];
520533
dispatch_semaphore_signal(_drawLock);
521534
}
522535

523536
- (BOOL)visible {
524-
return self.hasCursor && !_cursorHidden;
537+
return !self.inhibitCursor && self.hasCursor && !_cursorHidden;
525538
}
526539

527540
- (CGPoint)viewportOrigin {

CocoaSpice/CSMain.m

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,12 @@
2020
#import <pthread.h>
2121
#import "gst_ios_init.h"
2222

23+
@interface CSMain ()
24+
25+
@property (nonatomic, readwrite) BOOL running;
26+
27+
@end
28+
2329
@implementation CSMain {
2430
GMainContext *_main_context;
2531
GMainLoop *_main_loop;
@@ -100,15 +106,15 @@ - (void)dealloc {
100106

101107
- (void)spiceSetDebug:(BOOL)enabled {
102108
spice_util_set_debug(enabled);
103-
g_log_set_default_handler(logHandler, NULL);
109+
g_log_set_handler(NULL, G_LOG_LEVEL_MASK, logHandler, NULL);
104110
}
105111

106112
- (BOOL)spiceStart {
107113
if (!self.running) {
108114
if (pthread_create(&_spice_thread, NULL, &spice_main_loop, (__bridge_retained void *)self) != 0) {
109115
return NO;
110116
}
111-
_running = YES;
117+
self.running = YES;
112118
}
113119
return YES;
114120
}
@@ -118,7 +124,7 @@ - (void)spiceStop {
118124
void *status;
119125
g_main_loop_quit(_main_loop);
120126
pthread_join(_spice_thread, &status);
121-
_running = NO;
127+
self.running = NO;
122128
}
123129
}
124130

Configuration/UTMConfiguration.h

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -67,8 +67,7 @@ NS_ASSUME_NONNULL_BEGIN
6767
@property (nonatomic, assign) BOOL displayZoomScale;
6868
@property (nonatomic, assign) BOOL displayZoomLetterBox;
6969

70-
@property (nonatomic, assign) BOOL inputTouchscreenMode;
71-
@property (nonatomic, assign) BOOL inputDirect;
70+
@property (nonatomic, assign) BOOL inputLegacy;
7271

7372
@property (nonatomic, assign) BOOL networkEnabled;
7473
@property (nonatomic, assign) BOOL networkLocalhostOnly;

Configuration/UTMConfiguration.m

Lines changed: 11 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@
4444

4545
const NSString *const kUTMConfigTouchscreenModeKey = @"TouchscreenMode";
4646
const NSString *const kUTMConfigDirectInputKey = @"DirectInput";
47+
const NSString *const kUTMConfigInputLegacyKey = @"InputLegacy";
4748

4849
const NSString *const kUTMConfigNetworkEnabledKey = @"NetworkEnabled";
4950
const NSString *const kUTMConfigLocalhostOnlyKey = @"LocalhostOnly";
@@ -1362,6 +1363,12 @@ - (void)migrateConfigurationIfNecessary {
13621363
[obj removeObjectForKey:kUTMConfigCdromKey];
13631364
}
13641365
}];
1366+
// Migrate input settings
1367+
[_rootDict[kUTMConfigInputKey] removeObjectForKey:kUTMConfigTouchscreenModeKey];
1368+
[_rootDict[kUTMConfigInputKey] removeObjectForKey:kUTMConfigDirectInputKey];
1369+
if (!_rootDict[kUTMConfigInputKey][kUTMConfigInputLegacyKey]) {
1370+
self.inputLegacy = NO;
1371+
}
13651372
}
13661373

13671374
#pragma mark - Initialization
@@ -1563,20 +1570,12 @@ - (BOOL)displayZoomLetterBox {
15631570
return [_rootDict[kUTMConfigDisplayKey][kUTMConfigZoomLetterboxKey] boolValue];
15641571
}
15651572

1566-
- (void)setInputTouchscreenMode:(BOOL)inputTouchscreenMode {
1567-
_rootDict[kUTMConfigInputKey][kUTMConfigTouchscreenModeKey] = @(inputTouchscreenMode);
1568-
}
1569-
1570-
- (BOOL)inputTouchscreenMode {
1571-
return [_rootDict[kUTMConfigInputKey][kUTMConfigTouchscreenModeKey] boolValue];
1572-
}
1573-
1574-
- (void)setInputDirect:(BOOL)inputDirect {
1575-
_rootDict[kUTMConfigInputKey][kUTMConfigDirectInputKey] = @(inputDirect);
1573+
- (void)setInputLegacy:(BOOL)inputDirect {
1574+
_rootDict[kUTMConfigInputKey][kUTMConfigInputLegacyKey] = @(inputDirect);
15761575
}
15771576

1578-
- (BOOL)inputDirect {
1579-
return [_rootDict[kUTMConfigInputKey][kUTMConfigDirectInputKey] boolValue];
1577+
- (BOOL)inputLegacy {
1578+
return [_rootDict[kUTMConfigInputKey][kUTMConfigInputLegacyKey] boolValue];
15801579
}
15811580

15821581
- (void)setNetworkEnabled:(BOOL)networkEnabled {

ConfigurationViews/VMConfigInputViewController.h

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -21,13 +21,10 @@ NS_ASSUME_NONNULL_BEGIN
2121

2222
@interface VMConfigInputViewController : VMConfigViewController
2323

24-
@property (weak, nonatomic) IBOutlet UITableViewCell *pointerStyleTouchscreenCell;
25-
@property (weak, nonatomic) IBOutlet UITableViewCell *pointerStyleTrackpadCell;
26-
@property (weak, nonatomic) IBOutlet UITableViewCell *inputReceiverDirectCell;
27-
@property (weak, nonatomic) IBOutlet UITableViewCell *inputReceiverServerCell;
24+
@property (weak, nonatomic) IBOutlet UITableViewCell *openSettingsCell;
25+
@property (weak, nonatomic) IBOutlet UISwitch *legacyModeSwitch;
2826

29-
@property (nonatomic, assign) BOOL inputTouchscreenMode;
30-
@property (nonatomic, assign) BOOL inputDirect;
27+
- (IBAction)legacyModeChanged:(UISwitch *)sender;
3128

3229
@end
3330

ConfigurationViews/VMConfigInputViewController.m

Lines changed: 11 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -23,63 +23,26 @@ @interface VMConfigInputViewController ()
2323

2424
@implementation VMConfigInputViewController
2525

26-
- (void)viewDidLoad {
27-
[super viewDidLoad];
28-
// FIXME: remove this warning
29-
[self showUnimplementedAlert];
30-
}
31-
3226
- (void)refreshViewFromConfiguration {
3327
[super refreshViewFromConfiguration];
34-
self.inputTouchscreenMode = self.configuration.inputTouchscreenMode;
35-
self.inputDirect = self.configuration.inputDirect;
28+
self.legacyModeSwitch.on = self.configuration.inputLegacy;
3629
}
3730

38-
#pragma mark - Properties
31+
#pragma mark - Table delegate
3932

40-
- (void)setInputTouchscreenMode:(BOOL)inputTouchscreenMode {
41-
_inputTouchscreenMode = inputTouchscreenMode;
42-
self.configuration.inputTouchscreenMode = inputTouchscreenMode;
43-
if (inputTouchscreenMode) {
44-
[self.pointerStyleTouchscreenCell setAccessoryType:UITableViewCellAccessoryCheckmark];
45-
[self.pointerStyleTrackpadCell setAccessoryType:UITableViewCellAccessoryNone];
46-
[self.pointerStyleTouchscreenCell setSelected:NO animated:YES];
47-
} else {
48-
[self.pointerStyleTouchscreenCell setAccessoryType:UITableViewCellAccessoryNone];
49-
[self.pointerStyleTrackpadCell setAccessoryType:UITableViewCellAccessoryCheckmark];
50-
[self.pointerStyleTrackpadCell setSelected:NO animated:YES];
33+
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
34+
if ([tableView cellForRowAtIndexPath:indexPath] == self.openSettingsCell) {
35+
[[UIApplication sharedApplication] openURL:[NSURL URLWithString:UIApplicationOpenSettingsURLString]
36+
options:@{}
37+
completionHandler:nil];
38+
[tableView deselectRowAtIndexPath:indexPath animated:YES];
5139
}
5240
}
5341

54-
- (void)setInputDirect:(BOOL)inputDirect {
55-
_inputDirect = inputDirect;
56-
self.configuration.inputDirect = inputDirect;
57-
if (inputDirect) {
58-
[self.inputReceiverDirectCell setAccessoryType:UITableViewCellAccessoryCheckmark];
59-
[self.inputReceiverServerCell setAccessoryType:UITableViewCellAccessoryNone];
60-
[self.inputReceiverDirectCell setSelected:NO animated:YES];
61-
} else {
62-
[self.inputReceiverDirectCell setAccessoryType:UITableViewCellAccessoryNone];
63-
[self.inputReceiverServerCell setAccessoryType:UITableViewCellAccessoryCheckmark];
64-
[self.inputReceiverServerCell setSelected:NO animated:YES];
65-
}
66-
}
42+
#pragma mark - Event handlers
6743

68-
#pragma mark - Table delegate
69-
70-
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
71-
if ([tableView cellForRowAtIndexPath:indexPath] == self.pointerStyleTouchscreenCell) {
72-
self.inputTouchscreenMode = YES;
73-
}
74-
if ([tableView cellForRowAtIndexPath:indexPath] == self.pointerStyleTrackpadCell) {
75-
self.inputTouchscreenMode = NO;
76-
}
77-
if ([tableView cellForRowAtIndexPath:indexPath] == self.inputReceiverDirectCell) {
78-
self.inputDirect = YES;
79-
}
80-
if ([tableView cellForRowAtIndexPath:indexPath] == self.inputReceiverServerCell) {
81-
self.inputDirect = NO;
82-
}
44+
- (IBAction)legacyModeChanged:(UISwitch *)sender {
45+
self.configuration.inputLegacy = sender.on;
8346
}
8447

8548
@end

0 commit comments

Comments
 (0)