Add a toolbar above the on-screen keyboard with extra keys that are missing from iOS keyboard (#576)
* Add required images to assets * Add toolbar above keyboard with more key options * Fix tvOS errors
BIN
Limelight/Images.xcassets/AltIcon.imageset/AltIcon.png
vendored
Normal file
|
After Width: | Height: | Size: 2.4 KiB |
21
Limelight/Images.xcassets/AltIcon.imageset/Contents.json
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"filename" : "AltIcon.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"info" : {
|
||||
"version" : 1,
|
||||
"author" : "xcode"
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
21
Limelight/Images.xcassets/ControlIcon.imageset/Contents.json
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"filename" : "ControlIcon.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
BIN
Limelight/Images.xcassets/ControlIcon.imageset/ControlIcon.png
vendored
Normal file
|
After Width: | Height: | Size: 2.7 KiB |
21
Limelight/Images.xcassets/DeleteIcon.imageset/Contents.json
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"filename" : "DeleteIcon.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
BIN
Limelight/Images.xcassets/DeleteIcon.imageset/DeleteIcon.png
vendored
Normal file
|
After Width: | Height: | Size: 2.6 KiB |
21
Limelight/Images.xcassets/DoneIcon.imageset/Contents.json
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"filename" : "doneIcon.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
BIN
Limelight/Images.xcassets/DoneIcon.imageset/doneIcon.png
vendored
Normal file
|
After Width: | Height: | Size: 405 B |
21
Limelight/Images.xcassets/EscapeIcon.imageset/Contents.json
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"filename" : "EscapeIcon.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
BIN
Limelight/Images.xcassets/EscapeIcon.imageset/EscapeIcon.png
vendored
Normal file
|
After Width: | Height: | Size: 2.8 KiB |
21
Limelight/Images.xcassets/ShiftIcon.imageset/Contents.json
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"filename" : "ShiftIcon.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
BIN
Limelight/Images.xcassets/ShiftIcon.imageset/ShiftIcon.png
vendored
Normal file
|
After Width: | Height: | Size: 719 B |
21
Limelight/Images.xcassets/TabIcon.imageset/Contents.json
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"filename" : "TabIcon.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
BIN
Limelight/Images.xcassets/TabIcon.imageset/TabIcon.png
vendored
Normal file
|
After Width: | Height: | Size: 2.6 KiB |
21
Limelight/Images.xcassets/WindowsIcon.imageset/Contents.json
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"filename" : "WindowsIcon.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
BIN
Limelight/Images.xcassets/WindowsIcon.imageset/WindowsIcon.png
vendored
Normal file
|
After Width: | Height: | Size: 2.5 KiB |
@@ -352,6 +352,23 @@ static const double X1_MOUSE_SPEED_DIVISOR = 2.5;
|
||||
// Prepare the textbox used to capture keyboard events.
|
||||
keyInputField.delegate = self;
|
||||
keyInputField.text = @"0";
|
||||
#if !TARGET_OS_TV
|
||||
// Prepare the toolbar above the keyboard for more options
|
||||
UIToolbar *customToolbarView = [[UIToolbar alloc] initWithFrame:CGRectMake(0, 0, self.bounds.size.width, 44)];
|
||||
|
||||
UIBarButtonItem *doneBarButton = [self createButtonWithImageNamed:@"DoneIcon.png" backgroundColor:[UIColor clearColor] target:self action:@selector(toolbarButtonClicked:) keyCode:@"0x00" isToggleable:NO];
|
||||
UIBarButtonItem *windowsBarButton = [self createButtonWithImageNamed:@"WindowsIcon.png" backgroundColor:[UIColor blackColor] target:self action:@selector(toolbarButtonClicked:) keyCode:@"0x5B" isToggleable:YES];
|
||||
UIBarButtonItem *tabBarButton = [self createButtonWithImageNamed:@"TabIcon.png" backgroundColor:[UIColor blackColor] target:self action:@selector(toolbarButtonClicked:) keyCode:@"0x09" isToggleable:NO];
|
||||
UIBarButtonItem *shiftBarButton = [self createButtonWithImageNamed:@"ShiftIcon.png" backgroundColor:[UIColor blackColor] target:self action:@selector(toolbarButtonClicked:) keyCode:@"0xA0" isToggleable:YES];
|
||||
UIBarButtonItem *escapeBarButton = [self createButtonWithImageNamed:@"EscapeIcon.png" backgroundColor:[UIColor blackColor] target:self action:@selector(toolbarButtonClicked:) keyCode:@"0x1B" isToggleable:NO];
|
||||
UIBarButtonItem *controlBarButton = [self createButtonWithImageNamed:@"ControlIcon.png" backgroundColor:[UIColor blackColor] target:self action:@selector(toolbarButtonClicked:) keyCode:@"0xA2" isToggleable:YES];
|
||||
UIBarButtonItem *altBarButton = [self createButtonWithImageNamed:@"AltIcon.png" backgroundColor:[UIColor blackColor] target:self action:@selector(toolbarButtonClicked:) keyCode:@"0xA4" isToggleable:YES];
|
||||
UIBarButtonItem *deleteBarButton = [self createButtonWithImageNamed:@"DeleteIcon.png" backgroundColor:[UIColor blackColor] target:self action:@selector(toolbarButtonClicked:) keyCode:@"0x2E" isToggleable:NO];
|
||||
UIBarButtonItem *flexibleSpace = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace target:nil action:nil];
|
||||
|
||||
[customToolbarView setItems:[NSArray arrayWithObjects:doneBarButton, windowsBarButton, escapeBarButton, tabBarButton, shiftBarButton, controlBarButton, altBarButton, deleteBarButton, flexibleSpace, nil]];
|
||||
keyInputField.inputAccessoryView = customToolbarView;
|
||||
#endif
|
||||
[keyInputField becomeFirstResponder];
|
||||
[keyInputField addTarget:self action:@selector(onKeyboardPressed:) forControlEvents:UIControlEventEditingChanged];
|
||||
|
||||
@@ -364,6 +381,63 @@ static const double X1_MOUSE_SPEED_DIVISOR = 2.5;
|
||||
}
|
||||
}
|
||||
|
||||
- (UIBarButtonItem *)createButtonWithImageNamed:(NSString *)imageName backgroundColor:(UIColor *)backgroundColor target:(id)target action:(SEL)action keyCode:(NSString *)keyCode isToggleable:(BOOL)isToggleable {
|
||||
UIImage *image = [UIImage imageNamed:imageName];
|
||||
UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];
|
||||
[button setImage:image forState:UIControlStateNormal];
|
||||
button.frame = CGRectMake(0, 0, 30, 30);
|
||||
button.imageView.contentMode = UIViewContentModeScaleAspectFit;
|
||||
button.imageView.backgroundColor = backgroundColor;
|
||||
button.imageView.layer.cornerRadius = 10.0;
|
||||
button.imageEdgeInsets = UIEdgeInsetsMake(6, 6, 6, 6);
|
||||
[button addTarget:target action:action forControlEvents:UIControlEventTouchUpInside];
|
||||
objc_setAssociatedObject(button, "keyCode", keyCode, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
|
||||
objc_setAssociatedObject(button, "isToggleable", @(isToggleable), OBJC_ASSOCIATION_RETAIN_NONATOMIC);
|
||||
objc_setAssociatedObject(button, "isOn", @(NO), OBJC_ASSOCIATION_RETAIN_NONATOMIC);
|
||||
UIBarButtonItem *barButton = [[UIBarButtonItem alloc] initWithCustomView:button];
|
||||
return barButton;
|
||||
}
|
||||
|
||||
- (void)toolbarButtonClicked:(UIButton *)sender {
|
||||
BOOL isToggleable = [objc_getAssociatedObject(sender, "isToggleable") boolValue];
|
||||
BOOL isOn = [objc_getAssociatedObject(sender, "isOn") boolValue];
|
||||
if (isToggleable){
|
||||
isOn = !isOn;
|
||||
// Update the button's appearance based on its new state
|
||||
if (isOn) {
|
||||
sender.imageView.backgroundColor = [UIColor lightGrayColor];
|
||||
} else {
|
||||
sender.imageView.backgroundColor = [UIColor blackColor];
|
||||
}
|
||||
}
|
||||
// Update the new on/off state of the button
|
||||
objc_setAssociatedObject(sender, "isOn", @(isOn), OBJC_ASSOCIATION_RETAIN_NONATOMIC);
|
||||
// Get the keyCode parameter and convert to short for key press event
|
||||
NSString *keyCodeString = objc_getAssociatedObject(sender, "keyCode");
|
||||
unsigned int keyCodeInteger = 0;
|
||||
NSScanner *scanner = [NSScanner scannerWithString:keyCodeString];
|
||||
[scanner scanHexInt:&keyCodeInteger];
|
||||
short keyCodeShort = (short)keyCodeInteger;
|
||||
// Close keyboard if done button clicked
|
||||
if ([keyCodeString isEqual: @"0x00"]){
|
||||
[[UIApplication sharedApplication] sendAction:@selector(resignFirstResponder) to:nil from:nil forEvent:nil];
|
||||
} else {
|
||||
// Send key press event using keyCode parameter, toggle if necessary
|
||||
// FOR SOME REASON CTRL-ALT-DELETE DOESN'T WORK???
|
||||
if (isToggleable){
|
||||
if (isOn){
|
||||
LiSendKeyboardEvent(keyCodeShort, KEY_ACTION_DOWN, 0);
|
||||
} else {
|
||||
LiSendKeyboardEvent(keyCodeShort, KEY_ACTION_UP, 0);
|
||||
}
|
||||
} else {
|
||||
LiSendKeyboardEvent(keyCodeShort, KEY_ACTION_DOWN, 0);
|
||||
usleep(50 * 1000);
|
||||
LiSendKeyboardEvent(keyCodeShort, KEY_ACTION_UP, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (BOOL)handleMouseButtonEvent:(int)buttonAction forTouches:(NSSet *)touches withEvent:(UIEvent *)event {
|
||||
#if !TARGET_OS_TV
|
||||
if (@available(iOS 13.4, *)) {
|
||||
|
||||