diff --git a/Limelight/Input/CommandManager.swift b/Limelight/Input/CommandManager.swift index 9b275c48..5b43e196 100644 --- a/Limelight/Input/CommandManager.swift +++ b/Limelight/Input/CommandManager.swift @@ -57,7 +57,11 @@ import UIKit "M_X1" : BUTTON_X1, "M_X2" : BUTTON_X2] - @objc public static let oscButtonMappings: [String: Int32] = ["OSCA" : A_FLAG, + + @objc public static let oscButtonMappings: [String: Int32] = [ + "YSRT1" : 0, // RT button & RsvPad in GenshinImpact + "YSB1" : B_FLAG, // B button & RsvPad in GenshinImpact + "OSCA" : A_FLAG, "OSCB" : B_FLAG, "OSCX" : X_FLAG, "OSCY" : Y_FLAG, @@ -73,7 +77,7 @@ import UIKit "OSCRIGHT" : RIGHT_FLAG, "OSCL2" : 0, "OSCR2" : 0] - + @objc public static let oscRectangleButtonCmds: [String] = [ "OSCUP", "OSCDOWN", @@ -87,8 +91,14 @@ import UIKit @objc public static let nonVectorStickPads: [String] = ["LSPAD", "RSPAD"] @objc public static let specialOverlayButtonCmds: [String] = ["SETTINGS"] + @objc public static let specialGameWidgets: [String] = ["YSRT1", "YSB1","YSRT2", "YSB2", "YSEM", "YSYM"] + @objc public static let yuanshenRsvButtonCmds: [String] = ["YSRT1", "YSB1"] + @objc public static let yuanshenMouseButtonCmds: [String] = ["YSEM", "YSYM"] + static let keyboardButtonMappings: [String: Int16] = [ // Windows Key Codes + "YSEM": 0x45, // 'E' & mousePad button in GenshinImpact + "YSYM": 0x59, // 'Y' & mousePad button in GenshinImpact "CTRL": 0x11, // VK_CONTROL "SHIFT": 0x10, // VK_SHIFT "ALT": 0x12, // VK_MENU diff --git a/Limelight/Input/CustomOSC/OSCProfilesManager.m b/Limelight/Input/CustomOSC/OSCProfilesManager.m index b0185236..baf353b2 100644 --- a/Limelight/Input/CustomOSC/OSCProfilesManager.m +++ b/Limelight/Input/CustomOSC/OSCProfilesManager.m @@ -293,13 +293,13 @@ static NSMutableSet *OnScreenWidgetViews; for(OnScreenWidgetView* widgetView in OnScreenWidgetViews){ OnScreenButtonState *buttonState = [[OnScreenButtonState alloc] initWithButtonName:widgetView.keyString buttonType:CustomOnScreenWidget andPosition:widgetView.center]; buttonState.alias = widgetView.keyLabel; - buttonState.timestamp = widgetView.timestamp; buttonState.widthFactor = widgetView.widthFactor; buttonState.heightFactor = widgetView.heightFactor; buttonState.backgroundAlpha = widgetView.backgroundAlpha; buttonState.borderWidth = widgetView.borderWidth; buttonState.sensitivityFactor = widgetView.sensitivityFactor; buttonState.stickIndicatorOffset = widgetView.stickIndicatorOffset; + buttonState.widgetShape = widgetView.shape; NSData *buttonStateEncoded = [NSKeyedArchiver archivedDataWithRootObject:buttonState requiringSecureCoding:YES error:nil]; [buttonStatesEncoded addObject: buttonStateEncoded]; diff --git a/Limelight/Input/CustomOSC/OnScreenButtonState.h b/Limelight/Input/CustomOSC/OnScreenButtonState.h index e5a54db1..a1ef911d 100644 --- a/Limelight/Input/CustomOSC/OnScreenButtonState.h +++ b/Limelight/Input/CustomOSC/OnScreenButtonState.h @@ -24,12 +24,12 @@ NS_ASSUME_NONNULL_BEGIN @property CGPoint position; @property (nonatomic, assign) BOOL isHidden; @property (nonatomic, assign) uint8_t buttonType; -@property (nonatomic, assign) NSTimeInterval timestamp; @property (nonatomic, assign) CGFloat widthFactor; // for OnScreenWidgetView @property (nonatomic, assign) CGFloat heightFactor; // for OnScreenWidgetView @property (nonatomic, assign) CGFloat borderWidth; // for OnScreenWidgetView @property (nonatomic, assign) CGFloat sensitivityFactor; // for OnScreenWidgetView @property (nonatomic, assign) CGFloat stickIndicatorOffset; // for OnScreenWidgetView +@property NSString* widgetShape; // for OnScreenWidgetView @property (nonatomic, assign) CGFloat oscLayerSizeFactor; // for OnScreenController CALayer @property (nonatomic, assign) CGFloat backgroundAlpha; // for OnScreenController CALayer diff --git a/Limelight/Input/CustomOSC/OnScreenButtonState.m b/Limelight/Input/CustomOSC/OnScreenButtonState.m index 02da4e98..16a4a81e 100644 --- a/Limelight/Input/CustomOSC/OnScreenButtonState.m +++ b/Limelight/Input/CustomOSC/OnScreenButtonState.m @@ -29,7 +29,6 @@ - (void) encodeWithCoder:(NSCoder*)encoder { [encoder encodeObject:self.name forKey:@"name"]; [encoder encodeObject:self.alias forKey:@"alias"]; - [encoder encodeDouble:self.timestamp forKey:@"timestamp"]; [encoder encodeInt:self.buttonType forKey:@"buttonType"]; [encoder encodeCGPoint:self.position forKey:@"position"]; [encoder encodeBool:self.isHidden forKey:@"isHidden"]; @@ -40,13 +39,13 @@ [encoder encodeFloat:self.oscLayerSizeFactor forKey:@"oscLayerSizeFactor"]; [encoder encodeFloat:self.backgroundAlpha forKey:@"backgroundAlpha"]; [encoder encodeFloat:self.borderWidth forKey:@"borderWidth"]; + [encoder encodeObject:self.widgetShape forKey:@"widgetShape"]; } - (id) initWithCoder:(NSCoder*)decoder { if (self = [super init]) { self.name = [decoder decodeObjectForKey:@"name"]; self.alias = [decoder decodeObjectForKey:@"alias"]; - self.timestamp = [decoder decodeDoubleForKey:@"timestamp"]; self.buttonType = [decoder decodeIntForKey:@"buttonType"]; self.position = [decoder decodeCGPointForKey:@"position"]; self.isHidden = [decoder decodeBoolForKey:@"isHidden"]; @@ -57,6 +56,7 @@ self.oscLayerSizeFactor = [decoder decodeFloatForKey:@"oscLayerSizeFactor"]; self.backgroundAlpha = [decoder decodeFloatForKey:@"backgroundAlpha"]; self.borderWidth = [decoder decodeFloatForKey:@"borderWidth"]; + self.widgetShape = [decoder decodeObjectForKey:@"widgetShape"]; } return self; } diff --git a/Limelight/Input/OnScreenControls.m b/Limelight/Input/OnScreenControls.m index 8853fc43..e0123aec 100644 --- a/Limelight/Input/OnScreenControls.m +++ b/Limelight/Input/OnScreenControls.m @@ -1079,8 +1079,8 @@ static float L3_Y; if (fabsf(yStickVal) < STICK_DEAD_ZONE) yStickVal = 0; [_controllerSupport updateRightStick:_controller x:0x7FFE * xStickVal y:0x7FFE * -yStickVal]; // stick value populated to the controllerSupport here - NSLog(@"rStickValue, x: %f, y: %f", 0x7FFE * xStickVal, 0x7FFE * yStickVal); - NSLog(@"real controlled instance: %@", self); + // NSLog(@"rStickValue, x: %f, y: %f", 0x7FFE * xStickVal, 0x7FFE * yStickVal); + // NSLog(@"real controlled instance: %@", self); updated = true; } else if (touch == _dpadTouch) { diff --git a/Limelight/Input/OnScreenWidgetView.swift b/Limelight/Input/OnScreenWidgetView.swift index 30ef1246..6a4d5b93 100644 --- a/Limelight/Input/OnScreenWidgetView.swift +++ b/Limelight/Input/OnScreenWidgetView.swift @@ -22,7 +22,6 @@ import UIKit @objc static public var editMode: Bool = false @objc public var keyLabel: String @objc public var keyString: String - @objc public var timestamp: TimeInterval @objc public var pressed: Bool @objc public var widthFactor: CGFloat = 1.0 @objc public var heightFactor: CGFloat = 1.0 @@ -30,9 +29,12 @@ import UIKit @objc public var backgroundAlpha: CGFloat = 0.5 @objc public var latestTouchLocation: CGPoint @objc public var selfViewOnTheRight: Bool = false + @objc public var shape: String = "default" + + public let stickMaxOffset: CGFloat = 0x7FFE private let appWindow: UIView - + private var touchLockedForMoveEvent: UITouch private var touchBegan: Bool = false @@ -96,12 +98,12 @@ import UIKit private let buttonDownVisualEffectLayer = CAShapeLayer() private var buttonDownVisualEffectWidth: CGFloat - @objc init(keyString: String, keyLabel: String) { + @objc init(keyString: String, keyLabel: String, shape:String) { self.keyString = keyString self.keyLabel = keyLabel + self.shape = shape self.label = UILabel() // self.originalBackgroundColor = UIColor(white: 0.2, alpha: 0.7) - self.timestamp = 0 self.pressed = false // self.widthFactor = 1.0 // self.heightFactor = 1.0 @@ -213,7 +215,7 @@ import UIKit let realBackgroundAlpha = self.backgroundAlpha - 0.18 // offset to be consistent with legacy onScreen controller layer opacity self.backgroundColor = UIColor(white: 0.2, alpha: realBackgroundAlpha) // offset to be consistent with legacy onScreen controller layer opacity var borderAlpha = realBackgroundAlpha * 1.01 - if CommandManager.touchPadCmds.contains(self.keyString) { + if CommandManager.touchPadCmds.contains(self.keyString){ minimumBorderAlpha = 0.0 } if borderAlpha < minimumBorderAlpha { @@ -229,24 +231,21 @@ import UIKit } private func changeAndActivateContraints(){ - if CommandManager.oscButtonMappings.keys.contains(self.keyString) && !CommandManager.oscRectangleButtonCmds.contains(self.keyString){ // we'll make custom osc buttons round & smaller - + if self.shape == "round"{ // we'll make custom osc buttons round & smaller NSLayoutConstraint.activate([ self.widthAnchor.constraint(equalToConstant: 60 * self.widthFactor), self.heightAnchor.constraint(equalToConstant: 60 * self.heightFactor),]) - - // self.frame = CGRectMake(0, 0, 60*self.widthFactor, 60*self.heightFactor) - } - else if CommandManager.touchPadCmds.contains(self.keyString) { // make touchPads larger + } + if self.shape == "square" { + NSLayoutConstraint.activate([ + self.widthAnchor.constraint(equalToConstant: 70 * self.widthFactor), + self.heightAnchor.constraint(equalToConstant: 65 * self.heightFactor),]) + } + if self.shape == "largeSquare" { // override all shape strings NSLayoutConstraint.activate([ self.widthAnchor.constraint(equalToConstant: 170 * self.widthFactor), self.heightAnchor.constraint(equalToConstant: 150 * self.heightFactor),]) } - else { - NSLayoutConstraint.activate([ - self.widthAnchor.constraint(equalToConstant: 70 * self.widthFactor), - self.heightAnchor.constraint(equalToConstant: 65 * self.heightFactor),]) - } NSLayoutConstraint.activate([ label.leadingAnchor.constraint(equalTo: self.leadingAnchor, constant: 10), // set up label size contrain within UIView @@ -275,14 +274,18 @@ import UIKit self.tweakAlpha() - if CommandManager.oscButtonMappings.keys.contains(self.keyString) && !CommandManager.oscRectangleButtonCmds.contains(self.keyString){ //make oscButtons round and no border - self.layer.cornerRadius = self.frame.width/2 - // self.layer.borderWidth = self.borderWidth - label.minimumScaleFactor = 0.15 // Adjust the scale factor for oscButtons - label.font = UIFont.boldSystemFont(ofSize: 22) + if self.shape == "default" || self.shape.isEmpty { + if CommandManager.oscButtonMappings.keys.contains(self.keyString) && !CommandManager.oscRectangleButtonCmds.contains(self.keyString){ //make oscButtons round + self.shape = "round" + } + else { + self.shape = "square" + } } + if CommandManager.touchPadCmds.contains(self.keyString){ + self.shape = "largeSquare" // override shape from user input if(self.borderWidth < 1) {self.layer.borderWidth = 1} else {self.layer.borderWidth = self.borderWidth} label.text = "" // make touchPad display no text @@ -295,6 +298,17 @@ import UIKit self.layer.borderWidth = 0 } + if self.shape == "round" { + //setup round buttons + self.layer.cornerRadius = self.frame.width/2 + // self.layer.borderWidth = self.borderWidth + label.minimumScaleFactor = 0.15 // Adjust the scale factor for oscButtons + label.font = UIFont.boldSystemFont(ofSize: 22) + } + if self.shape == "square" || self.shape == "largeSquare" { + //just do nothing here + } + // self.layer.shadowColor = UIColor.clear.cgColor // self.layer.shadowRadius = 8 @@ -702,7 +716,7 @@ import UIKit private func setupButtonDownVisualEffectLayer() { self.buttonDownVisualEffectWidth = 8 - if CommandManager.oscButtonMappings.keys.contains(self.keyString) && !CommandManager.oscRectangleButtonCmds.contains(self.keyString){ + if self.shape == "round" { if widthFactor < 1.3 {self.buttonDownVisualEffectWidth = 15.3} // wider visual effect for osc buttons else {self.buttonDownVisualEffectWidth = 9} } @@ -729,9 +743,9 @@ import UIKit //=========================================send on screen controller stick events private func touchInputToStickInput(input: CGFloat) -> CGFloat{ - var target = 0x7FFE * input / stickInputScale - if target > 0x7FFE {target = 0x7FFE} - if target < -0x7FFE {target = -0x7FFE} + var target = stickMaxOffset * input / stickInputScale + if target > stickMaxOffset {target = stickMaxOffset} + if target < -stickMaxOffset {target = -stickMaxOffset} return target } @@ -746,9 +760,11 @@ import UIKit } private func sendRightStickTouchPadEvent(inputX: CGFloat, inputY: CGFloat){ - let targetX = self.touchInputToStickInput(input: inputX) - let targetY = -self.touchInputToStickInput(input: inputY) + var targetX = self.touchInputToStickInput(input: inputX) + var targetY = -self.touchInputToStickInput(input: inputY) // vertical input must be inverted + //targetX = (targetX >= 0 ? 1.0 : -1.0) * 8000.0 + (stickMaxOffset - 8000.0) * (targetX/stickMaxOffset) + //targetX = (targetX >= 0 ? 1.0 : -1.0) * 8000.0 + targetX - 8000.0*targetX/stickMaxOffset self.onScreenControls.sendRightStickTouchPadEvent(targetX, targetY) } @@ -765,14 +781,14 @@ import UIKit if keyString == "OSCL2" { self.onScreenControls.updateLeftTrigger(0xFF) } - if keyString == "OSCR2" {self.onScreenControls.updateRightTrigger(0xFF)} + if keyString == "OSCR2" || keyString == "YSRT1" {self.onScreenControls.updateRightTrigger(0xFF)} } private func sendOscButtonUpEvent(keyString: String){ let buttonFlag = CommandManager.oscButtonMappings[keyString] if buttonFlag != 0 {self.onScreenControls.releaseControllerButton(buttonFlag!)} if keyString == "OSCL2" {self.onScreenControls.updateLeftTrigger(0x00)} - if keyString == "OSCR2" {self.onScreenControls.updateRightTrigger(0x00)} + if keyString == "OSCR2" || keyString == "YSRT1" {self.onScreenControls.updateRightTrigger(0x00)} } //============================================================================== @@ -938,9 +954,7 @@ import UIKit super.touchesMoved(touches, with: event) if !OnScreenWidgetView.editMode { - if CommandManager.touchPadCmds.contains(self.keyString){ - handleTouchPadMoveEvent(touches, with: event) - } + handleTouchPadMoveEvent(touches, with: event) if CommandManager.specialOverlayButtonCmds.contains(self.keyString){ if let touch = touches.first { @@ -989,6 +1003,10 @@ import UIKit self.sendLeftStickTouchPadEvent(inputX: deltaX*1.5167*sensitivityFactor, inputY: deltaY*1.5167*sensitivityFactor) case "RSVPAD": self.sendRightStickTouchPadEvent(inputX: deltaX*1.5167*sensitivityFactor, inputY: deltaY*1.5167*sensitivityFactor); + case "YSRT1": + self.sendRightStickTouchPadEvent(inputX: deltaX*1.5167*sensitivityFactor, inputY: deltaY*1.5167*sensitivityFactor); + case "YSB1": + self.sendRightStickTouchPadEvent(inputX: deltaX*1.5167*sensitivityFactor, inputY: deltaY*1.5167*sensitivityFactor); case "DPAD", "WASDPAD", "ARROWPAD": handleLrudTouchMove() default: @@ -1024,7 +1042,7 @@ import UIKit } // then other types of pads - if !OnScreenWidgetView.editMode && CommandManager.touchPadCmds.contains(self.keyString) { + if !OnScreenWidgetView.editMode && (CommandManager.touchPadCmds.contains(self.keyString) || CommandManager.yuanshenRsvButtonCmds.contains(self.keyString)) { switch self.keyString{ case "LSPAD": self.onScreenControls.clearLeftStickTouchPadFlag() @@ -1036,6 +1054,10 @@ import UIKit self.onScreenControls.clearLeftStickTouchPadFlag() case "RSVPAD": self.onScreenControls.clearRightStickTouchPadFlag() + case "YSRT1": + self.onScreenControls.clearRightStickTouchPadFlag() + case "YSB1": + self.onScreenControls.clearRightStickTouchPadFlag() case "WASDPAD": LiSendKeyboardEvent(CommandManager.keyboardButtonMappings["W"]!,Int8(KEY_ACTION_UP), 0) LiSendKeyboardEvent(CommandManager.keyboardButtonMappings["A"]!,Int8(KEY_ACTION_UP), 0) diff --git a/Limelight/Input/StreamView.m b/Limelight/Input/StreamView.m index 6f912a6b..70d649ab 100644 --- a/Limelight/Input/StreamView.m +++ b/Limelight/Input/StreamView.m @@ -393,7 +393,7 @@ static const double X1_MOUSE_SPEED_DIVISOR = 2.5; for (NSData *buttonStateEncoded in oscProfile.buttonStates) { OnScreenButtonState* buttonState = [NSKeyedUnarchiver unarchivedObjectOfClass:[OnScreenButtonState class] fromData:buttonStateEncoded error:nil]; if(buttonState.buttonType == CustomOnScreenWidget){ - OnScreenWidgetView* widgetView = [[OnScreenWidgetView alloc] initWithKeyString:buttonState.name keyLabel:buttonState.alias]; //reconstruct widgetView + OnScreenWidgetView* widgetView = [[OnScreenWidgetView alloc] initWithKeyString:buttonState.name keyLabel:buttonState.alias shape:buttonState.widgetShape]; //reconstruct widgetView //-------------------------------------------------- onScreenControls.delegate = widgetView; // connecting onScreenControls to OnScreenWidgetView, sending the active instance for touchPad stick control [onScreenControls sendInstance]; diff --git a/Limelight/ViewControllers/CustomOSCViewControl/LayoutOnScreenControlsViewController.m b/Limelight/ViewControllers/CustomOSCViewControl/LayoutOnScreenControlsViewController.m index ef42ba56..b358ae40 100644 --- a/Limelight/ViewControllers/CustomOSCViewControl/LayoutOnScreenControlsViewController.m +++ b/Limelight/ViewControllers/CustomOSCViewControl/LayoutOnScreenControlsViewController.m @@ -86,9 +86,8 @@ for (NSData *buttonStateEncoded in oscProfile.buttonStates) { OnScreenButtonState* buttonState = [NSKeyedUnarchiver unarchivedObjectOfClass:[OnScreenButtonState class] fromData:buttonStateEncoded error:nil]; if(buttonState.buttonType == CustomOnScreenWidget){ - OnScreenWidgetView* widgetView = [[OnScreenWidgetView alloc] initWithKeyString:buttonState.name keyLabel:buttonState.alias]; //reconstruct widgetView + OnScreenWidgetView* widgetView = [[OnScreenWidgetView alloc] initWithKeyString:buttonState.name keyLabel:buttonState.alias shape:buttonState.widgetShape]; //reconstruct widgetView widgetView.translatesAutoresizingMaskIntoConstraints = NO; // weird but this is mandatory, or you will find no key views added to the right place - widgetView.timestamp = buttonState.timestamp; // will be set as key in in the dict. widgetView.widthFactor = buttonState.widthFactor; widgetView.heightFactor = buttonState.heightFactor; widgetView.borderWidth = buttonState.borderWidth; @@ -348,6 +347,12 @@ textField.spellCheckingType = UITextSpellCheckingTypeNo; }]; + [alertController addTextFieldWithConfigurationHandler:^(UITextField *textField) { + textField.placeholder = [LocalizationHelper localizedStringForKey:@"Shape (r - round, s - square)"]; + textField.keyboardType = UIKeyboardTypeASCIICapable; + textField.autocorrectionType = UITextAutocorrectionTypeNo; + textField.spellCheckingType = UITextSpellCheckingTypeNo; + }]; UIAlertAction *cancelAction = [UIAlertAction actionWithTitle:[LocalizationHelper localizedStringForKey:@"Cancel"] style:UIAlertActionStyleCancel @@ -366,6 +371,8 @@ NSString *cmdString = [alertController.textFields[0].text uppercaseString]; // convert to uppercase NSString *keyLabel = alertController.textFields[1].text; + NSString *widgetShape = [alertController.textFields[2].text lowercaseString]; + if([keyLabel isEqualToString:@""]) keyLabel = [[cmdString lowercaseString] capitalizedString]; bool noValidKeyboardString = [CommandManager.shared extractKeyStringsFromComboCommandFrom:cmdString] == nil; // this is a invalid string. bool noValidSuperComboButtonString = [CommandManager.shared extractKeyStringsFromComboKeysFrom:cmdString] == nil; // this is a invalid string. @@ -373,13 +380,17 @@ bool noValidTouchPadString = ![CommandManager.touchPadCmds containsObject:cmdString]; bool noValidOscButtonString = ![CommandManager.oscButtonMappings.allKeys containsObject:cmdString]; bool noValidSpecialButtonString = ![CommandManager.specialOverlayButtonCmds containsObject:cmdString]; + bool noValidSpecialGameWidgetString = ![CommandManager.specialGameWidgets containsObject:cmdString]; - if(noValidKeyboardString && noValidMouseButtonString && noValidTouchPadString && noValidOscButtonString && noValidSpecialButtonString && noValidSuperComboButtonString) return; + if(noValidKeyboardString && noValidMouseButtonString && noValidTouchPadString && noValidOscButtonString && noValidSpecialButtonString && noValidSuperComboButtonString && noValidSpecialGameWidgetString) return; + if([widgetShape isEqualToString:@"r"]) widgetShape = @"round"; + if([widgetShape isEqualToString:@"s"]) widgetShape = @"square"; + if([widgetShape isEqualToString:@""]) widgetShape = @"default"; //saving & present the keyboard button: - OnScreenWidgetView* widgetView = [[OnScreenWidgetView alloc] initWithKeyString:cmdString keyLabel:keyLabel]; + OnScreenWidgetView* widgetView = [[OnScreenWidgetView alloc] initWithKeyString:cmdString keyLabel:keyLabel shape:widgetShape]; widgetView.translatesAutoresizingMaskIntoConstraints = NO; // weird but this is mandatory, or you will find no key views added to the right place - widgetView.timestamp = CACurrentMediaTime(); // will be set as key in in the dict. + [self.OnScreenWidgetViews addObject:widgetView]; // Add the widgetView to the view controller's view [self.view addSubview:widgetView]; @@ -427,8 +438,8 @@ [self.widgetAlphaSlider setValue: self->selectedWidgetView.backgroundAlpha]; [self.widgetBorderWidthSlider setValue:self->selectedWidgetView.borderWidth]; - NSSet *stickAndMouseTouchpads = [NSSet setWithObjects:@"LSPAD", @"RSPAD", @"LSVPAD", @"RSVPAD", @"MOUSEPAD", nil]; - NSSet *nonVectorStickPads = [NSSet setWithObjects:@"LSPAD", @"RSPAD", nil]; + NSSet *stickAndMouseTouchpads = [NSSet setWithObjects:@"YSB1", @"YSRT1", @"LSPAD", @"RSPAD", @"LSVPAD", @"RSVPAD", @"MOUSEPAD", nil]; + NSSet *nonVectorStickPads = [NSSet setWithObjects: @"LSPAD", @"RSPAD", nil]; bool showSensitivityFactorSlider = [stickAndMouseTouchpads containsObject:self->selectedWidgetView.keyString];