mirror of
				https://github.com/SoPat712/YTLitePlus.git
				synced 2025-10-31 04:44:14 -04:00 
			
		
		
		
	added files via upload
This commit is contained in:
		
							
								
								
									
										326
									
								
								Tweaks/FLEX/Utility/Keyboard/FLEXKeyboardShortcutManager.m
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										326
									
								
								Tweaks/FLEX/Utility/Keyboard/FLEXKeyboardShortcutManager.m
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,326 @@ | ||||
| // | ||||
| //  FLEXKeyboardShortcutManager.m | ||||
| //  FLEX | ||||
| // | ||||
| //  Created by Ryan Olson on 9/19/15. | ||||
| //  Copyright © 2020 FLEX Team. All rights reserved. | ||||
| // | ||||
|  | ||||
| #import "FLEXKeyboardShortcutManager.h" | ||||
| #import "FLEXUtility.h" | ||||
| #import <objc/runtime.h> | ||||
| #import <objc/message.h> | ||||
|  | ||||
| #if TARGET_OS_SIMULATOR | ||||
|  | ||||
| @interface UIEvent (UIPhysicalKeyboardEvent) | ||||
|  | ||||
| @property (nonatomic) NSString *_modifiedInput; | ||||
| @property (nonatomic) NSString *_unmodifiedInput; | ||||
| @property (nonatomic) UIKeyModifierFlags _modifierFlags; | ||||
| @property (nonatomic) BOOL _isKeyDown; | ||||
| @property (nonatomic) long _keyCode; | ||||
|  | ||||
| @end | ||||
|  | ||||
| @interface FLEXKeyInput : NSObject <NSCopying> | ||||
|  | ||||
| @property (nonatomic, copy, readonly) NSString *key; | ||||
| @property (nonatomic, readonly) UIKeyModifierFlags flags; | ||||
| @property (nonatomic, copy, readonly) NSString *helpDescription; | ||||
|  | ||||
| @end | ||||
|  | ||||
| @implementation FLEXKeyInput | ||||
|  | ||||
| - (BOOL)isEqual:(id)object { | ||||
|     BOOL isEqual = NO; | ||||
|     if ([object isKindOfClass:[FLEXKeyInput class]]) { | ||||
|         FLEXKeyInput *keyCommand = (FLEXKeyInput *)object; | ||||
|         BOOL equalKeys = self.key == keyCommand.key || [self.key isEqual:keyCommand.key]; | ||||
|         BOOL equalFlags = self.flags == keyCommand.flags; | ||||
|         isEqual = equalKeys && equalFlags; | ||||
|     } | ||||
|     return isEqual; | ||||
| } | ||||
|  | ||||
| - (NSUInteger)hash { | ||||
|     return self.key.hash ^ self.flags; | ||||
| } | ||||
|  | ||||
| - (id)copyWithZone:(NSZone *)zone { | ||||
|     return [[self class] keyInputForKey:self.key flags:self.flags helpDescription:self.helpDescription]; | ||||
| } | ||||
|  | ||||
| - (NSString *)description { | ||||
|     NSDictionary<NSString *, NSString *> *keyMappings = @{ | ||||
|         UIKeyInputUpArrow : @"↑", | ||||
|         UIKeyInputDownArrow : @"↓", | ||||
|         UIKeyInputLeftArrow : @"←", | ||||
|         UIKeyInputRightArrow : @"→", | ||||
|         UIKeyInputEscape : @"␛", | ||||
|         @" " : @"␠" | ||||
|     }; | ||||
|      | ||||
|     NSString *prettyKey = nil; | ||||
|     if (self.key && keyMappings[self.key]) { | ||||
|         prettyKey = keyMappings[self.key]; | ||||
|     } else { | ||||
|         prettyKey = [self.key uppercaseString]; | ||||
|     } | ||||
|      | ||||
|     NSString *prettyFlags = @""; | ||||
|     if (self.flags & UIKeyModifierControl) { | ||||
|         prettyFlags = [prettyFlags stringByAppendingString:@"⌃"]; | ||||
|     } | ||||
|     if (self.flags & UIKeyModifierAlternate) { | ||||
|         prettyFlags = [prettyFlags stringByAppendingString:@"⌥"]; | ||||
|     } | ||||
|     if (self.flags & UIKeyModifierShift) { | ||||
|         prettyFlags = [prettyFlags stringByAppendingString:@"⇧"]; | ||||
|     } | ||||
|     if (self.flags & UIKeyModifierCommand) { | ||||
|         prettyFlags = [prettyFlags stringByAppendingString:@"⌘"]; | ||||
|     } | ||||
|      | ||||
|     // Fudging to get easy columns with tabs | ||||
|     if (prettyFlags.length < 2) { | ||||
|         prettyKey = [prettyKey stringByAppendingString:@"\t"]; | ||||
|     } | ||||
|      | ||||
|     return [NSString stringWithFormat:@"%@%@\t%@", prettyFlags, prettyKey, self.helpDescription]; | ||||
| } | ||||
|  | ||||
| + (instancetype)keyInputForKey:(NSString *)key flags:(UIKeyModifierFlags)flags { | ||||
|     return [self keyInputForKey:key flags:flags helpDescription:nil]; | ||||
| } | ||||
|  | ||||
| + (instancetype)keyInputForKey:(NSString *)key | ||||
|                          flags:(UIKeyModifierFlags)flags | ||||
|                helpDescription:(NSString *)helpDescription { | ||||
|     FLEXKeyInput *keyInput = [self new]; | ||||
|     if (keyInput) { | ||||
|         keyInput->_key = key; | ||||
|         keyInput->_flags = flags; | ||||
|         keyInput->_helpDescription = helpDescription; | ||||
|     } | ||||
|     return keyInput; | ||||
| } | ||||
|  | ||||
| @end | ||||
|  | ||||
| @interface FLEXKeyboardShortcutManager () | ||||
|  | ||||
| @property (nonatomic) NSMutableDictionary<FLEXKeyInput *, dispatch_block_t> *actionsForKeyInputs; | ||||
|  | ||||
| @property (nonatomic, getter=isPressingShift) BOOL pressingShift; | ||||
| @property (nonatomic, getter=isPressingCommand) BOOL pressingCommand; | ||||
| @property (nonatomic, getter=isPressingControl) BOOL pressingControl; | ||||
|  | ||||
| @end | ||||
|  | ||||
| @implementation FLEXKeyboardShortcutManager | ||||
|  | ||||
| + (instancetype)sharedManager { | ||||
|     static FLEXKeyboardShortcutManager *sharedManager = nil; | ||||
|     static dispatch_once_t onceToken; | ||||
|     dispatch_once(&onceToken, ^{ | ||||
|         sharedManager = [self new]; | ||||
|     }); | ||||
|     return sharedManager; | ||||
| } | ||||
|  | ||||
| + (void)load { | ||||
|     SEL originalKeyEventSelector = NSSelectorFromString(@"handleKeyUIEvent:"); | ||||
|     SEL swizzledKeyEventSelector = [FLEXUtility swizzledSelectorForSelector:originalKeyEventSelector]; | ||||
|      | ||||
|     void (^handleKeyUIEventSwizzleBlock)(UIApplication *, UIEvent *) = ^(UIApplication *slf, UIEvent *event) { | ||||
|          | ||||
|         [[[self class] sharedManager] handleKeyboardEvent:event]; | ||||
|          | ||||
|         ((void(*)(id, SEL, id))objc_msgSend)(slf, swizzledKeyEventSelector, event); | ||||
|     }; | ||||
|      | ||||
|     [FLEXUtility replaceImplementationOfKnownSelector:originalKeyEventSelector | ||||
|         onClass:[UIApplication class] | ||||
|         withBlock:handleKeyUIEventSwizzleBlock | ||||
|         swizzledSelector:swizzledKeyEventSelector | ||||
|     ]; | ||||
|      | ||||
|     if ([[UITouch class] instancesRespondToSelector:@selector(maximumPossibleForce)]) { | ||||
|         SEL originalSendEventSelector = NSSelectorFromString(@"sendEvent:"); | ||||
|         SEL swizzledSendEventSelector = [FLEXUtility swizzledSelectorForSelector:originalSendEventSelector]; | ||||
|          | ||||
|         void (^sendEventSwizzleBlock)(UIApplication *, UIEvent *) = ^(UIApplication *slf, UIEvent *event) { | ||||
|             if (event.type == UIEventTypeTouches) { | ||||
|                 FLEXKeyboardShortcutManager *keyboardManager = FLEXKeyboardShortcutManager.sharedManager; | ||||
|                 NSInteger pressureLevel = 0; | ||||
|                 if (keyboardManager.isPressingShift) { | ||||
|                     pressureLevel++; | ||||
|                 } | ||||
|                 if (keyboardManager.isPressingCommand) { | ||||
|                     pressureLevel++; | ||||
|                 } | ||||
|                 if (keyboardManager.isPressingControl) { | ||||
|                     pressureLevel++; | ||||
|                 } | ||||
|                 if (pressureLevel > 0) { | ||||
|                     if (@available(iOS 9.0, *)) { | ||||
|                         for (UITouch *touch in [event allTouches]) { | ||||
|                             double adjustedPressureLevel = pressureLevel * 20 * touch.maximumPossibleForce; | ||||
|                             [touch setValue:@(adjustedPressureLevel) forKey:@"_pressure"]; | ||||
|                         } | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
|              | ||||
|             ((void(*)(id, SEL, id))objc_msgSend)(slf, swizzledSendEventSelector, event); | ||||
|         }; | ||||
|          | ||||
|         [FLEXUtility replaceImplementationOfKnownSelector:originalSendEventSelector | ||||
|             onClass:[UIApplication class] | ||||
|             withBlock:sendEventSwizzleBlock | ||||
|             swizzledSelector:swizzledSendEventSelector | ||||
|         ]; | ||||
|          | ||||
|         SEL originalSupportsTouchPressureSelector = NSSelectorFromString(@"_supportsForceTouch"); | ||||
|         SEL swizzledSupportsTouchPressureSelector = [FLEXUtility swizzledSelectorForSelector:originalSupportsTouchPressureSelector]; | ||||
|          | ||||
|         BOOL (^supportsTouchPressureSwizzleBlock)(UIDevice *) = ^BOOL(UIDevice *slf) { | ||||
|             return YES; | ||||
|         }; | ||||
|          | ||||
|         [FLEXUtility replaceImplementationOfKnownSelector:originalSupportsTouchPressureSelector | ||||
|             onClass:[UIDevice class] | ||||
|             withBlock:supportsTouchPressureSwizzleBlock | ||||
|             swizzledSelector:swizzledSupportsTouchPressureSelector | ||||
|         ]; | ||||
|     } | ||||
| } | ||||
|  | ||||
| - (instancetype)init { | ||||
|     self = [super init]; | ||||
|      | ||||
|     if (self) { | ||||
|         _actionsForKeyInputs = [NSMutableDictionary new]; | ||||
|         _enabled = YES; | ||||
|     } | ||||
|      | ||||
|     return self; | ||||
| } | ||||
|  | ||||
| - (void)registerSimulatorShortcutWithKey:(NSString *)key | ||||
|                                modifiers:(UIKeyModifierFlags)modifiers | ||||
|                                   action:(dispatch_block_t)action | ||||
|                              description:(NSString *)description | ||||
|                            allowOverride:(BOOL)allowOverride { | ||||
|     FLEXKeyInput *keyInput = [FLEXKeyInput keyInputForKey:key flags:modifiers helpDescription:description]; | ||||
|     if (!allowOverride && self.actionsForKeyInputs[keyInput] != nil) { | ||||
|         return; | ||||
|     } else { | ||||
|         [self.actionsForKeyInputs setObject:action forKey:keyInput]; | ||||
|     } | ||||
| } | ||||
|  | ||||
| static const long kFLEXControlKeyCode = 0xe0; | ||||
| static const long kFLEXShiftKeyCode = 0xe1; | ||||
| static const long kFLEXCommandKeyCode = 0xe3; | ||||
|  | ||||
| - (void)handleKeyboardEvent:(UIEvent *)event { | ||||
|     if (!self.enabled) { | ||||
|         return; | ||||
|     } | ||||
|      | ||||
|     NSString *modifiedInput = nil; | ||||
|     NSString *unmodifiedInput = nil; | ||||
|     UIKeyModifierFlags flags = 0; | ||||
|     BOOL isKeyDown = NO; | ||||
|      | ||||
|     if ([event respondsToSelector:@selector(_modifiedInput)]) { | ||||
|         modifiedInput = [event _modifiedInput]; | ||||
|     } | ||||
|      | ||||
|     if ([event respondsToSelector:@selector(_unmodifiedInput)]) { | ||||
|         unmodifiedInput = [event _unmodifiedInput]; | ||||
|     } | ||||
|      | ||||
|     if ([event respondsToSelector:@selector(_modifierFlags)]) { | ||||
|         flags = [event _modifierFlags]; | ||||
|     } | ||||
|      | ||||
|     if ([event respondsToSelector:@selector(_isKeyDown)]) { | ||||
|         isKeyDown = [event _isKeyDown]; | ||||
|     } | ||||
|      | ||||
|     BOOL interactionEnabled = !UIApplication.sharedApplication.isIgnoringInteractionEvents; | ||||
|     BOOL hasFirstResponder = NO; | ||||
|     if (isKeyDown && modifiedInput.length > 0 && interactionEnabled) { | ||||
|         UIResponder *firstResponder = nil; | ||||
|         for (UIWindow *window in FLEXUtility.allWindows) { | ||||
|             firstResponder = [window valueForKey:@"firstResponder"]; | ||||
|             if (firstResponder) { | ||||
|                 hasFirstResponder = YES; | ||||
|                 break; | ||||
|             } | ||||
|         } | ||||
|          | ||||
|         // Ignore key commands (except escape) when there's an active responder | ||||
|         if (firstResponder) { | ||||
|             if ([unmodifiedInput isEqual:UIKeyInputEscape]) { | ||||
|                 [firstResponder resignFirstResponder]; | ||||
|             } | ||||
|         } else { | ||||
|             FLEXKeyInput *exactMatch = [FLEXKeyInput keyInputForKey:unmodifiedInput flags:flags]; | ||||
|              | ||||
|             dispatch_block_t actionBlock = self.actionsForKeyInputs[exactMatch]; | ||||
|              | ||||
|             if (!actionBlock) { | ||||
|                 FLEXKeyInput *shiftMatch = [FLEXKeyInput | ||||
|                     keyInputForKey:modifiedInput flags:flags&(~UIKeyModifierShift) | ||||
|                 ]; | ||||
|                 actionBlock = self.actionsForKeyInputs[shiftMatch]; | ||||
|             } | ||||
|              | ||||
|             if (!actionBlock) { | ||||
|                 FLEXKeyInput *capitalMatch = [FLEXKeyInput | ||||
|                     keyInputForKey:[unmodifiedInput uppercaseString] flags:flags | ||||
|                 ]; | ||||
|                 actionBlock = self.actionsForKeyInputs[capitalMatch]; | ||||
|             } | ||||
|              | ||||
|             if (actionBlock) { | ||||
|                 actionBlock(); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|      | ||||
|     // Calling _keyCode on events from the simulator keyboard will crash. | ||||
|     // It is only safe to call _keyCode when there's not an active responder. | ||||
|     if (!hasFirstResponder && [event respondsToSelector:@selector(_keyCode)]) { | ||||
|         long keyCode = [event _keyCode]; | ||||
|         if (keyCode == kFLEXControlKeyCode) { | ||||
|             self.pressingControl = isKeyDown; | ||||
|         } else if (keyCode == kFLEXCommandKeyCode) { | ||||
|             self.pressingCommand = isKeyDown; | ||||
|         } else if (keyCode == kFLEXShiftKeyCode) { | ||||
|             self.pressingShift = isKeyDown; | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| - (NSString *)keyboardShortcutsDescription { | ||||
|     NSMutableString *description = [NSMutableString new]; | ||||
|     NSArray<FLEXKeyInput *> *keyInputs = [self.actionsForKeyInputs.allKeys | ||||
|         sortedArrayUsingComparator:^NSComparisonResult(FLEXKeyInput *input1, FLEXKeyInput *input2) { | ||||
|             return [input1.key caseInsensitiveCompare:input2.key]; | ||||
|         } | ||||
|     ]; | ||||
|     for (FLEXKeyInput *keyInput in keyInputs) { | ||||
|         [description appendFormat:@"%@\n", keyInput]; | ||||
|     } | ||||
|     return [description copy]; | ||||
| } | ||||
|  | ||||
| @end | ||||
|  | ||||
| #endif | ||||
		Reference in New Issue
	
	Block a user
	 Balackburn
					Balackburn