generic improvements & fixes
This commit is contained in:
@@ -2,6 +2,7 @@
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="24506" targetRuntime="iOS.CocoaTouch.iPad" propertyAccessControl="none" useAutolayout="YES" colorMatched="YES" initialViewController="EVd-wq-ego">
|
||||
<device id="ipad11_0rounded" orientation="portrait" layout="fullscreen" appearance="light"/>
|
||||
<dependencies>
|
||||
<deployment identifier="iOS"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="24504"/>
|
||||
<capability name="Image references" minToolsVersion="12.0"/>
|
||||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||
@@ -12,7 +13,7 @@
|
||||
<objects>
|
||||
<viewController id="wb7-af-jn8" customClass="MainFrameViewController" sceneMemberID="viewController">
|
||||
<collectionView key="view" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" indicatorStyle="black" dataMode="prototypes" id="TZj-Lc-M9d" customClass="AppCollectionView">
|
||||
<rect key="frame" x="0.0" y="0.0" width="834" height="1210"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="834" height="1124"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<color key="backgroundColor" systemColor="systemBackgroundColor"/>
|
||||
<collectionViewFlowLayout key="collectionViewLayout" minimumLineSpacing="20" minimumInteritemSpacing="20" id="f7l-kG-hJc">
|
||||
@@ -1145,16 +1146,16 @@
|
||||
</constraints>
|
||||
</stackView>
|
||||
<stackView verifyAmbiguity="off" opaque="NO" contentMode="scaleToFill" ambiguous="YES" spacing="20" translatesAutoresizingMaskIntoConstraints="NO" id="pTO-ff-set">
|
||||
<rect key="frame" x="3145" y="191" width="293.5" height="31"/>
|
||||
<rect key="frame" x="3145" y="191" width="275.5" height="31"/>
|
||||
<subviews>
|
||||
<label verifyAmbiguity="off" opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Pencil Tip Offset" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" minimumScaleFactor="0.64999997615814209" adjustsLetterSpacingToFitWidth="YES" adjustsFontForContentSizeCategory="YES" translatesAutoresizingMaskIntoConstraints="NO" id="pTO-ff-lbl" userLabel="uiLabel">
|
||||
<rect key="frame" x="0.0" y="0.0" width="143.5" height="31"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="125.5" height="31"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="17"/>
|
||||
<nil key="textColor"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<switch opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="750" verticalHuggingPriority="750" contentHorizontalAlignment="center" contentVerticalAlignment="center" on="YES" translatesAutoresizingMaskIntoConstraints="NO" id="pTO-ff-swi">
|
||||
<rect key="frame" x="163.5" y="0.0" width="132" height="31"/>
|
||||
<rect key="frame" x="145.5" y="0.0" width="132" height="31"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="width" constant="130" id="pTO-ff-wid"/>
|
||||
</constraints>
|
||||
@@ -2079,19 +2080,19 @@
|
||||
<stackView verifyAmbiguity="off" opaque="NO" contentMode="scaleToFill" ambiguous="YES" axis="vertical" spacing="5" translatesAutoresizingMaskIntoConstraints="NO" id="WtH-Ii-ZUv">
|
||||
<rect key="frame" x="3145" y="426" width="380" height="56.5"/>
|
||||
<subviews>
|
||||
<label verifyAmbiguity="off" opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Hover Mode" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="DhB-EF-mDt">
|
||||
<label verifyAmbiguity="off" opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Pencil Mode" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="DhB-EF-mDt">
|
||||
<rect key="frame" x="0.0" y="0.0" width="380" height="20.5"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="17"/>
|
||||
<color key="textColor" red="0.93902439019999995" green="0.9625305918" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<segmentedControl verifyAmbiguity="off" opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="top" segmentControlStyle="plain" selectedSegmentIndex="0" translatesAutoresizingMaskIntoConstraints="NO" id="t12-bo-icS">
|
||||
<segmentedControl verifyAmbiguity="off" opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="top" apportionsSegmentWidthsByContent="YES" segmentControlStyle="plain" selectedSegmentIndex="0" translatesAutoresizingMaskIntoConstraints="NO" id="t12-bo-icS">
|
||||
<rect key="frame" x="0.0" y="25.5" width="380" height="32"/>
|
||||
<segments>
|
||||
<segment title="Disabled"/>
|
||||
<segment title="Hovering Disabled"/>
|
||||
<segment title="Stylus"/>
|
||||
<segment title="Mouse"/>
|
||||
<segment title="Both"/>
|
||||
<segment title="Touch"/>
|
||||
</segments>
|
||||
<color key="tintColor" red="0.6716768742" green="0.61711704730000005" blue="0.99902987480000005" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<color key="selectedSegmentTintColor" systemColor="linkColor"/>
|
||||
@@ -2325,8 +2326,6 @@
|
||||
<outlet property="hapticEngineStack" destination="MUp-Hc-VgH" id="XuW-ww-cmv"/>
|
||||
<outlet property="hdrStack" destination="dH7-Sy-EdJ" id="cJm-bj-Aqo"/>
|
||||
<outlet property="hdrSwitch" destination="wIq-fF-X8l" id="Ozz-h0-nJL"/>
|
||||
<outlet property="hoverModeSelector" destination="t12-bo-icS" id="0d6-QD-Mtg"/>
|
||||
<outlet property="hoverModeStack" destination="WtH-Ii-ZUv" id="BvA-MP-rmE"/>
|
||||
<outlet property="leftClickDelaySlider" destination="Mh4-1P-bSv" id="Tbj-Y0-t1x"/>
|
||||
<outlet property="leftClickDelayStack" destination="q0S-CP-V6v" id="0lz-MN-OEb"/>
|
||||
<outlet property="leftStickMinOffsetSlider" destination="KtJ-qH-KJX" id="vIV-4l-gbA"/>
|
||||
@@ -2356,6 +2355,8 @@
|
||||
<outlet property="optimizeGamesSwitch" destination="Sui-Ig-YxN" id="Lxu-si-ugy"/>
|
||||
<outlet property="passthroughGesturesStack" destination="wUP-2q-5vh" id="a4w-16-lLs"/>
|
||||
<outlet property="passthroughGesturesSwitch" destination="eO1-kV-e9j" id="5r8-o4-t9J"/>
|
||||
<outlet property="pencilModeSelector" destination="t12-bo-icS" id="0d6-QD-Mtg"/>
|
||||
<outlet property="pencilModeStack" destination="WtH-Ii-ZUv" id="BvA-MP-rmE"/>
|
||||
<outlet property="pencilPausesNativeTouchStack" destination="jLJ-Eo-Zi6" id="a4V-Lp-xDG"/>
|
||||
<outlet property="pencilPausesNativeTouchSwitch" destination="Pjf-Vi-3wE" id="L84-RY-6iV"/>
|
||||
<outlet property="pencilTickIntervalSlider" destination="IOG-l4-gtQ" id="3Kb-uT-ILa"/>
|
||||
@@ -3947,9 +3948,6 @@
|
||||
<systemColor name="systemGray3Color">
|
||||
<color red="0.78039215689999997" green="0.78039215689999997" blue="0.80000000000000004" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
</systemColor>
|
||||
<systemColor name="systemGray5Color">
|
||||
<color red="0.8980392157" green="0.8980392157" blue="0.91764705879999997" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
</systemColor>
|
||||
<systemColor name="systemTealColor">
|
||||
<color red="0.18823529410000001" green="0.69019607839999997" blue="0.78039215689999997" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
</systemColor>
|
||||
|
||||
@@ -389,6 +389,8 @@ import Foundation
|
||||
|
||||
@objc static var swapABXY:Bool = false
|
||||
|
||||
@objc static var gamepadArrivalReported: Bool = false
|
||||
|
||||
@objc static func string(for element: ControllerElement) -> String {
|
||||
return element.displayName
|
||||
}
|
||||
|
||||
@@ -88,9 +88,8 @@
|
||||
[self._dPadBackground addSublayer:self._leftButton];
|
||||
}
|
||||
|
||||
NSLog(@"layer name ttttttttttt============================");
|
||||
for(CALayer* buttonLayer in self.OSCButtonLayerPool){
|
||||
NSLog(@"layer name %@", buttonLayer.name);
|
||||
// NSLog(@"layer name %@", buttonLayer.name);
|
||||
}
|
||||
|
||||
[self resizeControllerLayerWith:self._dPadBackground and:_dPadSizeFactor];
|
||||
|
||||
@@ -22,11 +22,11 @@ typedef NS_ENUM(NSInteger, MapGyroTo) {
|
||||
driftCorrection
|
||||
};
|
||||
|
||||
typedef NS_ENUM(NSInteger, PencilHoverMode) {
|
||||
HoverDisabled,
|
||||
HoverPencil,
|
||||
HoverMouse,
|
||||
HoverBoth
|
||||
typedef NS_ENUM(NSInteger, PencilAndHoverMode) {
|
||||
hoverDisabled,
|
||||
pencilOnly,
|
||||
pencilToMouse,
|
||||
pencilToTouch
|
||||
};
|
||||
|
||||
|
||||
@@ -82,7 +82,7 @@ typedef NS_ENUM(NSInteger, PencilHoverMode) {
|
||||
@property NSString *squeezeEndShortcut;
|
||||
@property (nonatomic, assign) bool pencilPausesNativeTouch;
|
||||
@property (nonatomic, assign) bool disablePencilSlideGestures;
|
||||
@property (nonatomic, assign) PencilHoverMode pencilHoverMode;
|
||||
@property (nonatomic, assign) PencilAndHoverMode pencilAndHoverMode;
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -74,7 +74,7 @@
|
||||
[encoder encodeObject:self.squeezeEndShortcut forKey:@"squeezeEndShortcut"];
|
||||
[encoder encodeBool:self.pencilPausesNativeTouch forKey:@"pencilPausesNativeTouch"];
|
||||
[encoder encodeBool:self.disablePencilSlideGestures forKey:@"disablePencilSlideGestures"];
|
||||
[encoder encodeInt64:self.pencilHoverMode forKey:@"pencilHoverMode"];
|
||||
[encoder encodeInt64:self.pencilAndHoverMode forKey:@"pencilHoverMode"];
|
||||
}
|
||||
|
||||
- (id) initWithCoder:(NSCoder*)decoder {
|
||||
@@ -201,7 +201,7 @@
|
||||
|
||||
self.pencilPausesNativeTouch = [decoder containsValueForKey:@"pencilPausesNativeTouch"] ? [decoder decodeBoolForKey:@"pencilPausesNativeTouch"] : false;
|
||||
self.disablePencilSlideGestures = [decoder containsValueForKey:@"disablePencilSlideGestures"] ? [decoder decodeBoolForKey:@"disablePencilSlideGestures"] : false;
|
||||
self.pencilHoverMode = [decoder containsValueForKey:@"pencilHoverMode"] ? [decoder decodeInt64ForKey:@"pencilHoverMode"] : HoverPencil;
|
||||
self.pencilAndHoverMode = [decoder containsValueForKey:@"pencilHoverMode"] ? [decoder decodeInt64ForKey:@"pencilHoverMode"] : pencilOnly;
|
||||
}
|
||||
|
||||
return self;
|
||||
@@ -253,7 +253,7 @@
|
||||
copy.squeezeEndShortcut = [self.squeezeEndShortcut mutableCopy]; // NSString → NSMutableString
|
||||
copy.pencilPausesNativeTouch = self.pencilPausesNativeTouch;
|
||||
copy.disablePencilSlideGestures = self.disablePencilSlideGestures;
|
||||
copy.pencilHoverMode = self.pencilHoverMode;
|
||||
copy.pencilAndHoverMode = self.pencilAndHoverMode;
|
||||
return copy;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,85 +0,0 @@
|
||||
//
|
||||
// OSCProfilesManager.h
|
||||
// Moonlight
|
||||
//
|
||||
// Created by Long Le on 1/1/23.
|
||||
// Copyright © 2022 Moonlight Game Streaming Project. All rights reserved.
|
||||
//
|
||||
// Modified by True砖家 since 2024.6.24
|
||||
// Copyright © 2024 True砖家 @ Bilibili. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "OSCProfile.h"
|
||||
#import "DataManager.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
/**
|
||||
This singleton object can be accessed from any class and provides methods to get and set on screen controller profile related data.
|
||||
Note that the implementation file contains a number of 'Helper' methods. These helper methods are only used in this class's implementation file and help to reduce re-writing large blocks of code that are called multiple times throughout the file
|
||||
*/
|
||||
@interface OSCProfilesManager : NSObject
|
||||
@property NSMutableArray <OSCProfile *> *currentProfiles;
|
||||
@property (atomic, assign) WidgetSizeTransition widgetSizeTransition;
|
||||
|
||||
+ (OSCProfilesManager *)sharedManager:(CGRect)viewBounds;
|
||||
+ (void)setOnScreenWidgetViewsSet:(NSMutableSet* )set;
|
||||
+ (void)setLayoutViewBounds:(CGRect)bounds;
|
||||
|
||||
|
||||
#pragma mark - Getters
|
||||
/**
|
||||
* Returns an array of decoded profile objects
|
||||
*/
|
||||
- (NSMutableArray *) getAllProfiles;
|
||||
|
||||
/**
|
||||
* Returns the OSC Profile that is currently selected to be displayed on screen during game streaming
|
||||
*/
|
||||
- (OSCProfile *) getSelectedProfile;
|
||||
|
||||
- (uint32_t) getIndexOfLastProfile;
|
||||
|
||||
/**
|
||||
* Returns the index of the 'selected' profile within the array it's in
|
||||
*/
|
||||
- (NSInteger) getIndexOfSelectedProfile;
|
||||
- (NSMutableArray *) getEncodedProfiles;
|
||||
// - (NSData* )getSelectedEncodedProfile;
|
||||
- (void) importEncodedProfiles:(NSMutableArray* )profilesEncoded;
|
||||
- (OnScreenButtonState *)unarchiveButtonStateEncoded:(NSData *)data;
|
||||
- (void) updateDefaultTemplates;
|
||||
- (void) importDefaultTemplates;
|
||||
|
||||
#pragma mark - Setters
|
||||
/**
|
||||
* Sets the profile object with the particular index as the selected profile to be displayed on screen during game streaming
|
||||
*/
|
||||
- (void) setProfileToSelected:(uint32_t)index;
|
||||
- (void) replaceSelectedProfileWith:(OSCProfile*)newProfile overwriteDefault:(bool)overwriteDefault;
|
||||
- (void) replaceProfile:(OSCProfile*)oldProfile withProfile:(OSCProfile*)newProfile;
|
||||
|
||||
/**
|
||||
* Saves a profile object with a particular 'name' and an array of button layers (the CALayer button layers are the objects currently visible on screen) to persistent storage
|
||||
*/
|
||||
- (void) duplicateSelectedProfileWithName:(NSString*)name;
|
||||
|
||||
- (bool) updateSelectedProfile:(NSMutableSet *) oscButtonLayers;
|
||||
|
||||
/**
|
||||
* Delete current selected profile.
|
||||
*/
|
||||
- (void) deleteCurrentSelectedProfile;
|
||||
|
||||
#pragma mark - Queries
|
||||
/**
|
||||
* Lets the caller of this method know whether a profile with a given name already exists in persistent storage
|
||||
*/
|
||||
- (BOOL) profileNameAlreadyExist:(NSString*)name;
|
||||
- (OSCProfile *) findProfileByName:(NSString*) name inProfileArray:(NSMutableArray*)profiles;
|
||||
- (CGPoint)normalizeWidgetPosition:(CGPoint)position;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
@@ -1,579 +0,0 @@
|
||||
//
|
||||
// OSCProfilesManager.m
|
||||
// Moonlight
|
||||
//
|
||||
// Created by Long Le on 1/1/23.
|
||||
// Copyright © 2023 Moonlight Game Streaming Project. All rights reserved.
|
||||
//
|
||||
// Modified by True砖家 since 2024.6.24
|
||||
// Copyright © 2024 True砖家 @ Bilibili. All rights reserved.
|
||||
//
|
||||
|
||||
#import "OSCProfilesManager.h"
|
||||
#import "OnScreenButtonState.h"
|
||||
#import "VoidLink-Swift.h"
|
||||
#import "OnScreenControls.h"
|
||||
|
||||
@implementation OSCProfilesManager
|
||||
|
||||
static NSMutableSet *OnScreenWidgetViews;
|
||||
static CGRect layoutViewBounds;
|
||||
|
||||
#pragma mark - Initializer
|
||||
|
||||
+ (OSCProfilesManager *) sharedManager:(CGRect)viewBounds {
|
||||
static OSCProfilesManager *_sharedManager = nil;
|
||||
static dispatch_once_t onceToken;
|
||||
if(!CGRectEqualToRect(viewBounds, CGRectZero)) layoutViewBounds = viewBounds;
|
||||
// NSLog(@"bounds width: %f, height: %f", layoutViewBounds.size.width, layoutViewBounds.size.height);
|
||||
dispatch_once(&onceToken, ^{
|
||||
_sharedManager = [[self alloc] init];
|
||||
});
|
||||
// _sharedManager.currentProfiles = [_sharedManager getAllProfiles];
|
||||
return _sharedManager;
|
||||
}
|
||||
|
||||
|
||||
#pragma mark - Class Helper Methods
|
||||
|
||||
|
||||
+ (void)setOnScreenWidgetViewsSet:(NSMutableSet* )set{
|
||||
OnScreenWidgetViews = set;
|
||||
}
|
||||
|
||||
+ (void)setLayoutViewBounds:(CGRect)bounds{
|
||||
layoutViewBounds = bounds;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the profile whose 'name' property has a value that is equal to the 'name' passed into the method
|
||||
*/
|
||||
- (OSCProfile *) OSCProfileWithName:(NSString*)name {
|
||||
NSMutableArray *profiles = [self getAllProfiles];
|
||||
|
||||
for (OSCProfile *profile in profiles) {
|
||||
|
||||
if ([profile.name isEqualToString:name]) {
|
||||
return profile;
|
||||
}
|
||||
}
|
||||
|
||||
return nil;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array of encoded 'OSCProfile' objects from the array of decoded 'OSCProfile' objects passed into this method
|
||||
*/
|
||||
- (NSMutableArray *) encodedProfilesFromArray:(NSMutableArray *)profiles {
|
||||
|
||||
NSMutableArray *profilesEncoded = [[NSMutableArray alloc] init];
|
||||
/* encode each profile and add them back into an array */
|
||||
for (OSCProfile *profile in profiles) { //
|
||||
NSData *profileEncoded = [NSKeyedArchiver archivedDataWithRootObject:profile requiringSecureCoding:YES error:nil];
|
||||
[profilesEncoded addObject:profileEncoded];
|
||||
}
|
||||
|
||||
return profilesEncoded;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Delete an 'OSCProfile' object of specific index for another in the 'OSCProfile' objects array stored in persistent storage
|
||||
*/
|
||||
-(void)deleteCurrentSelectedProfile{
|
||||
NSMutableArray *profiles = [self getAllProfiles];
|
||||
NSInteger selectedIndex = [self getIndexOfSelectedProfile];
|
||||
|
||||
/* Remove the selected profile */
|
||||
if(selectedIndex != 0) [profiles removeObjectAtIndex:selectedIndex]; //deleting default profile (index 0) is not allowed
|
||||
else {
|
||||
NSLog(@"Default profile!"); // to be updated here.
|
||||
}
|
||||
|
||||
selectedIndex--;
|
||||
if(selectedIndex < 0) selectedIndex = 0;
|
||||
OSCProfile *newSelectedProfile = [profiles objectAtIndex:selectedIndex];
|
||||
newSelectedProfile.isSelected = YES;
|
||||
|
||||
NSMutableArray *profilesEncoded = [self encodedProfilesFromArray:profiles]; // encode each 'profile' object in the array and add them to a new array
|
||||
|
||||
/* Encode the array itself, NOT the objects in the array, which are already encoded. Save array to persistent storage */
|
||||
NSData *data = [NSKeyedArchiver archivedDataWithRootObject:profilesEncoded requiringSecureCoding:YES error:nil];
|
||||
[[NSUserDefaults standardUserDefaults] setObject:data forKey:@"OSCProfiles"];
|
||||
[[NSUserDefaults standardUserDefaults] synchronize];
|
||||
|
||||
}
|
||||
|
||||
- (void)replaceSelectedProfileWith:(OSCProfile*)newProfile overwriteDefault:(bool)overwriteDefault{
|
||||
NSInteger index = 0;
|
||||
NSMutableArray *profiles = [self getAllProfiles];
|
||||
for (OSCProfile *profile in profiles) {
|
||||
if (profile.isSelected == YES) {
|
||||
index = [profiles indexOfObject:profile];
|
||||
}
|
||||
}
|
||||
if(index>0) profiles[index] = newProfile;
|
||||
else if(overwriteDefault) profiles[index] = newProfile;
|
||||
|
||||
NSMutableArray *profilesEncoded = [self encodedProfilesFromArray:profiles];
|
||||
NSData *data = [NSKeyedArchiver archivedDataWithRootObject:profilesEncoded requiringSecureCoding:YES error:nil];
|
||||
[[NSUserDefaults standardUserDefaults] setObject:data forKey:@"OSCProfiles"];
|
||||
[[NSUserDefaults standardUserDefaults] synchronize];
|
||||
}
|
||||
|
||||
/**
|
||||
* Replaces one 'OSCProfile' object for another in the 'OSCProfile' objects array stored in persistent storage
|
||||
*/
|
||||
- (void) replaceProfile:(OSCProfile*)oldProfile withProfile:(OSCProfile*)newProfile {
|
||||
NSMutableArray *profiles = [self getAllProfiles];
|
||||
|
||||
for (OSCProfile *profile in profiles) { // set all profiles' 'isSelected' property to NO since the new profile we're saving over the old profile with will be the 'selected' profile
|
||||
profile.isSelected = NO;
|
||||
}
|
||||
|
||||
/* Set the new profile as the selected one. The reasoning behind this is that this method is currently being used when the user saves over an existing profile with another profile that has the same name. The expected behavior is that the newly saved profile becomes the selected profile which will show on screen when they launch the game stream view */
|
||||
newProfile.isSelected = YES;
|
||||
|
||||
/* Remove the old profile from the array and insert the new profile into its place */
|
||||
int index = 0;
|
||||
for (int i = 0; i < profiles.count; i++) {
|
||||
|
||||
if ([[profiles[i] name] isEqualToString: oldProfile.name]) {
|
||||
index = i;
|
||||
}
|
||||
}
|
||||
[profiles removeObjectAtIndex:index];
|
||||
[profiles insertObject:newProfile atIndex:index];
|
||||
|
||||
NSMutableArray *profilesEncoded = [self encodedProfilesFromArray:profiles]; // encode each 'profile' object in the array and add them to a new array
|
||||
|
||||
/* Encode the array itself, NOT the objects in the array, which are already encoded. Save array to persistent storage */
|
||||
NSData *data = [NSKeyedArchiver archivedDataWithRootObject:profilesEncoded requiringSecureCoding:YES error:nil];
|
||||
[[NSUserDefaults standardUserDefaults] setObject:data forKey:@"OSCProfiles"];
|
||||
[[NSUserDefaults standardUserDefaults] synchronize];
|
||||
}
|
||||
|
||||
- (NSMutableArray *) getEncodedProfiles {
|
||||
NSData *profilesArrayEncoded = [[NSUserDefaults standardUserDefaults] objectForKey: @"OSCProfiles"]; // Get the encoded array of encoded OSC profiles from persistent storage
|
||||
NSSet *classes = [NSSet setWithObjects:[NSString class], [NSMutableData class], [NSMutableArray class], [OSCProfile class], [OnScreenButtonState class], nil];
|
||||
|
||||
NSMutableArray *profilesEncoded = [NSKeyedUnarchiver unarchivedObjectOfClasses:classes fromData:profilesArrayEncoded error:nil]; // Decode the encoded array itself, NOT the objects contained in the array
|
||||
|
||||
return profilesEncoded;
|
||||
}
|
||||
|
||||
- (void) importEncodedProfiles:(NSMutableArray* )profilesEncoded {
|
||||
NSMutableArray* targetProfiles = [_currentProfiles mutableCopy]; //_currentProfiles is availabled as long as getAllProfiles was called before calling this method (_currentProfiles avoids frequent accessing persisted data)
|
||||
/*
|
||||
profile = [self findProfileByName:DEFAULT_TEMPLATE_NAME1 inProfileArray:targetProfiles];
|
||||
if(profile && targetProfiles.count > 1) [targetProfiles removeObject:profile];
|
||||
profile = [self findProfileByName:DEFAULT_TEMPLATE_NAME2 inProfileArray:targetProfiles];
|
||||
if(profile && targetProfiles.count > 1) [targetProfiles removeObject:profile];
|
||||
*/
|
||||
|
||||
/*
|
||||
NSString *bundleId = [[NSBundle mainBundle] bundleIdentifier];
|
||||
bool importPencilProProfile = ([bundleId isEqualToString:@"com.voidlink.iOS"]
|
||||
|| [bundleId isEqualToString:@"com.voidlinkextreme.iOS"]
|
||||
|| [bundleId isEqualToString:@"com.voidlink.tf.debug10.iOS"]);
|
||||
|
||||
if(!importPencilProProfile && [GenericUtils isIPad]){
|
||||
[profilesEncoded removeObjectAtIndex:1];
|
||||
}
|
||||
*/
|
||||
|
||||
if(targetProfiles.count > 0) [targetProfiles removeObjectAtIndex:0];
|
||||
NSMutableArray* localEncodedPofiles = [self encodedProfilesFromArray:targetProfiles];
|
||||
[profilesEncoded addObjectsFromArray:localEncodedPofiles];
|
||||
NSData *data = [NSKeyedArchiver archivedDataWithRootObject:profilesEncoded requiringSecureCoding:YES error:nil];
|
||||
[[NSUserDefaults standardUserDefaults] setObject:data forKey:@"OSCProfiles"];
|
||||
[[NSUserDefaults standardUserDefaults] synchronize];
|
||||
}
|
||||
|
||||
|
||||
- (BOOL)isIPhone{
|
||||
return ([UIDevice currentDevice].userInterfaceIdiom == UIUserInterfaceIdiomPhone);
|
||||
}
|
||||
|
||||
- (void) importDefaultTemplates{
|
||||
NSString *filePath = [[NSBundle mainBundle] pathForResource: [self isIPhone] ? @"widgetTemplatesIPhone": @"widgetTemplates" ofType:@"bin"];
|
||||
if (filePath) {
|
||||
// 2. 读取二进制数据
|
||||
NSError *error;
|
||||
NSData *fileData = [NSData dataWithContentsOfFile:filePath options:NSDataReadingMappedIfSafe error:&error];
|
||||
NSMutableArray *profilesEncoded;
|
||||
if (fileData && !error) {
|
||||
// 3. 成功读取
|
||||
NSSet *classes = [NSSet setWithObjects: [NSMutableData class], [NSMutableArray class], nil];
|
||||
profilesEncoded = [NSKeyedUnarchiver unarchivedObjectOfClasses:classes fromData:fileData error:&error];
|
||||
[self importEncodedProfiles:profilesEncoded];
|
||||
|
||||
NSString *bundleId = [[NSBundle mainBundle] bundleIdentifier];
|
||||
/*
|
||||
bool isRegularTF = !([bundleId isEqualToString:@"com.voidlink.iOS"]
|
||||
|| [bundleId isEqualToString:@"com.voidlinkextreme.iOS"]
|
||||
|| [bundleId isEqualToString:@"com.voidlink.tf.debug10.iOS"]);
|
||||
|
||||
[self setProfileToSelected: GenericUtils.isIPhone ? 1 : (isRegularTF ? 1: 2)]; */
|
||||
[self setProfileToSelected: 0];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (void) updateDefaultTemplates{
|
||||
NSString *filePath = [[NSBundle mainBundle] pathForResource: [self isIPhone] ? @"widgetTemplatesIPhone": @"widgetTemplates" ofType:@"bin"];
|
||||
if (filePath) {
|
||||
// 2. 读取二进制数据
|
||||
NSError *error;
|
||||
NSData *fileData = [NSData dataWithContentsOfFile:filePath options:NSDataReadingMappedIfSafe error:&error];
|
||||
if (fileData && !error) {
|
||||
NSSet *classes = [NSSet setWithObjects:[NSString class], [NSMutableData class], [NSMutableArray class], [OSCProfile class], [OnScreenButtonState class], nil];
|
||||
NSMutableArray *defaultProfilesEncoded = [NSKeyedUnarchiver unarchivedObjectOfClasses:classes fromData:fileData error:nil]; // Decode the encoded array itself, NOT the objects contained in the array
|
||||
OSCProfile *defaultProfileDecoded;
|
||||
NSMutableArray *targetProfilesDecoded = [self getAllProfiles];
|
||||
OSCProfile *newPencilProProfile;
|
||||
bool pencilProProfileExisted = false;
|
||||
for (NSData *profileEncoded in defaultProfilesEncoded) {
|
||||
defaultProfileDecoded = [NSKeyedUnarchiver unarchivedObjectOfClasses: classes fromData:profileEncoded error: nil];
|
||||
OSCProfile *targetProfile = [self findProfileByName:defaultProfileDecoded.name inProfileArray:targetProfilesDecoded];
|
||||
if([defaultProfileDecoded.name isEqualToString:@"Pencil Pro"]){
|
||||
newPencilProProfile = [defaultProfileDecoded mutableCopy];
|
||||
}
|
||||
if(targetProfile){
|
||||
if([targetProfile.name isEqualToString:@"Pencil Pro"]){
|
||||
pencilProProfileExisted = true;
|
||||
}
|
||||
uint64_t targetIndex = [targetProfilesDecoded indexOfObject:targetProfile];
|
||||
targetProfilesDecoded[targetIndex] = defaultProfileDecoded;
|
||||
}
|
||||
}
|
||||
if(newPencilProProfile && !pencilProProfileExisted){
|
||||
if(newPencilProProfile) [targetProfilesDecoded insertObject:newPencilProProfile atIndex:1];
|
||||
}
|
||||
|
||||
NSMutableArray* targetPofilesEncoded = [self encodedProfilesFromArray:targetProfilesDecoded];
|
||||
NSData *data = [NSKeyedArchiver archivedDataWithRootObject:targetPofilesEncoded requiringSecureCoding:YES error:nil];
|
||||
[[NSUserDefaults standardUserDefaults] setObject:data forKey:@"OSCProfiles"];
|
||||
[[NSUserDefaults standardUserDefaults] synchronize];
|
||||
[self setProfileToSelected:0];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#pragma mark - Globally Accessible Methods
|
||||
|
||||
#pragma mark - Getters
|
||||
|
||||
- (NSMutableArray *) getAllProfiles {
|
||||
NSData *profilesArrayEncoded = [[NSUserDefaults standardUserDefaults] objectForKey: @"OSCProfiles"]; // Get the encoded array of encoded OSC profiles from persistent storage
|
||||
NSSet *classes = [NSSet setWithObjects:[NSString class], [NSMutableData class], [NSMutableArray class], [OSCProfile class], [OnScreenButtonState class], nil];
|
||||
|
||||
NSMutableArray *profilesEncoded = [NSKeyedUnarchiver unarchivedObjectOfClasses:classes fromData:profilesArrayEncoded error:nil]; // Decode the encoded array itself, NOT the objects contained in the array
|
||||
|
||||
/* Decode each of the encoded profiles, place them into an array, then return the array */
|
||||
NSMutableArray *profilesDecoded = [[NSMutableArray alloc] init];
|
||||
OSCProfile *profileDecoded;
|
||||
for (NSData *profileEncoded in profilesEncoded) {
|
||||
|
||||
profileDecoded = [NSKeyedUnarchiver unarchivedObjectOfClasses: classes fromData:profileEncoded error: nil];
|
||||
[profilesDecoded addObject: profileDecoded];
|
||||
}
|
||||
_currentProfiles = profilesDecoded;
|
||||
return profilesDecoded;
|
||||
}
|
||||
|
||||
- (NSMutableArray *) decodeProfilesFrom:(NSMutableArray* )profilesEncoded {
|
||||
NSSet *classes = [NSSet setWithObjects:[NSString class], [NSMutableData class], [NSMutableArray class], [OSCProfile class], [OnScreenButtonState class], nil];
|
||||
NSMutableArray *profilesDecoded = [[NSMutableArray alloc] init];
|
||||
OSCProfile *profileDecoded;
|
||||
for (NSData *profileEncoded in profilesEncoded) {
|
||||
|
||||
profileDecoded = [NSKeyedUnarchiver unarchivedObjectOfClasses: classes fromData:profileEncoded error: nil];
|
||||
[profilesDecoded addObject: profileDecoded];
|
||||
}
|
||||
return profilesDecoded;
|
||||
}
|
||||
|
||||
- (OSCProfile *) getSelectedProfile {
|
||||
// NSLog(@"getAllProfiles test %f", CACurrentMediaTime());
|
||||
NSMutableArray *profiles = [self getAllProfiles];
|
||||
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
|
||||
|
||||
// NSString* persistedKey = @"widgetProfileUpdated-20251015";
|
||||
// NSString* persistedKey = @"widgetProfileUpdated-20260322";
|
||||
// NSString* persistedKey = @"widgetProfileUpdated-20260413-2";
|
||||
// NSString* persistedKey = @"widgetProfileUpdated-20260430-1";
|
||||
// NSString* persistedKey = @"widgetProfileUpdated-20260513-1";
|
||||
NSString* persistedKey = @"widgetProfileUpdated-20260530";
|
||||
BOOL needImportDefaultTemplates = [defaults objectForKey:persistedKey] == nil;
|
||||
|
||||
if(profiles.count == 0 || needImportDefaultTemplates){
|
||||
if(profiles.count == 0) [self importDefaultTemplates];
|
||||
else [self updateDefaultTemplates];
|
||||
[[NSUserDefaults standardUserDefaults] setBool:YES forKey:persistedKey];
|
||||
[[NSUserDefaults standardUserDefaults] synchronize];
|
||||
profiles = [self getAllProfiles];
|
||||
}
|
||||
for (OSCProfile *profile in profiles) {
|
||||
if (profile.isSelected) {
|
||||
return profile;
|
||||
}
|
||||
}
|
||||
return profiles[0];
|
||||
}
|
||||
|
||||
- (NSInteger) getIndexOfSelectedProfile {
|
||||
NSMutableArray *profiles = [self getAllProfiles];
|
||||
for (OSCProfile *profile in profiles) {
|
||||
|
||||
if (profile.isSelected == YES) {
|
||||
return [profiles indexOfObject:profile];
|
||||
}
|
||||
}
|
||||
return 0; // if none of the profiles in the array have their 'isSelected' property set to YES (which should not be possible) return the 'Default' profile as the 'selected' profile
|
||||
}
|
||||
|
||||
- (uint32_t) getIndexOfLastProfile {
|
||||
NSMutableArray *profiles = [self getAllProfiles];
|
||||
return (uint32_t)profiles.count-1; // if none of the profiles in the array have their 'isSelected' property set to YES (which should not be possible) return the 'Default' profile as the 'selected' profile
|
||||
}
|
||||
|
||||
|
||||
#pragma mark - Setters
|
||||
|
||||
- (void) setProfileToSelected:(uint32_t)tableIndex {
|
||||
NSMutableArray *profiles = [self getAllProfiles];
|
||||
|
||||
[profiles enumerateObjectsUsingBlock:^(OSCProfile* profile, NSUInteger idx, BOOL *stop) {
|
||||
profile.isSelected = idx == tableIndex;
|
||||
}];
|
||||
|
||||
NSMutableArray *profilesEncoded = [self encodedProfilesFromArray:profiles]; // encode each 'profile' object in the array and add them to a new array
|
||||
|
||||
/* Encode the array itself, NOT the objects inside the array, which have already been encoded by this point */
|
||||
NSData *data = [NSKeyedArchiver archivedDataWithRootObject:profilesEncoded requiringSecureCoding:YES error:nil];
|
||||
[[NSUserDefaults standardUserDefaults] setObject:data forKey:@"OSCProfiles"];
|
||||
[[NSUserDefaults standardUserDefaults] synchronize];
|
||||
}
|
||||
|
||||
|
||||
- (bool) updateSelectedProfile:(NSMutableSet *) oscButtonLayers {
|
||||
NSMutableArray* buttonStatesEncoded = [self convertOnScreenControllerAndWidgetsToButtonStates:oscButtonLayers];
|
||||
if([self getIndexOfSelectedProfile]==0) return false;
|
||||
/*
|
||||
OSCProfile *newProfile = [[OSCProfile alloc] initWithName:[self getSelectedProfile].name
|
||||
buttonStates:buttonStatesEncoded isSelected:YES]; // create a new 'OSCProfile'. Set the array of encoded button states created above to the 'buttonStates' property of the new profile, along with a 'name'. Set 'isSelected' argument to YES which will set this saved profile as the one that will show up in the game stream view
|
||||
*/
|
||||
OSCProfile *selectedProfile = [self getSelectedProfile];
|
||||
selectedProfile.buttonStatesEncoded = buttonStatesEncoded;
|
||||
selectedProfile.unfoldedExclusiveFolderSequence = OnScreenWidgetView.unfoldedExclusiveFolderSequence;
|
||||
selectedProfile.postExclusiveUnfoldedSequences = OnScreenWidgetView.postExclusiveUnfoldedSequences;
|
||||
[self replaceSelectedProfileWith:selectedProfile overwriteDefault:NO];
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
- (void) duplicateSelectedProfileWithName:(NSString*)name {
|
||||
if ([self profileNameAlreadyExist:name]) return;
|
||||
else { // otherwise encode then add the new profile to the end of the OSCProfiles array
|
||||
NSMutableArray *profiles = [self getAllProfiles];
|
||||
OSCProfile* newProfile = nil;
|
||||
for(OSCProfile* profile in profiles){
|
||||
if(profile.isSelected){
|
||||
profile.isSelected = false;
|
||||
newProfile = [profile mutableCopy];
|
||||
newProfile.isSelected = true;
|
||||
newProfile.name = name;
|
||||
}
|
||||
}
|
||||
if(newProfile){
|
||||
NSData *newProfileEncoded = [NSKeyedArchiver archivedDataWithRootObject:newProfile requiringSecureCoding:YES error:nil];
|
||||
NSMutableArray *profilesEncoded = [self encodedProfilesFromArray:profiles];
|
||||
[profilesEncoded addObject:newProfileEncoded];
|
||||
|
||||
/* Encode the 'profilesEncoded' array itself, NOT the objects in the 'profilesEncoded' array, all of which are already encoded by this point */
|
||||
NSData *data = [NSKeyedArchiver archivedDataWithRootObject:profilesEncoded requiringSecureCoding:YES error:nil];
|
||||
[[NSUserDefaults standardUserDefaults] setObject:data forKey:@"OSCProfiles"];
|
||||
[[NSUserDefaults standardUserDefaults] synchronize];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (CGPoint)normalizeWidgetPosition:(CGPoint)position {
|
||||
CGPoint newPosition = position;
|
||||
if(position.x > 1.0 && position.y >1.0){
|
||||
position.x = position.x / layoutViewBounds.size.width;
|
||||
position.y = position.y / layoutViewBounds.size.height;
|
||||
}
|
||||
NSLog(@"layoutToolView bounds: %f, %f", layoutViewBounds.size.width, layoutViewBounds.size.height);
|
||||
NSLog(@"position: %f, %f, denormalized position: %f, %f", position.x, position.y, newPosition.x, newPosition.y);
|
||||
return position;
|
||||
}
|
||||
|
||||
- (CGPoint)denormalizeWidgetPosition:(CGPoint)position {
|
||||
if(position.x < 1.0 && position.y < 1.0){
|
||||
position.x = position.x * layoutViewBounds.size.width;
|
||||
position.y = position.y * layoutViewBounds.size.height;
|
||||
}
|
||||
return position;
|
||||
}
|
||||
|
||||
- (NSMutableArray* ) convertOnScreenControllerAndWidgetsToButtonStates:(NSMutableSet *) oscButtonLayers {
|
||||
/* iterate through each OSC button the user sees on screen, create an 'OnScreenButtonState' object from each button, encode each object, and then add each object to an array */
|
||||
/*
|
||||
NSSet *validPositionButtonNames = [NSSet setWithObjects:
|
||||
@"l2Button",
|
||||
@"l1Button",
|
||||
@"dPad",
|
||||
@"selectButton",
|
||||
@"leftStickBackground",
|
||||
@"rightStickBackground",
|
||||
@"r2Button",
|
||||
@"r1Button",
|
||||
@"aButton",
|
||||
@"bButton",
|
||||
@"xButton",
|
||||
@"yButton",
|
||||
@"startButton",
|
||||
nil]; */
|
||||
NSMutableArray *buttonStatesEncoded = [[NSMutableArray alloc] init];
|
||||
|
||||
// save on-screen game controller buttons & sticks as buttonstate:
|
||||
for (CALayer *oscButtonLayer in oscButtonLayers) {
|
||||
if(oscButtonLayer.isHidden) continue;
|
||||
|
||||
CGPoint normalizedPosition = [self normalizeWidgetPosition:oscButtonLayer.position];
|
||||
OnScreenButtonState *buttonState = [[OnScreenButtonState alloc] initWithButtonName:oscButtonLayer.name buttonType:LegacyOnScreenControls andPosition:normalizedPosition];
|
||||
// add hidden attr here
|
||||
buttonState.isHidden = oscButtonLayer.isHidden;
|
||||
buttonState.oscLayerSizeFactor = [OnScreenControls getControllerLayerSizeFactor:oscButtonLayer];
|
||||
buttonState.backgroundAlpha = oscButtonLayer.opacity;
|
||||
|
||||
NSNumber *style = [OnScreenControls.layerVibrationStyleDic objectForKey:oscButtonLayer.name];
|
||||
if ([style isKindOfClass:[NSNumber class]]) {
|
||||
buttonState.vibrationStyle = [style unsignedCharValue];
|
||||
// 使用 val
|
||||
}
|
||||
else buttonState.vibrationStyle = UIImpactFeedbackStyleLight;
|
||||
|
||||
// NSLog(@"oscLayerName: %@, opacity: %f, ", oscButtonLayer.name, buttonState.backgroundAlpha);
|
||||
// buttonState.oscLayerSizeFactor = oscButtonLayer.bounds;
|
||||
|
||||
NSData *buttonStateEncoded = [NSKeyedArchiver archivedDataWithRootObject:buttonState requiringSecureCoding:YES error:nil];
|
||||
[buttonStatesEncoded addObject: buttonStateEncoded];
|
||||
}
|
||||
|
||||
// save on-screen widget views (keyboard & mouse command) as buttonstate:
|
||||
_widgetSizeTransition = keepWidgetSize;
|
||||
for(OnScreenWidgetView* widgetView in OnScreenWidgetView.mapping.allValues){
|
||||
CGPoint normalizedPosition = [self normalizeWidgetPosition:widgetView.storedCenter];
|
||||
OnScreenButtonState *buttonState = [[OnScreenButtonState alloc] initWithButtonName:widgetView.cmdString buttonType:CustomOnScreenWidget andPosition:normalizedPosition];
|
||||
buttonState.alias = widgetView.widgetLabel;
|
||||
buttonState.sequence = widgetView.sequence;
|
||||
buttonState.sequenceSet = widgetView.sequenceSet;
|
||||
buttonState.parentSequence = widgetView.parentSequence;
|
||||
buttonState.autoDockTimer = widgetView.autoDockIdleDuration;
|
||||
buttonState.dockedAlpha = widgetView.autoDockSettledAlpha;
|
||||
buttonState.folded = widgetView.folded;
|
||||
buttonState.revealMode = widgetView.revealMode;
|
||||
buttonState.bulkMoveEnabled = widgetView.bulkMoveEnabled;
|
||||
buttonState.widthFactor = [self normalizeSizeWidthFactorWith:widgetView];
|
||||
buttonState.heightFactor = [self normalizeSizeHeightFactorWith:widgetView];
|
||||
buttonState.backgroundAlpha = widgetView.originalBackgroundAlpha;
|
||||
buttonState.labelAlpha = widgetView.originalLabelAlpha;
|
||||
buttonState.borderAlpha = widgetView.borderAlpha;
|
||||
buttonState.highlightAlpha = widgetView.highlightAlpha;
|
||||
buttonState.borderWidth = widgetView.borderWidth;
|
||||
buttonState.highlightSizeFactor = widgetView.highlightSizeFactor;
|
||||
buttonState.autoTapInterval = widgetView.autoTapInterval;
|
||||
buttonState.autoTapRepeats = widgetView.autoTapRepeats;
|
||||
buttonState.vibrationStyle = widgetView.vibrationStyle;
|
||||
buttonState.mouseButtonAction = widgetView.mouseButtonAction;
|
||||
buttonState.animatesTransition = widgetView.animatesTransition;
|
||||
buttonState.sensitivityFactorY = widgetView.sensitivityFactorY;
|
||||
buttonState.slideThreshold = widgetView.slideThreshold;
|
||||
buttonState.yawFactor = widgetView.yawFactor;
|
||||
buttonState.pitchFactor = widgetView.pitchFactor;
|
||||
buttonState.rollFactor = widgetView.rollFactor;
|
||||
buttonState.decelerationRateX = widgetView.decelerationRateX;
|
||||
buttonState.decelerationRateY = widgetView.decelerationRateY;
|
||||
buttonState.widgetShape = widgetView.shape;
|
||||
buttonState.walkModeThreshold = widgetView.dWheelWalkModeThreshold;
|
||||
buttonState.minStickOffset = widgetView.minStickOffset;
|
||||
buttonState.buttonMode = widgetView.buttonMode;
|
||||
buttonState.sprintKeyActionType = widgetView.sprintKeyActionType;
|
||||
buttonState.sprintKeyThreshold = widgetView.sprintKeyThreshold;
|
||||
buttonState.walkKeyActionType = widgetView.walkKeyActionType;
|
||||
buttonState.walkKeyThreshold = widgetView.walkKeyThreshold;
|
||||
///
|
||||
buttonState.sensitivityFactorX = widgetView.sensitivityFactorX;
|
||||
buttonState.componentSizeFactor = [self normalizeComponentSizeFactorWith:widgetView];
|
||||
buttonState.touchPointAnchored = widgetView.touchPointAnchored;
|
||||
buttonState.stickIndicatorOffset = widgetView.stickIndicatorOffset;
|
||||
|
||||
NSData *buttonStateEncoded = [NSKeyedArchiver archivedDataWithRootObject:buttonState requiringSecureCoding:YES error:nil];
|
||||
[buttonStatesEncoded addObject: buttonStateEncoded];
|
||||
}
|
||||
return buttonStatesEncoded;
|
||||
}
|
||||
|
||||
- (CGFloat)getReferenceLen{
|
||||
CGFloat screenWidthInPoints = CGRectGetWidth([[UIScreen mainScreen] bounds]);
|
||||
CGFloat screenHeightInPoints = CGRectGetHeight([[UIScreen mainScreen] bounds]);
|
||||
CGFloat longSideLen = fmax(screenWidthInPoints,screenHeightInPoints);
|
||||
CGFloat referenceLen = longSideLen;
|
||||
if(_widgetSizeTransition == keepWidgetSize) referenceLen = longSideLen;
|
||||
if(_widgetSizeTransition == transitionWithOrientation) referenceLen = screenWidthInPoints;
|
||||
return referenceLen;
|
||||
}
|
||||
|
||||
- (CGFloat)normalizeSizeWidthFactorWith:(OnScreenWidgetView* )widget{
|
||||
return widget.bounds.size.width/[self getReferenceLen] * 10000;
|
||||
}
|
||||
|
||||
- (CGFloat)normalizeSizeHeightFactorWith:(OnScreenWidgetView* )widget{
|
||||
return widget.bounds.size.height/[self getReferenceLen] * 10000;
|
||||
}
|
||||
|
||||
- (CGFloat)normalizeComponentSizeFactorWith:(OnScreenWidgetView* )widget{
|
||||
if(widget.isStickWheel
|
||||
|| widget.isDisplacementBasedStickPad) {
|
||||
return widget.denormalizedComponentSizeFactor*widget.baselineDiameter/[self getReferenceLen] * 10000;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
#pragma mark - Queries
|
||||
|
||||
- (BOOL) profileNameAlreadyExist:(NSString*)name {
|
||||
NSMutableArray *profiles = [self getAllProfiles];
|
||||
/* Iterate through the decoded profiles and return 'YES' if one of the profiles' 'name' properties equals the 'name' passed into this method */
|
||||
for (OSCProfile *profile in profiles) {
|
||||
if ([profile.name isEqualToString:name]) {
|
||||
return YES;
|
||||
}
|
||||
}
|
||||
return NO;
|
||||
}
|
||||
|
||||
- (OSCProfile *) findProfileByName:(NSString*) name inProfileArray:(NSMutableArray*)profiles {
|
||||
/* Iterate through the decoded profiles and return 'YES' if one of the profiles' 'name' properties equals the 'name' passed into this method */
|
||||
for (OSCProfile *profile in profiles) {
|
||||
if ([profile.name isEqualToString:name]) {
|
||||
return profile;
|
||||
}
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (OnScreenButtonState *)unarchiveButtonStateEncoded:(NSData *)data {
|
||||
OnScreenButtonState* buttonState;
|
||||
buttonState = [NSKeyedUnarchiver unarchivedObjectOfClasses:[NSSet setWithObjects:[NSString class], [OnScreenButtonState class], [NSSet class], [NSNumber class], nil]
|
||||
fromData:data
|
||||
error:nil];
|
||||
return buttonState;
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -418,8 +418,8 @@ class OSCProfilesManager: NSObject {
|
||||
|
||||
func normalizeWidgetPosition(_ position: CGPoint) -> CGPoint {
|
||||
var normalizedPosition = position
|
||||
let originalPosition = position
|
||||
if position.x > 1.0, position.y > 1.0 {
|
||||
// let originalPosition = position
|
||||
if abs(position.x) > 1.0, abs(position.y) > 1.0 {
|
||||
normalizedPosition.x = position.x / Self.layoutViewBounds.size.width
|
||||
normalizedPosition.y = position.y / Self.layoutViewBounds.size.height
|
||||
}
|
||||
@@ -430,7 +430,7 @@ class OSCProfilesManager: NSObject {
|
||||
|
||||
private func denormalizeWidgetPosition(_ position: CGPoint) -> CGPoint {
|
||||
var denormalizedPosition = position
|
||||
if position.x < 1.0, position.y < 1.0 {
|
||||
if abs(position.x) < 2.01, abs(position.y) < 2.01 {
|
||||
denormalizedPosition.x = position.x * Self.layoutViewBounds.size.width
|
||||
denormalizedPosition.y = position.y * Self.layoutViewBounds.size.height
|
||||
}
|
||||
|
||||
@@ -404,8 +404,8 @@ import CoreMotion
|
||||
}
|
||||
|
||||
private func clearGyroInput(interruptNonGyroInput:Bool){
|
||||
// guard let onScreenControls = onScreenControls else { return }
|
||||
|
||||
guard ControllerUtil.gamepadArrivalReported else { return }
|
||||
|
||||
if yawPitchToRightStick{
|
||||
onScreenControls?.sendRightStickTouchPadEvent(rightStickPhysicalInputX+rightStickTouchInputX-yawBias, rightStickPhysicalInputY+rightStickTouchInputY-pitchBias)
|
||||
}
|
||||
|
||||
@@ -360,7 +360,7 @@ static float L3_Y;
|
||||
}
|
||||
|
||||
- (CGPoint) denormalizeWidgetPosition:(CGPoint)position {
|
||||
if(position.x < 1.0 && position.y < 1.0) {
|
||||
if(position.x < 1.01 && position.y < 1.01) {
|
||||
position.x = position.x * _view.bounds.size.width;
|
||||
position.y = position.y * _view.bounds.size.height;
|
||||
// NSLog(@"denormalizing position: %f, %f", position.x, position.y);
|
||||
|
||||
@@ -61,11 +61,11 @@ import ObjectiveC.runtime
|
||||
func alterAbsTouchDragWith(mouseButton:Int32)
|
||||
func enablePencilHover()
|
||||
func disablePencilHover()
|
||||
func setAllowSingleTouchEnabled(_ enabled:Bool)
|
||||
func handleDisableSingleTouchButtonUp()
|
||||
func replaceBrush(shortcut:String)
|
||||
func replaceEraser(shortcut:String)
|
||||
func presentPressureCurveVC()
|
||||
func toggleTouch(disabled:Bool)
|
||||
func handleTouchDisableButtonUp()
|
||||
func toggleGamepadOverlay(overlayEnabled:Bool)
|
||||
@objc(magnifierMoveStreamViewWithTranslation:)
|
||||
func magnifierMoveStreamView(translation: CGVector)
|
||||
@@ -672,14 +672,15 @@ import ObjectiveC.runtime
|
||||
self.hasTrackPoint = true
|
||||
self.hasNonEditableLabel = (self.cmdString == "DISABLETOUCH"
|
||||
|| self.cmdString == "GAMEPADOVERLAY"
|
||||
|| self.cmdString == "DISABLETILT")
|
||||
|| self.cmdString == "DISABLETILT"
|
||||
|| self.cmdString == "NOSINGLETOUCH")
|
||||
self.hasTemporaryLabel = CommandManager.velocityBasedTouchPads.contains(self.touchPadString) && (self.isMotionControlButton || self.buttonString == "NULL")
|
||||
|| self.cmdString == "RSVPAD"
|
||||
|| self.cmdString == "LSVPAD"
|
||||
|
||||
self.mouseButtonActionDelay = self.cmdString.contains("ABSMOUSEPAD") ? 0.005 : 0
|
||||
|
||||
self.standardFoldingInterval = widgetType == .touchPad ? 0.05 : 0.15;
|
||||
self.standardFoldingInterval = widgetType == .touchPad ? 0.05 : 0.085;
|
||||
|
||||
self.isMagnifier = self.cmdString.contains("MAGNIFIER")
|
||||
|
||||
@@ -1053,13 +1054,21 @@ import ObjectiveC.runtime
|
||||
if self.hasNonEditableLabel {
|
||||
|
||||
switch cmdString {
|
||||
case "DISABLETOUCH":
|
||||
self.nonEditableWidgetLabel = LocalizationHelper.localizedString(forKey: touchDisabledFLag ? "=EnableTouch" : "=DisableTouch" )
|
||||
case "GAMEPADOVERLAY":
|
||||
self.nonEditableWidgetLabel = LocalizationHelper.localizedString(forKey: OnScreenWidgetView.gamepadOverlayFLag ? "=GamepadOverlayOn" : "=GamepadOverlayOff" )
|
||||
self.nonEditableWidgetLabel = OnScreenWidgetView.gamepadOverlayFLag ? "=GamepadOverlayOn".localized : "=GamepadOverlayOff".localized
|
||||
case "DISABLETOUCH":
|
||||
if let vc = StreamFrameViewController.sharedInstance() {
|
||||
self.nonEditableWidgetLabel = vc.touchDisabled ? "=EnableTouch".localized : "=DisableTouch".localized
|
||||
}
|
||||
else {self.nonEditableWidgetLabel = "=DisableTouch".localized}
|
||||
case "NOSINGLETOUCH":
|
||||
if let vc = StreamFrameViewController.sharedInstance() {
|
||||
self.nonEditableWidgetLabel = vc.singleTouchDisabled ? "=EnableSingleTouch".localized : "=DisableSingleTouch".localized
|
||||
}
|
||||
else {self.nonEditableWidgetLabel = "=DisableSingleTouch".localized}
|
||||
case "DISABLETILT":
|
||||
if let pencilHandler = PencilHandler.shared {
|
||||
self.nonEditableWidgetLabel = LocalizationHelper.localizedString(forKey: pencilHandler.disableTilt ? "=enableTilt" : "=disableTilt" )
|
||||
self.nonEditableWidgetLabel = pencilHandler.disableTilt ? "=enableTilt".localized : "=disableTilt".localized
|
||||
}
|
||||
else {self.nonEditableWidgetLabel = "=disableTilt".localized}
|
||||
default:
|
||||
@@ -1690,7 +1699,7 @@ import ObjectiveC.runtime
|
||||
|
||||
// legacy keyboard button combo connected by "+"
|
||||
if !OnScreenWidgetView.editMode && self.cmdString.contains("+") && !self.cmdString.contains("-"){
|
||||
if buttonMode == .movable, moveableButtonLongPressed() {return}
|
||||
if buttonMode == .movable, firstTouchMoved {return}
|
||||
if leaveNonSkillButtonAlone {return}
|
||||
self.buttonDownVisualEffect()
|
||||
if var autoReleaseComboButtons = CommandManager.shared.extractAutoReleaseButtonStrings(from: self.cmdString) {
|
||||
@@ -1874,7 +1883,7 @@ import ObjectiveC.runtime
|
||||
self.onScreenControls?.sendRightStickTouchPadEvent(stickOffsetVector.dx, stickOffsetVector.dy)
|
||||
}
|
||||
self.motionHandler?.mixOnScreenRightStickAndGyroInput(x: targetX, y: targetY)
|
||||
if !OnScreenWidgetView.gamepadArrivalReported {OnScreenWidgetView.gamepadArrivalReported = true}
|
||||
if !ControllerUtil.gamepadArrivalReported {ControllerUtil.gamepadArrivalReported = true}
|
||||
}
|
||||
|
||||
private func sendLeftStickTouchPadEvent(weightedTouchX:CGFloat, weightedTouchY:CGFloat, circulate:Bool=false){
|
||||
@@ -1889,7 +1898,7 @@ import ObjectiveC.runtime
|
||||
self.onScreenControls?.sendLeftStickTouchPadEvent(stickOffsetVector.dx, stickOffsetVector.dy)
|
||||
}
|
||||
self.motionHandler?.mixOnScreenLeftStickAndGyroInput(x: targetX, y: targetY)
|
||||
if !OnScreenWidgetView.gamepadArrivalReported {OnScreenWidgetView.gamepadArrivalReported = true}
|
||||
if !ControllerUtil.gamepadArrivalReported {ControllerUtil.gamepadArrivalReported = true}
|
||||
}
|
||||
|
||||
private func sendLeftTriggerTouchPadEvent(inputY: CGFloat){
|
||||
@@ -1963,7 +1972,7 @@ import ObjectiveC.runtime
|
||||
DispatchQueue.global(qos: .userInteractive).async {
|
||||
if CommandManager.oscButtonMappings.keys.contains(realButtonString) {
|
||||
self.sendOscButtonDownEvent(oscString: realButtonString)
|
||||
if !OnScreenWidgetView.gamepadArrivalReported {OnScreenWidgetView.gamepadArrivalReported = true}
|
||||
if !ControllerUtil.gamepadArrivalReported {ControllerUtil.gamepadArrivalReported = true}
|
||||
}
|
||||
if CommandManager.keyboardButtonMappings.keys.contains(realButtonString) {
|
||||
LiSendKeyboardEvent(CommandManager.keyboardButtonMappings[realButtonString]!,Int8(KEY_ACTION_DOWN), 0)
|
||||
@@ -2249,8 +2258,10 @@ import ObjectiveC.runtime
|
||||
|
||||
if self.widgetType == WidgetTypeEnum.button && (self.buttonMode == .movable || self.temporarilyMovable) {
|
||||
movableButtonReleased = false
|
||||
DispatchQueue.main.asyncAfter(deadline: .now() + 0.3) {
|
||||
OnScreenWidgetView.updateStreamViewGuidelines(for: self)
|
||||
if false {
|
||||
DispatchQueue.main.asyncAfter(deadline: .now() + 0.3) {
|
||||
OnScreenWidgetView.updateStreamViewGuidelines(for: self)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2341,8 +2352,10 @@ import ObjectiveC.runtime
|
||||
layoutUpdateDelegate?.updateGuidelinesForOnScreenWidget(self)
|
||||
}
|
||||
else {
|
||||
if self.widgetType == .button {superview?.bringSubviewToFront(self)}
|
||||
OnScreenWidgetView.updateStreamViewGuidelines(for: self)
|
||||
// if self.widgetType == .button {superview?.bringSubviewToFront(self)}
|
||||
if false {
|
||||
OnScreenWidgetView.updateStreamViewGuidelines(for: self)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2486,7 +2499,10 @@ import ObjectiveC.runtime
|
||||
|
||||
if (self.buttonMode == .movable || self.temporarilyMovable) && self.moveableButtonLongPressed() {
|
||||
if let touch = touches.first {
|
||||
CATransaction.begin()
|
||||
CATransaction.setDisableActions(true)
|
||||
self.moveByTouch(touch: touch)
|
||||
CATransaction.commit()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2825,10 +2841,10 @@ import ObjectiveC.runtime
|
||||
switch self.motionControlButtonString {
|
||||
case "GYRO":
|
||||
self.motionHandler?.startMotionControlByOnScreenButton(self, yawFactor: yawFactor, pitchFactor: pitchFactor, rollFactor: rollFactor)
|
||||
if !OnScreenWidgetView.gamepadArrivalReported {OnScreenWidgetView.gamepadArrivalReported = oscProfile.mapGyroTo == .mapGyroToControllerStick}
|
||||
if !ControllerUtil.gamepadArrivalReported {ControllerUtil.gamepadArrivalReported = oscProfile.mapGyroTo == .mapGyroToControllerStick}
|
||||
case "GYROPAUSE":
|
||||
self.motionHandler?.stopMotionUpdate(interruptNoneGyroInput:false)
|
||||
if !OnScreenWidgetView.gamepadArrivalReported {OnScreenWidgetView.gamepadArrivalReported = oscProfile.mapGyroTo == .mapGyroToControllerStick}
|
||||
if !ControllerUtil.gamepadArrivalReported {ControllerUtil.gamepadArrivalReported = oscProfile.mapGyroTo == .mapGyroToControllerStick}
|
||||
break
|
||||
case "ACCEL":
|
||||
break
|
||||
@@ -2888,9 +2904,6 @@ import ObjectiveC.runtime
|
||||
case "PENCILHOVER":
|
||||
if !self.isPencilProEnabled() {break}
|
||||
self.functionalWidgetDelegate?.enablePencilHover()
|
||||
case "NOSINGLETOUCH":
|
||||
if !self.isPencilProEnabled() {break}
|
||||
self.functionalWidgetDelegate?.setAllowSingleTouchEnabled(false)
|
||||
default:
|
||||
break
|
||||
}
|
||||
@@ -2898,29 +2911,24 @@ import ObjectiveC.runtime
|
||||
|
||||
private var movableButtonReleased:Bool = true
|
||||
private func moveableButtonLongPressed() -> Bool{
|
||||
return !movableButtonReleased && CACurrentMediaTime() - self.touchTapTimeStamp > 0.3
|
||||
return !movableButtonReleased && CACurrentMediaTime() - self.touchTapTimeStamp > 0.05
|
||||
}
|
||||
|
||||
private var singleTouchEnabled:Bool = true
|
||||
|
||||
|
||||
private func handleFunctionalButtonUp(event: UIEvent? = nil){
|
||||
// print("handleFunctionalButtonUp \(self.widgetLabel), event Empty: \(String(describing: event)), \(CACurrentMediaTime())")
|
||||
if autoDockIsDocked {return}
|
||||
if firstTouchMoved {return}
|
||||
/*
|
||||
if buttonMode == .movable {
|
||||
if moveableButtonLongPressed() && !UITouchUtil.touches(in: self, from: event).isEmpty {return}
|
||||
switch self.functionalButtonString {
|
||||
// case "FOLDER":
|
||||
// self.folded = !self.folded
|
||||
// OnScreenWidgetView.set(folded: self.folded, for: self)
|
||||
case "NOSINGLETOUCH":
|
||||
if !self.isPencilProEnabled() {break}
|
||||
singleTouchEnabled = !singleTouchEnabled
|
||||
self.functionalWidgetDelegate?.setAllowSingleTouchEnabled(singleTouchEnabled)
|
||||
return
|
||||
default:
|
||||
break
|
||||
}
|
||||
}
|
||||
} */
|
||||
|
||||
switch self.functionalButtonString {
|
||||
case "FOLDER":
|
||||
@@ -2962,16 +2970,28 @@ import ObjectiveC.runtime
|
||||
self.functionalWidgetDelegate?.bringUpSoftKeyboard()
|
||||
case "ABSTCHDRAG":
|
||||
self.functionalWidgetDelegate?.alterAbsTouchDragWith(mouseButton:BUTTON_LEFT)
|
||||
case "DISABLETOUCH":
|
||||
self.handleTouchDisableButtonUp()
|
||||
case "GAMEPADOVERLAY":
|
||||
self.gamepadOverlayButtonUp()
|
||||
case "PENCILHOVER":
|
||||
if !self.isPencilProEnabled() {break}
|
||||
self.functionalWidgetDelegate?.disablePencilHover()
|
||||
|
||||
case "DISABLETOUCH":
|
||||
if let streamFrameVC = StreamFrameViewController.sharedInstance() {
|
||||
streamFrameVC.touchDisabled = !streamFrameVC.touchDisabled
|
||||
self.functionalWidgetDelegate?.handleTouchDisableButtonUp()
|
||||
}
|
||||
case "NOSINGLETOUCH":
|
||||
if !self.isPencilProEnabled() {break}
|
||||
self.functionalWidgetDelegate?.setAllowSingleTouchEnabled(true)
|
||||
if let streamFrameVC = StreamFrameViewController.sharedInstance() {
|
||||
streamFrameVC.singleTouchDisabled = !streamFrameVC.singleTouchDisabled
|
||||
self.functionalWidgetDelegate?.handleDisableSingleTouchButtonUp()
|
||||
}
|
||||
case "DISABLETILT":
|
||||
if !self.isPencilProEnabled() {break}
|
||||
if let pencilHandler = PencilHandler.shared {
|
||||
pencilHandler.disableTilt = !pencilHandler.disableTilt
|
||||
}
|
||||
case "BRUSH":
|
||||
if !self.isPencilProEnabled() {break}
|
||||
var brushShortcut = self.cmdString.replacingOccurrences(of: "BRUSH+", with: "")
|
||||
@@ -2982,12 +3002,6 @@ import ObjectiveC.runtime
|
||||
var eraserShortcut = self.cmdString.replacingOccurrences(of: "ERASER+", with: "")
|
||||
eraserShortcut = eraserShortcut.replacingOccurrences(of: "ERASER", with: "")
|
||||
self.functionalWidgetDelegate?.replaceEraser(shortcut: eraserShortcut)
|
||||
case "DISABLETILT":
|
||||
if !self.isPencilProEnabled() {break}
|
||||
if let pencilHandler = PencilHandler.shared {
|
||||
pencilHandler.disableTilt = !pencilHandler.disableTilt
|
||||
self.setupAtrributedText()
|
||||
}
|
||||
case "PRESSURECURVE":
|
||||
if ["com.voidlink.iOS"
|
||||
, "com.voidlinkextreme.iOS"
|
||||
@@ -2998,15 +3012,12 @@ import ObjectiveC.runtime
|
||||
default:
|
||||
break
|
||||
}
|
||||
|
||||
if self.hasNonEditableLabel {
|
||||
self.setupAtrributedText()
|
||||
}
|
||||
}
|
||||
|
||||
private var touchDisabledFLag:Bool = false
|
||||
private func handleTouchDisableButtonUp(){
|
||||
touchDisabledFLag = !touchDisabledFLag
|
||||
self.setupAtrributedText()
|
||||
self.functionalWidgetDelegate?.toggleTouch(disabled: touchDisabledFLag)
|
||||
}
|
||||
|
||||
|
||||
@objc static var gamepadOverlayFLag:Bool = false
|
||||
private func gamepadOverlayButtonUp(){
|
||||
self.relocatedDuringStreaming = true
|
||||
@@ -3806,10 +3817,20 @@ import ObjectiveC.runtime
|
||||
@objc static var enableFolderAnimation:Bool = true
|
||||
private static func setCollection(folded:Bool, for folder:OnScreenWidgetView, exception:OnScreenWidgetView? = nil, recursive:Bool = false, isExclusiveFolderAction:Bool = false) {
|
||||
guard folder.isFolder else {return}
|
||||
|
||||
if !OnScreenWidgetView.enableFolderAnimation, folder.parentSequence == -1 {
|
||||
folder.buttonDownVisualEffect()
|
||||
folder.buttonDownVisualEffectLayer.isHidden = false
|
||||
DispatchQueue.main.asyncAfter(deadline: .now() + 1.5) {
|
||||
folder.buttonDownVisualEffectLayer.isHidden = true
|
||||
}
|
||||
}
|
||||
|
||||
// guard folder.folded != hidden else { return }
|
||||
folder.folded = folded
|
||||
folder.setupAtrributedText()
|
||||
folder.reverseColorPhase(reversed: !folder.folded)
|
||||
|
||||
if folded {
|
||||
for sequence in folder.sequenceSet {
|
||||
guard let widget = OnScreenWidgetView.mapping[sequence], widget != exception else {continue}
|
||||
@@ -3897,8 +3918,16 @@ import ObjectiveC.runtime
|
||||
}
|
||||
}
|
||||
|
||||
@objc static func disableFolderAnimation(for duration: TimeInterval){
|
||||
enableFolderAnimation = false
|
||||
DispatchQueue.global().asyncAfter(deadline: .now() + duration) {
|
||||
enableFolderAnimation = true
|
||||
}
|
||||
}
|
||||
|
||||
@objc static func set(folded:Bool, for folder:OnScreenWidgetView) { // folder综合逻辑
|
||||
guard folder.isFolder else {return}
|
||||
|
||||
if !folded {
|
||||
OnScreenWidgetView.deepestButton = OnScreenWidgetView.getDeepestButton()
|
||||
}
|
||||
@@ -4129,7 +4158,6 @@ import ObjectiveC.runtime
|
||||
return OnScreenWidgetView.mapping.keys.max() ?? -1
|
||||
}
|
||||
|
||||
@objc static var gamepadArrivalReported: Bool = false
|
||||
override func didMoveToSuperview() {
|
||||
super.didMoveToSuperview()
|
||||
OnScreenWidgetView.installAutoDockIfNeeded()
|
||||
@@ -4141,14 +4169,14 @@ import ObjectiveC.runtime
|
||||
label.alpha = 1
|
||||
autoDockRestoreOriginalAlpha()
|
||||
if self.motionControlButtonString == "GYRO" {
|
||||
if OnScreenWidgetView.gamepadArrivalReported {self.motionHandler?.stopMotionUpdate(interruptNoneGyroInput: true)}
|
||||
if ControllerUtil.gamepadArrivalReported {self.motionHandler?.stopMotionUpdate(interruptNoneGyroInput: true)}
|
||||
self.motionHandler?.motionStarter = nil
|
||||
}
|
||||
if self.motionControlButtonString == "ACCEL" {}
|
||||
if self.motionControlButtonString == "MOTION" {}
|
||||
|
||||
if self.widgetType == WidgetTypeEnum.button && !OnScreenWidgetView.editMode {
|
||||
if OnScreenWidgetView.gamepadArrivalReported {self.sendComboButtonsUpEvent(comboStrings: self.comboButtonStrings)}
|
||||
if ControllerUtil.gamepadArrivalReported {self.sendComboButtonsUpEvent(comboStrings: self.comboButtonStrings)}
|
||||
self.functionalWidgetDelegate?.alterAbsTouchDragWith(mouseButton:BUTTON_LEFT)
|
||||
}
|
||||
buttonDownVisualEffectLayer.removeFromSuperlayer()
|
||||
@@ -4167,7 +4195,7 @@ import ObjectiveC.runtime
|
||||
stickWheelLayer.removeFromSuperlayer()
|
||||
stickWheelLayerSmall.removeFromSuperlayer()
|
||||
self.inertialScroller.timer?.clean()
|
||||
if OnScreenWidgetView.gamepadArrivalReported {
|
||||
if ControllerUtil.gamepadArrivalReported {
|
||||
self.clearLeftStickTouchPadFlag()
|
||||
self.clearRightStickTouchPadFlag()
|
||||
}
|
||||
@@ -4255,7 +4283,7 @@ import ObjectiveC.runtime
|
||||
}
|
||||
|
||||
deinit {
|
||||
print("onScreenWidgetView deinit \(self.widgetLabel))")
|
||||
// print("onScreenWidgetView deinit \(self.widgetLabel))")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -25,7 +25,7 @@ import UIKit
|
||||
private var manualHoverFlag: Bool = false
|
||||
@objc static var hoverSupported: Bool = false
|
||||
// @objc static private(set) var autoHoverTermination: Bool = false
|
||||
@objc static private(set) var hoverMode: PencilHoverMode = .HoverPencil
|
||||
@objc static private(set) var pencilAndHoverMode: PencilAndHoverMode = .pencilOnly
|
||||
private(set) var pencilProEnabled: Bool = false
|
||||
private var isFirstMove: Bool = false
|
||||
private var strokeSampleIndex: Int32 = 0
|
||||
@@ -105,7 +105,7 @@ import UIKit
|
||||
}
|
||||
|
||||
// PencilHandler.autoHoverTermination = selectedProfile.autoPencilHoverTermination
|
||||
PencilHandler.hoverMode = selectedProfile.pencilHoverMode
|
||||
PencilHandler.pencilAndHoverMode = selectedProfile.pencilAndHoverMode
|
||||
|
||||
pressureCurveEnabled = selectedProfile.pressureCurveEnabled
|
||||
|
||||
@@ -151,6 +151,12 @@ import UIKit
|
||||
PencilHandler.isDrawing = true
|
||||
// isFirstMove = true
|
||||
strokeSampleIndex = 0
|
||||
|
||||
guard PencilHandler.pencilAndHoverMode == .pencilOnly || PencilHandler.pencilAndHoverMode == .hoverDisabled else {
|
||||
handleNonPencilModes(touches)
|
||||
return
|
||||
}
|
||||
|
||||
for touch in touches {
|
||||
let coalesced = event.coalescedTouches(for: touch) ?? []
|
||||
_ = self.sendStylusEvent(touchBatch: pencilTickEnabled ? coalesced : [touch])
|
||||
@@ -159,6 +165,12 @@ import UIKit
|
||||
|
||||
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
|
||||
guard let event = event else { return }
|
||||
|
||||
guard PencilHandler.pencilAndHoverMode == .pencilOnly || PencilHandler.pencilAndHoverMode == .hoverDisabled else {
|
||||
handleNonPencilModes(touches)
|
||||
return
|
||||
}
|
||||
|
||||
for touch in touches {
|
||||
let coalesced = event.coalescedTouches(for: touch) ?? []
|
||||
_ = self.sendStylusEvent(touchBatch: pencilTickEnabled ? coalesced : [touch])
|
||||
@@ -167,6 +179,12 @@ import UIKit
|
||||
|
||||
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
|
||||
guard let event = event else { return }
|
||||
|
||||
guard PencilHandler.pencilAndHoverMode == .pencilOnly || PencilHandler.pencilAndHoverMode == .hoverDisabled else {
|
||||
handleNonPencilModes(touches)
|
||||
return
|
||||
}
|
||||
|
||||
for touch in touches {
|
||||
let coalesced = event.coalescedTouches(for: touch) ?? []
|
||||
_ = self.sendStylusEvent(touchBatch: pencilTickEnabled ? coalesced : [touch])
|
||||
@@ -176,6 +194,34 @@ import UIKit
|
||||
override func touchesCancelled(_ touches: Set<UITouch>, with event: UIEvent?) {
|
||||
self.touchesEnded(touches, with: event)
|
||||
}
|
||||
|
||||
private func handleNonPencilModes(_ touches: Set<UITouch>) {
|
||||
guard let touch = touches.first else { return }
|
||||
let location = touch.location(in: streamView)
|
||||
let normalizedLocation = self.getNormalizedLocation(point: location)
|
||||
if let streamView = streamView as? StreamView {
|
||||
switch touch.phase {
|
||||
case .began where PencilHandler.pencilAndHoverMode == .pencilToMouse:
|
||||
streamView.updateCursorLocation(location, isMouse: false)
|
||||
LiSendMouseButtonEvent(CChar(BUTTON_ACTION_PRESS), BUTTON_LEFT)
|
||||
case .began where PencilHandler.pencilAndHoverMode == .pencilToTouch:
|
||||
LiSendTouchEvent(UInt8(LI_TOUCH_EVENT_DOWN), 666666, Float(normalizedLocation.x), Float(normalizedLocation.y), Float((touch.force/touch.maximumPossibleForce)/sin(touch.altitudeAngle)), 0, 0, getRotation(fromAzimuthAngle: Float(touch.azimuthAngle(in: streamView))))
|
||||
case .moved where PencilHandler.pencilAndHoverMode == .pencilToMouse:
|
||||
streamView.updateCursorLocation(location, isMouse: false)
|
||||
case .moved where PencilHandler.pencilAndHoverMode == .pencilToTouch:
|
||||
LiSendTouchEvent(UInt8(LI_TOUCH_EVENT_MOVE), 666666, Float(normalizedLocation.x), Float(normalizedLocation.y), Float((touch.force/touch.maximumPossibleForce)/sin(touch.altitudeAngle)), 0, 0, getRotation(fromAzimuthAngle: Float(touch.azimuthAngle(in: streamView))))
|
||||
case .ended where PencilHandler.pencilAndHoverMode == .pencilToMouse,
|
||||
.cancelled where PencilHandler.pencilAndHoverMode == .pencilToMouse:
|
||||
streamView.updateCursorLocation(location, isMouse: false)
|
||||
LiSendMouseButtonEvent(CChar(BUTTON_ACTION_RELEASE), BUTTON_LEFT)
|
||||
case .ended where PencilHandler.pencilAndHoverMode == .pencilToTouch,
|
||||
.cancelled where PencilHandler.pencilAndHoverMode == .pencilToTouch:
|
||||
LiSendTouchEvent(UInt8(LI_TOUCH_EVENT_UP), 666666, Float(normalizedLocation.x), Float(normalizedLocation.y), 0, 0, 0, 0)
|
||||
default:
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Core Logic
|
||||
|
||||
@@ -229,7 +275,15 @@ import UIKit
|
||||
|
||||
func getTilt(fromAltitudeAngle altitudeAngle: Float) -> UInt8 {
|
||||
let altitudeDegs = abs(Int16(altitudeAngle * (180.0 / .pi)))
|
||||
return disableTilt ? 0 : UInt8(90 - min(90, Int(altitudeDegs)))
|
||||
let tilt = disableTilt ? 0 : UInt8(90 - min(90, Int(altitudeDegs)))
|
||||
return tilt
|
||||
}
|
||||
|
||||
private func getNormalizedLocation(point: CGPoint) -> CGPoint {
|
||||
let location = self.adjustCoordinatesForVideoArea(point: point)
|
||||
let videoSize = self.getVideoAreaSize()
|
||||
let normalizedLocation = CGPoint(x: location.x/videoSize.width, y: location.y/videoSize.height)
|
||||
return normalizedLocation
|
||||
}
|
||||
|
||||
var previousForce: Float = 0
|
||||
@@ -250,9 +304,7 @@ import UIKit
|
||||
.applying(CGAffineTransform(translationX: pencilTipOffset.x, y: pencilTipOffset.y))
|
||||
let azimuth = touch.azimuthAngle(in: streamView)
|
||||
let altitude = touch.altitudeAngle
|
||||
let location = self.adjustCoordinatesForVideoArea(point: point)
|
||||
let videoSize = self.getVideoAreaSize()
|
||||
let normalizedLocation = CGPoint(x: location.x/videoSize.width, y: location.y/videoSize.height)
|
||||
let normalizedLocation = self.getNormalizedLocation(point: point)
|
||||
var force = Float(touch.force/touch.maximumPossibleForce)/sin(Float(altitude))
|
||||
force = (self.pencilTickEnabled && force == 0) ? previousForce : force
|
||||
|
||||
@@ -332,7 +384,7 @@ import UIKit
|
||||
|
||||
if eventType == UInt8(LI_TOUCH_EVENT_UP) {
|
||||
PencilHandler.isDrawing = false
|
||||
if PencilHandler.hoverMode == .HoverDisabled || !PencilHandler.hoverSupported {
|
||||
if PencilHandler.pencilAndHoverMode == .hoverDisabled || !PencilHandler.hoverSupported {
|
||||
LiSendPenEvent(UInt8(LI_TOUCH_EVENT_HOVER), UInt8(LI_TOOL_TYPE_PEN), 0, Float(normalizedLocation.x), Float(normalizedLocation.y), 0, 0, 0, self.getRotation(fromAzimuthAngle: Float(azimuth)), self.getTilt(fromAltitudeAngle: Float(altitude)))
|
||||
DispatchQueue.global().asyncAfter(deadline: .now() + 0.0086){
|
||||
if !PencilHandler.isDrawing {
|
||||
|
||||
+24
-13
@@ -73,7 +73,7 @@ static const double X1_MOUSE_SPEED_DIVISOR = 2.5;
|
||||
|
||||
NSTimer* interactionTimer;
|
||||
BOOL hasUserInteracted;
|
||||
|
||||
|
||||
NSDictionary<NSString *, NSNumber *> *dictCodes;
|
||||
CustomTapGestureRecognizer *keyboardToggleRecognizer;
|
||||
UIPanGestureRecognizer *discreteMouseWheelRecognizer;
|
||||
@@ -236,6 +236,7 @@ static const double X1_MOUSE_SPEED_DIVISOR = 2.5;
|
||||
case NativeTouch:
|
||||
keyboardToggleRecognizer.immediateTriggering = false;
|
||||
self->touchHandler = [[NativeTouchHandler alloc] initWithView:self settings:settings profile:profile];
|
||||
[(NativeTouchHandler* )touchHandler setAllowSingleTouchEnabled:!_streamFrameVC.singleTouchDisabled];
|
||||
break;
|
||||
case NativeTouchOnly:
|
||||
keyboardToggleRecognizer.immediateTriggering = false;
|
||||
@@ -254,11 +255,11 @@ static const double X1_MOUSE_SPEED_DIVISOR = 2.5;
|
||||
self->touchHandler = nil;
|
||||
keyboardToggleRecognizer.immediateTriggering = false;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
sessionTouchHandler = touchHandler;
|
||||
if(_streamFrameVC.touchDisabled) touchHandler = nil;
|
||||
}
|
||||
|
||||
- (void)refreshKeyboardToggleRecognizer:(uint8_t)numberOfTouches{
|
||||
@@ -619,7 +620,7 @@ static const double X1_MOUSE_SPEED_DIVISOR = 2.5;
|
||||
}
|
||||
|
||||
- (CGPoint)denormalizeWidgetPosition:(CGPoint)position {
|
||||
if(position.x < 1.0 && position.y < 1.0){
|
||||
if(position.x < 2.01 && position.y < 2.01){
|
||||
position.x = position.x * _streamFrameTopLayerView.bounds.size.width;
|
||||
position.y = position.y * _streamFrameTopLayerView.bounds.size.height;
|
||||
}
|
||||
@@ -691,10 +692,11 @@ static const double X1_MOUSE_SPEED_DIVISOR = 2.5;
|
||||
self->oscProfileMan = [OSCProfilesManager sharedManager:self->_streamFrameTopLayerView.bounds];
|
||||
|
||||
if(!profile){
|
||||
NSLog(@"reloadOnScreenWidgets in streamview %d", reloadWidgets);
|
||||
profile = [self->oscProfileMan getSelectedProfile]; //returns the currently selected OSCProfile
|
||||
}
|
||||
|
||||
NSLog(@"reloadOnScreenWidgets in streamview %d", reloadWidgets);
|
||||
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
MotionHandler* motionHandler = [MotionHandler sharedWithProfile:profile];
|
||||
|
||||
@@ -718,6 +720,11 @@ static const double X1_MOUSE_SPEED_DIVISOR = 2.5;
|
||||
// remove all keyboard widget views first
|
||||
[self clearOnScreenWidgets];
|
||||
|
||||
self->_streamFrameVC.touchDisabled = false;
|
||||
self->_streamFrameVC.singleTouchDisabled = false;
|
||||
PencilHandler* pencilHandler = [PencilHandler shared];
|
||||
if(pencilHandler) pencilHandler.disableTilt = false;
|
||||
|
||||
bool sequenceGenerated = false;
|
||||
bool hasMovableWidget = false;
|
||||
|
||||
@@ -767,6 +774,7 @@ static const double X1_MOUSE_SPEED_DIVISOR = 2.5;
|
||||
widgetView.minStickOffset = buttonState.minStickOffset;
|
||||
widgetView.dWheelWalkModeThreshold = buttonState.walkModeThreshold;
|
||||
widgetView.buttonMode = buttonState.buttonMode;
|
||||
if([widgetView.cmdString isEqualToString:@"NOSINGLETOUCH"]) widgetView.buttonMode = movable;
|
||||
widgetView.sprintKeyActionType = buttonState.sprintKeyActionType;
|
||||
widgetView.sprintKeyThreshold = buttonState.sprintKeyThreshold;
|
||||
widgetView.walkKeyActionType = buttonState.walkKeyActionType;
|
||||
@@ -999,7 +1007,9 @@ static const double X1_MOUSE_SPEED_DIVISOR = 2.5;
|
||||
});
|
||||
}
|
||||
|
||||
CGPoint location = [self adjustCoordinatesForVideoArea:[gesture locationInView:self]];
|
||||
CGPoint originalLocation = [gesture locationInView:self];
|
||||
CGPoint location = [self adjustCoordinatesForVideoArea:originalLocation];
|
||||
NSLog(@" location %f, %f", location.x, location.y);
|
||||
PencilHandler* handler = PencilHandler.shared;
|
||||
location = CGPointApplyAffineTransform(location, CGAffineTransformMakeTranslation(handler.pencilTipOffset.x, handler.pencilTipOffset.y));
|
||||
|
||||
@@ -1023,19 +1033,20 @@ static const double X1_MOUSE_SPEED_DIVISOR = 2.5;
|
||||
|
||||
|
||||
dispatch_after(0, dispatch_get_global_queue(QOS_CLASS_USER_INTERACTIVE,0), ^{// Code to execute after the delay
|
||||
if(PencilHandler.isDrawing) return;
|
||||
switch (PencilHandler.hoverMode) {
|
||||
case HoverPencil:
|
||||
if(PencilHandler.isDrawing && PencilHandler.pencilAndHoverMode == pencilOnly && PencilHandler.pencilAndHoverMode == hoverDisabled) return;
|
||||
switch (PencilHandler.pencilAndHoverMode) {
|
||||
case pencilOnly:
|
||||
LiSendPenEvent(type, LI_TOOL_TYPE_PEN, 0, location.x / videoSize.width, location.y / videoSize.height, distance, 0.0f, 0.0f, rotationAngle, tiltAngle);
|
||||
break;
|
||||
case HoverMouse:
|
||||
[self updateCursorLocation:location isMouse:YES];
|
||||
case pencilToMouse:
|
||||
if(gesture.state != UIGestureRecognizerStateEnded) [self updateCursorLocation:originalLocation isMouse:NO];
|
||||
break;
|
||||
case HoverDisabled:
|
||||
case hoverDisabled:
|
||||
break;
|
||||
case HoverBoth:
|
||||
case pencilToTouch:
|
||||
/*
|
||||
LiSendPenEvent(type, LI_TOOL_TYPE_PEN, 0, location.x / videoSize.width, location.y / videoSize.height, distance, 0.0f, 0.0f, rotationAngle, tiltAngle);
|
||||
[self updateCursorLocation:location isMouse:YES];
|
||||
[self updateCursorLocation:location isMouse:YES]; */
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
|
||||
@@ -1121,6 +1121,35 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"=DisableSingleTouch" : {
|
||||
"extractionState" : "manual",
|
||||
"localizations" : {
|
||||
"en" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "🚫 SingleTouch"
|
||||
}
|
||||
},
|
||||
"zh-Hans" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "🚫 单指触摸"
|
||||
}
|
||||
},
|
||||
"zh-Hant" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "🚫 單指觸摸"
|
||||
}
|
||||
},
|
||||
"zh-HK" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "🚫 單指觸摸"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"=disableTilt" : {
|
||||
"extractionState" : "manual",
|
||||
"localizations" : {
|
||||
@@ -1295,6 +1324,35 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"=EnableSingleTouch" : {
|
||||
"extractionState" : "manual",
|
||||
"localizations" : {
|
||||
"en" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "🟢 SingleTouch"
|
||||
}
|
||||
},
|
||||
"zh-Hans" : {
|
||||
"stringUnit" : {
|
||||
"state" : "needs_review",
|
||||
"value" : "🟢 单指触摸"
|
||||
}
|
||||
},
|
||||
"zh-Hant" : {
|
||||
"stringUnit" : {
|
||||
"state" : "needs_review",
|
||||
"value" : "🟢 單指觸摸"
|
||||
}
|
||||
},
|
||||
"zh-HK" : {
|
||||
"stringUnit" : {
|
||||
"state" : "needs_review",
|
||||
"value" : "🟢 單指觸摸"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"=enableTilt" : {
|
||||
"extractionState" : "manual",
|
||||
"localizations" : {
|
||||
@@ -2455,35 +2513,6 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"=noSingleTouch" : {
|
||||
"extractionState" : "manual",
|
||||
"localizations" : {
|
||||
"en" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "🚫SingleTouch"
|
||||
}
|
||||
},
|
||||
"zh-Hans" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "🚫单指触摸"
|
||||
}
|
||||
},
|
||||
"zh-Hant" : {
|
||||
"stringUnit" : {
|
||||
"state" : "needs_review",
|
||||
"value" : "🚫單指觸摸"
|
||||
}
|
||||
},
|
||||
"zh-HK" : {
|
||||
"stringUnit" : {
|
||||
"state" : "needs_review",
|
||||
"value" : "🚫單指觸摸"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"=null" : {
|
||||
"extractionState" : "manual",
|
||||
"localizations" : {
|
||||
@@ -10149,35 +10178,6 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"hoverModeStackTip" : {
|
||||
"extractionState" : "manual",
|
||||
"localizations" : {
|
||||
"en" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "When “both” is selected, you’ll get flickering cursor on host.\nThis function is available without purchasing [Drawing Toolkit]."
|
||||
}
|
||||
},
|
||||
"zh-Hans" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "当选择“同时悬停”时,PC端的光标将会闪烁。\n此功能是Pencil基础功能的一部分,不属于Drawing Toolkit。 "
|
||||
}
|
||||
},
|
||||
"zh-Hant" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "當選擇「同時懸停」時,PC 端的游標將會閃爍。\n此功能為 Pencil 基礎功能的一部分,不屬於 Drawing Toolkit。"
|
||||
}
|
||||
},
|
||||
"zh-HK" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "當選擇「同時懸停」時,PC 端的游標將會閃爍。\n此功能為 Pencil 基礎功能的一部分,不屬於 Drawing Toolkit。"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"I'm an artist" : {
|
||||
"extractionState" : "manual",
|
||||
"localizations" : {
|
||||
@@ -13303,6 +13303,52 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"Pencil hover" : {
|
||||
"extractionState" : "manual",
|
||||
"localizations" : {
|
||||
"zh-Hans" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "Pencil 悬停"
|
||||
}
|
||||
},
|
||||
"zh-Hant" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "Pencil 懸浮"
|
||||
}
|
||||
},
|
||||
"zh-HK" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "Pencil 懸浮"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"Pencil Pro Pack" : {
|
||||
"extractionState" : "manual",
|
||||
"localizations" : {
|
||||
"zh-Hans" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "Pencil 专业套装"
|
||||
}
|
||||
},
|
||||
"zh-Hant" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "Pencil 專業套裝"
|
||||
}
|
||||
},
|
||||
"zh-HK" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "Pencil 專業套裝"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"Pencil Tip Offset" : {
|
||||
"extractionState" : "manual",
|
||||
"localizations" : {
|
||||
@@ -13361,52 +13407,6 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"Pencil hover" : {
|
||||
"extractionState" : "manual",
|
||||
"localizations" : {
|
||||
"zh-Hans" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "Pencil 悬停"
|
||||
}
|
||||
},
|
||||
"zh-Hant" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "Pencil 懸浮"
|
||||
}
|
||||
},
|
||||
"zh-HK" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "Pencil 懸浮"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"Pencil Pro Pack" : {
|
||||
"extractionState" : "manual",
|
||||
"localizations" : {
|
||||
"zh-Hans" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "Pencil 专业套装"
|
||||
}
|
||||
},
|
||||
"zh-Hant" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "Pencil 專業套裝"
|
||||
}
|
||||
},
|
||||
"zh-HK" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "Pencil 專業套裝"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"pencilKeyboardCmdURL" : {
|
||||
"extractionState" : "manual",
|
||||
"localizations" : {
|
||||
@@ -13436,6 +13436,35 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"pencilModeStackTip" : {
|
||||
"extractionState" : "manual",
|
||||
"localizations" : {
|
||||
"en" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "This function is available without purchasing [Drawing Toolkit]."
|
||||
}
|
||||
},
|
||||
"zh-Hans" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "此功能是Pencil基础功能的一部分,不属于Drawing Toolkit。 "
|
||||
}
|
||||
},
|
||||
"zh-Hant" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "此功能為 Pencil 基礎功能的一部分,不屬於 Drawing Toolkit。"
|
||||
}
|
||||
},
|
||||
"zh-HK" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "此功能為 Pencil 基礎功能的一部分,不屬於 Drawing Toolkit。"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"PencilProPackDescription" : {
|
||||
"extractionState" : "manual"
|
||||
},
|
||||
@@ -19123,6 +19152,35 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"X Offset" : {
|
||||
"extractionState" : "manual",
|
||||
"localizations" : {
|
||||
"en" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "X Offset"
|
||||
}
|
||||
},
|
||||
"zh-Hans" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "X 偏移"
|
||||
}
|
||||
},
|
||||
"zh-Hant" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "X 偏移"
|
||||
}
|
||||
},
|
||||
"zh-HK" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "X 偏移"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"X1" : {
|
||||
"extractionState" : "manual",
|
||||
"localizations" : {
|
||||
@@ -19169,58 +19227,6 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"X Offset" : {
|
||||
"extractionState" : "manual",
|
||||
"localizations" : {
|
||||
"en" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "X Offset"
|
||||
}
|
||||
},
|
||||
"zh-Hans" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "X 偏移"
|
||||
}
|
||||
},
|
||||
"zh-Hant" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "X 偏移"
|
||||
}
|
||||
},
|
||||
"zh-HK" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "X 偏移"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"Yaw factor: %.2f" : {
|
||||
"extractionState" : "manual",
|
||||
"localizations" : {
|
||||
"zh-Hans" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "偏航系数: %.2f"
|
||||
}
|
||||
},
|
||||
"zh-Hant" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "偏航係數: %.2f"
|
||||
}
|
||||
},
|
||||
"zh-HK" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "偏航係數: %.2f"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"Y Offset" : {
|
||||
"extractionState" : "manual",
|
||||
"localizations" : {
|
||||
@@ -19250,6 +19256,29 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"Yaw factor: %.2f" : {
|
||||
"extractionState" : "manual",
|
||||
"localizations" : {
|
||||
"zh-Hans" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "偏航系数: %.2f"
|
||||
}
|
||||
},
|
||||
"zh-Hant" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "偏航係數: %.2f"
|
||||
}
|
||||
},
|
||||
"zh-HK" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "偏航係數: %.2f"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"Yes" : {
|
||||
"extractionState" : "manual",
|
||||
"localizations" : {
|
||||
@@ -19359,4 +19388,4 @@
|
||||
}
|
||||
},
|
||||
"version" : "1.1"
|
||||
}
|
||||
}
|
||||
+38
-20
@@ -306,6 +306,7 @@ final class LayoutOnScreenControlsViewController: UIViewController, OnScreenWidg
|
||||
selectedWidget = nil
|
||||
widgetPanelStoredCenter = widgetPanelStack.center
|
||||
setupWidgetPanel()
|
||||
// print("loadingMode \(profileSelectorLoadingMode)")
|
||||
profileRefresh()
|
||||
if !toolbarStackView.isHidden {
|
||||
GenericUtils.handleLayoutToolTip(in: self)
|
||||
@@ -330,7 +331,7 @@ final class LayoutOnScreenControlsViewController: UIViewController, OnScreenWidg
|
||||
@objc func dummytest() {}
|
||||
|
||||
private func denormalizeWidgetPosition(_ position: CGPoint) -> CGPoint {
|
||||
guard position.x < 1.0, position.y < 1.0 else { return position }
|
||||
guard abs(position.x) < 2.01, abs(position.y) < 2.01 else { return position }
|
||||
return CGPoint(x: position.x * view.bounds.width, y: position.y * view.bounds.height)
|
||||
}
|
||||
|
||||
@@ -358,8 +359,10 @@ final class LayoutOnScreenControlsViewController: UIViewController, OnScreenWidg
|
||||
}
|
||||
|
||||
@objc func reloadOnScreenWidgetViews() {
|
||||
if self.profileSelectorLoadingMode == .selectProfileFromMainFrame { return }
|
||||
|
||||
|
||||
// if self.profileSelectorLoadingMode == .selectProfileFromMainFrame { return }
|
||||
guard self.profileSelectorLoadingMode == .selectProfileFromLayoutTool || self.profileSelectorLoadingMode == .selectProfileFromStreamView else { return }
|
||||
|
||||
OnScreenWidgetView.isTweakingHighlight = false
|
||||
OnScreenWidgetView.editMode = true
|
||||
|
||||
@@ -367,7 +370,20 @@ final class LayoutOnScreenControlsViewController: UIViewController, OnScreenWidg
|
||||
self.hideStickIndicators()
|
||||
self.clearOnScreenWidgets()
|
||||
|
||||
guard let oscProfile = self.profilesManager?.getSelectedProfile() else { return }
|
||||
var oscProfile: OSCProfile?
|
||||
|
||||
if let profileSelector = self.profileSelectorViewController, profileSelector.profiles.count > 0 {
|
||||
oscProfile = profileSelector.profiles[profileSelector.selectedProfileIndex] as? OSCProfile
|
||||
}
|
||||
else {
|
||||
oscProfile = self.profilesManager?.getSelectedProfile()
|
||||
}
|
||||
|
||||
guard let oscProfile = oscProfile else { return }
|
||||
|
||||
if self.profileSelectorLoadingMode == .selectProfileFromStreamView, oscProfile.name == "Default" {
|
||||
OnScreenWidgetView.disableFolderAnimation(for: 1)
|
||||
}
|
||||
|
||||
if self.profileSelectorLoadingMode == .selectProfileFromStreamView || self.profileSelectorLoadingMode == .pickProfile {
|
||||
NotificationCenter.default.post(name: Notification.Name("GameProfileSelectedNotification"), object: oscProfile)
|
||||
@@ -529,16 +545,18 @@ final class LayoutOnScreenControlsViewController: UIViewController, OnScreenWidg
|
||||
profileSelectorViewController?.layoutViewBounds = view.bounds
|
||||
profileSelectorViewController?.needToUpdateOscLayoutTVC = { [weak self] in
|
||||
guard let self else { return }
|
||||
if !loadJustTapped {
|
||||
// if !loadJustTapped {
|
||||
self.reloadOnScreenWidgetViews()
|
||||
}
|
||||
// }
|
||||
loadJustTapped = false
|
||||
self.profileSelectorViewController?.currentOSCButtonLayers = self.layoutOSC.oscButtonLayerPool
|
||||
}
|
||||
reloadOnScreenWidgetViews()
|
||||
if profileSelectorLoadingMode == .selectProfileFromLayoutTool {
|
||||
reloadOnScreenWidgetViews()
|
||||
}
|
||||
}
|
||||
|
||||
@objc var profileSelectorLoadingMode: ProfileSelectorLoadingMode = .selectProfile
|
||||
@objc var profileSelectorLoadingMode: ProfileSelectorLoadingMode = .selectProfileFromLayoutTool
|
||||
|
||||
@objc(presentProfileSelectorWithLoadingMode:)
|
||||
func presentProfileSelector(with loadingModeRawValue: Int) {
|
||||
@@ -562,18 +580,18 @@ final class LayoutOnScreenControlsViewController: UIViewController, OnScreenWidg
|
||||
if loadingMode != .pickProfileData {selectedWidget = nil}
|
||||
let controller = ProfileSelectorViewController()
|
||||
controller.layoutViewBounds = view.bounds
|
||||
controller.needToUpdateOscLayoutTVC = { [weak self] in
|
||||
guard let self else { return }
|
||||
if loadingMode == .selectProfile || loadingMode == .selectProfileFromStreamView || loadingMode == .pickProfile {
|
||||
self.reloadOnScreenWidgetViews()
|
||||
}
|
||||
}
|
||||
controller.currentOSCButtonLayers = layoutOSC.oscButtonLayerPool
|
||||
controller.modalPresentationStyle = .overCurrentContext
|
||||
controller.loadingMode = loadingMode
|
||||
controller.pickedProfileDataHandler = pickedProfileDataHandler
|
||||
widgetPanelStack.isHidden = true
|
||||
profileSelectorViewController = controller
|
||||
controller.needToUpdateOscLayoutTVC = { [weak self] in
|
||||
guard let self else { return }
|
||||
if loadingMode == .selectProfileFromLayoutTool || loadingMode == .selectProfileFromStreamView {
|
||||
self.reloadOnScreenWidgetViews()
|
||||
}
|
||||
}
|
||||
present(controller, animated: animated)
|
||||
}
|
||||
|
||||
@@ -581,7 +599,7 @@ final class LayoutOnScreenControlsViewController: UIViewController, OnScreenWidg
|
||||
@IBAction func loadTapped(_ sender: Any?) {
|
||||
// saveTapped(nil)
|
||||
loadJustTapped = true
|
||||
presentProfileSelector(with: .selectProfile)
|
||||
presentProfileSelector(with: .selectProfileFromLayoutTool)
|
||||
}
|
||||
|
||||
@IBAction func importFromOtherButtonTapped(_ sender: Any?) {
|
||||
@@ -659,7 +677,7 @@ final class LayoutOnScreenControlsViewController: UIViewController, OnScreenWidg
|
||||
super.viewWillTransition(to: size, with: coordinator)
|
||||
viewWillBeResized = true
|
||||
hideStickIndicators()
|
||||
if self.profileSelectorLoadingMode == .selectProfile {
|
||||
if self.profileSelectorLoadingMode == .selectProfileFromLayoutTool {
|
||||
|
||||
let oldSize = view.bounds.size
|
||||
let scaleX = size.width / oldSize.width
|
||||
@@ -842,7 +860,7 @@ final class LayoutOnScreenControlsViewController: UIViewController, OnScreenWidg
|
||||
|
||||
private func refreshPanelForSelectedWidget(_ widgetView: OnScreenWidgetView) {
|
||||
// hideStickIndicators()
|
||||
if OnScreenWidgetView.gamepadArrivalReported {clearSickInput()}
|
||||
if ControllerUtil.gamepadArrivalReported {clearSickInput()}
|
||||
enableCommonWidgetTools()
|
||||
widgetViewSelected = true
|
||||
controllerLayerSelected = false
|
||||
@@ -1587,7 +1605,7 @@ final class LayoutOnScreenControlsViewController: UIViewController, OnScreenWidg
|
||||
}
|
||||
|
||||
private func clearSickInput() {
|
||||
if selectedWidget != nil && widgetViewSelected && OnScreenWidgetView.gamepadArrivalReported {
|
||||
if selectedWidget != nil && widgetViewSelected && ControllerUtil.gamepadArrivalReported {
|
||||
OnScreenControls.shared()?.clearLeftStickTouchPadFlag()
|
||||
OnScreenControls.shared()?.clearRightStickTouchPadFlag()
|
||||
}
|
||||
@@ -1632,7 +1650,7 @@ final class LayoutOnScreenControlsViewController: UIViewController, OnScreenWidg
|
||||
@objc private func handleProfileSelectorDismiss() {
|
||||
|
||||
switch profileSelectorLoadingMode {
|
||||
case .selectProfile:
|
||||
case .selectProfileFromLayoutTool:
|
||||
if profileSelectorViewController?.loadingMode != .pickProfileData {
|
||||
setupWidgetPanel()
|
||||
}
|
||||
@@ -1721,7 +1739,7 @@ final class LayoutOnScreenControlsViewController: UIViewController, OnScreenWidg
|
||||
}
|
||||
|
||||
private func setupWidgetPanel() {
|
||||
widgetPanelStack.isHidden = profileSelectorLoadingMode != .selectProfile
|
||||
widgetPanelStack.isHidden = profileSelectorLoadingMode != .selectProfileFromLayoutTool
|
||||
tipTitleLabel.textAlignment = .left
|
||||
tipTitleLabel.contentMode = .top
|
||||
tipTitleLabel.lineBreakMode = .byWordWrapping
|
||||
|
||||
+8
-7
@@ -274,7 +274,7 @@ private extension UInt64 {
|
||||
}
|
||||
|
||||
@objc enum ProfileSelectorLoadingMode: Int {
|
||||
case selectProfile
|
||||
case selectProfileFromLayoutTool
|
||||
case selectProfileFromStreamView
|
||||
case selectProfileFromMainFrame
|
||||
case pickProfile
|
||||
@@ -287,15 +287,15 @@ final class ProfileSelectorViewController: UIViewController, UICollectionViewDat
|
||||
var currentFileOperation: FileOperation = .importOperation
|
||||
private var currentExportScope: ProfileExportScope = .allProfiles
|
||||
var needToUpdateOscLayoutTVC: (() -> Void)?
|
||||
var loadingMode: ProfileSelectorLoadingMode = .selectProfile
|
||||
var loadingMode: ProfileSelectorLoadingMode = .selectProfileFromLayoutTool
|
||||
@nonobjc var pickedProfileDataHandler: ((OSCProfile) -> Void)?
|
||||
weak var currentOSCButtonLayers: NSMutableSet?
|
||||
var layoutViewBounds: CGRect = .zero
|
||||
|
||||
private var profilesManager: OSCProfilesManager!
|
||||
private var horizontalConstraintsConfigured = false
|
||||
private var profiles: NSMutableArray = []
|
||||
private var selectedProfileIndex = 0
|
||||
private(set) var profiles: NSMutableArray = []
|
||||
private(set) var selectedProfileIndex = 0
|
||||
private var profilesLoadGeneration = 0
|
||||
private var profileCollectionView: UICollectionView!
|
||||
private let contentView = UIView()
|
||||
@@ -448,8 +448,9 @@ final class ProfileSelectorViewController: UIViewController, UICollectionViewDat
|
||||
}
|
||||
if profiles.count > 0 {
|
||||
scrollToSelectedProfile(animated: true)
|
||||
notifyProfileViewDidRefresh()
|
||||
} else {
|
||||
reloadProfilesAsync(scrollToSelected: true)
|
||||
reloadProfilesAsync(scrollToSelected: true, notify: true)
|
||||
}
|
||||
|
||||
if (loadingMode == .selectProfileFromMainFrame || loadingMode == .selectProfileFromStreamView)
|
||||
@@ -748,7 +749,7 @@ final class ProfileSelectorViewController: UIViewController, UICollectionViewDat
|
||||
if loadingMode != .selectProfileFromStreamView
|
||||
&& loadingMode != .pickProfile
|
||||
&& loadingMode != .pickProfileData
|
||||
&& loadingMode != .selectProfile
|
||||
&& loadingMode != .selectProfileFromLayoutTool
|
||||
{
|
||||
guard let selectedProfileIndex = validProfileIndex(selectedProfileIndex) else { return }
|
||||
NotificationCenter.default.post(name: Notification.Name("GameProfileSelectedNotification"), object: self.profiles[selectedProfileIndex])
|
||||
@@ -1189,7 +1190,7 @@ final class ProfileSelectorViewController: UIViewController, UICollectionViewDat
|
||||
}
|
||||
|
||||
func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldReceive touch: UITouch) -> Bool {
|
||||
if (loadingMode != .selectProfile
|
||||
if (loadingMode != .selectProfileFromLayoutTool
|
||||
&& loadingMode != .selectProfileFromMainFrame
|
||||
&& loadingMode != .selectProfileFromStreamView
|
||||
),
|
||||
|
||||
@@ -306,8 +306,8 @@
|
||||
@property (weak, nonatomic) IBOutlet UIStackView *disablePencilSlideGestureStack;
|
||||
@property (weak, nonatomic) IBOutlet UISwitch *disablePencilSlideGestureSwitch;
|
||||
|
||||
@property (weak, nonatomic) IBOutlet UIStackView *hoverModeStack;
|
||||
@property (weak, nonatomic) IBOutlet UISegmentedControl *hoverModeSelector;
|
||||
@property (weak, nonatomic) IBOutlet UIStackView *pencilModeStack;
|
||||
@property (weak, nonatomic) IBOutlet UISegmentedControl *pencilModeSelector;
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -434,7 +434,7 @@ BOOL isCustomResolution(int resolutionSelected) {
|
||||
[self.squeezeShortcutSwitch setOn:oscProfile.squeezeShorcutEnabled];
|
||||
[self.pencilPausesNativeTouchSwitch setOn:oscProfile.pencilPausesNativeTouch];
|
||||
[self.disablePencilSlideGestureSwitch setOn:oscProfile.disablePencilSlideGestures];
|
||||
self.hoverModeSelector.selectedSegmentIndex = oscProfile.pencilHoverMode;
|
||||
self.pencilModeSelector.selectedSegmentIndex = oscProfile.pencilAndHoverMode;
|
||||
}
|
||||
|
||||
- (void)saveGameProfileConfigs{
|
||||
@@ -472,7 +472,7 @@ BOOL isCustomResolution(int resolutionSelected) {
|
||||
&& oscProfile.squeezeShorcutEnabled == self.squeezeShortcutSwitch.isOn
|
||||
&& oscProfile.pencilPausesNativeTouch == self.pencilPausesNativeTouchSwitch.isOn
|
||||
&& oscProfile.disablePencilSlideGestures == self.disablePencilSlideGestureSwitch.isOn
|
||||
&& oscProfile.pencilHoverMode == self.hoverModeSelector.selectedSegmentIndex
|
||||
&& oscProfile.pencilAndHoverMode == self.pencilModeSelector.selectedSegmentIndex
|
||||
);
|
||||
|
||||
if(!configNotChanged){
|
||||
@@ -499,12 +499,12 @@ BOOL isCustomResolution(int resolutionSelected) {
|
||||
oscProfile.squeezeShorcutEnabled = self.squeezeShortcutSwitch.isOn;
|
||||
oscProfile.pencilPausesNativeTouch = self.pencilPausesNativeTouchSwitch.isOn;
|
||||
oscProfile.disablePencilSlideGestures = self.disablePencilSlideGestureSwitch.isOn;
|
||||
oscProfile.pencilHoverMode = self.hoverModeSelector.selectedSegmentIndex;
|
||||
oscProfile.pencilAndHoverMode = self.pencilModeSelector.selectedSegmentIndex;
|
||||
[oscProfileMan replaceSelectedProfileWith:oscProfile overwriteDefault:YES];
|
||||
if(PencilHandler.shared) [PencilHandler.shared setupPressureLUTWithProfile:oscProfile];
|
||||
}
|
||||
|
||||
if(!leftStickMinOffsetSliderNotMoved || !rightStickMinOffsetSliderNotMoved || OnScreenWidgetView.gamepadArrivalReported){
|
||||
if(!leftStickMinOffsetSliderNotMoved || !rightStickMinOffsetSliderNotMoved || ControllerUtil.gamepadArrivalReported){
|
||||
if(OnScreenControls.shared){
|
||||
[OnScreenControls.shared clearLeftStickTouchPadFlag];
|
||||
[OnScreenControls.shared clearRightStickTouchPadFlag];
|
||||
@@ -1087,9 +1087,9 @@ BOOL isCustomResolution(int resolutionSelected) {
|
||||
self.squeezeShortcutStack.hasInfoTag = YES;
|
||||
[self addSetting:self.squeezeShortcutStack ofId:@"squeezeShortcutStack" to:pencilSection];
|
||||
|
||||
self.hoverModeStack.isGameProfileSetting = YES;
|
||||
self.hoverModeStack.hasInfoTag = YES;
|
||||
[self addSetting:self.hoverModeStack ofId:@"hoverModeStack" to:pencilSection];
|
||||
self.pencilModeStack.isGameProfileSetting = YES;
|
||||
self.pencilModeStack.hasInfoTag = YES;
|
||||
[self addSetting:self.pencilModeStack ofId:@"pencilModeStack" to:pencilSection];
|
||||
|
||||
self.pencilPausesNativeTouchStack.isGameProfileSetting = YES;
|
||||
[self addSetting:self.pencilPausesNativeTouchStack ofId:@"pencilPausesNativeTouchStack" to:pencilSection];
|
||||
@@ -1799,8 +1799,8 @@ BOOL isCustomResolution(int resolutionSelected) {
|
||||
tipText = [LocalizationHelper localizedStringForKey:@"asyncFrameDequeueStackTip"];
|
||||
showOnlineDocAction = false;
|
||||
}
|
||||
if([sender.superview.accessibilityIdentifier isEqualToString: @"hoverModeStack"]){
|
||||
tipText = [LocalizationHelper localizedStringForKey:@"hoverModeStackTip"];
|
||||
if([sender.superview.accessibilityIdentifier isEqualToString: @"pencilModeStack"]){
|
||||
tipText = [LocalizationHelper localizedStringForKey:@"pencilModeStackTip"];
|
||||
showOnlineDocAction = false;
|
||||
}
|
||||
if([sender.superview.accessibilityIdentifier isEqualToString: @"pencilTickStack"]){
|
||||
@@ -3107,7 +3107,7 @@ BOOL isCustomResolution(int resolutionSelected) {
|
||||
rightButtonCaptured = true;
|
||||
|
||||
if (@available(iOS 13.0, *)) {
|
||||
NSLog(@"custom posistion local %d , stream: %d", currentSettings.customLocalRadialMenuButtonPosition.intValue, currentSettings.customStreamingRadialMenuButtonPosition.intValue);
|
||||
// NSLog(@"custom posistion local %d , stream: %d", currentSettings.customLocalRadialMenuButtonPosition.intValue, currentSettings.customStreamingRadialMenuButtonPosition.intValue);
|
||||
|
||||
ControllerNavigator.localRadialMenuButton = (ControllerElement)currentSettings.localRadialMenuButton.intValue;
|
||||
ControllerNavigator.customPositionForLocalRadialMenuButton = (ControllerElementPosition)currentSettings.customLocalRadialMenuButtonPosition.intValue;
|
||||
@@ -3196,21 +3196,21 @@ BOOL isCustomResolution(int resolutionSelected) {
|
||||
[self findDynamicLabelFromStack:(UIStackView*)sender.superview].text = [NSString stringWithFormat:@" %d ", (int16_t)sender.value];
|
||||
if(settingsViewJustExpanded) return;
|
||||
LiSendControllerEvent(0, 0, 0, _rollToLeftStickSwitch.isOn?sender.value:0, 0, _yawPitchToRightStickSwitch.isOn?sender.value:0, 0);
|
||||
OnScreenWidgetView.gamepadArrivalReported = true;
|
||||
ControllerUtil.gamepadArrivalReported = true;
|
||||
}
|
||||
|
||||
- (void)leftStickMinOffsetSliderMoved:(UISlider* )sender{
|
||||
[self findDynamicLabelFromStack:(UIStackView*)sender.superview].text = [NSString stringWithFormat:@" %d ", (int16_t)sender.value];
|
||||
if(settingsViewJustExpanded) return;
|
||||
LiSendControllerEvent(0, 0, 0, sender.value, 0, 0, 0);
|
||||
OnScreenWidgetView.gamepadArrivalReported = true;
|
||||
ControllerUtil.gamepadArrivalReported = true;
|
||||
}
|
||||
|
||||
- (void)rightStickMinOffsetSliderMoved:(UISlider* )sender{
|
||||
[self findDynamicLabelFromStack:(UIStackView*)sender.superview].text = [NSString stringWithFormat:@" %d ", (int16_t)sender.value];
|
||||
if(settingsViewJustExpanded) return;
|
||||
LiSendControllerEvent(0, 0, 0, 0, 0, sender.value, 0);
|
||||
OnScreenWidgetView.gamepadArrivalReported = true;
|
||||
ControllerUtil.gamepadArrivalReported = true;
|
||||
}
|
||||
|
||||
- (void)invokeOscLayout{
|
||||
@@ -4247,8 +4247,10 @@ BOOL isCustomResolution(int resolutionSelected) {
|
||||
|
||||
CGFloat settingsMenuOffset = _rememberFoldStateSwitch.isOn ? _scrollView.contentOffset.y : 0;
|
||||
|
||||
NSInteger height = self.mainFrameViewController.settingsExpandedInStreamView ? currentSettings.height.intValue : [self getChosenStreamHeight];
|
||||
NSInteger width = self.mainFrameViewController.settingsExpandedInStreamView ? currentSettings.width.intValue : [self getChosenStreamWidth];
|
||||
NSInteger height = self.mainFrameViewController.isStreaming ? currentSettings.height.intValue : [self getChosenStreamHeight];
|
||||
NSInteger width = self.mainFrameViewController.isStreaming ? currentSettings.width.intValue : [self getChosenStreamWidth];
|
||||
|
||||
// NSLog(@"saveSettings aspectRatio %d, %ld, %ld",self.mainFrameViewController.isStreaming, width, height);
|
||||
|
||||
NSInteger framerate = [self getChosenFrameRate];
|
||||
|
||||
|
||||
@@ -47,6 +47,9 @@
|
||||
@property (nonatomic, assign) CGPoint streamViewMagnifierContentOffset;
|
||||
@property (nonatomic, assign) CGFloat streamViewMagnifierZoomScale;
|
||||
|
||||
@property(nonatomic, assign) bool touchDisabled;
|
||||
@property(nonatomic, assign) bool singleTouchDisabled;
|
||||
|
||||
|
||||
+ (StreamFrameViewController *)sharedInstance;
|
||||
|
||||
|
||||
@@ -41,6 +41,7 @@
|
||||
@interface AVDisplayCriteria()
|
||||
@property(readonly) int videoDynamicRange;
|
||||
@property(readonly, nonatomic) float refreshRate;
|
||||
|
||||
- (id)initWithRefreshRate:(float)arg1 videoDynamicRange:(int)arg2;
|
||||
@end
|
||||
|
||||
@@ -127,6 +128,7 @@ static __weak StreamFrameViewController *VLSharedStreamFrameViewController = nil
|
||||
MicHandler* micHandler;
|
||||
MotionHandler *_motionHandler;
|
||||
|
||||
|
||||
#else
|
||||
UITapGestureRecognizer *_menuTapGestureRecognizer;
|
||||
UITapGestureRecognizer *_menuDoubleTapGestureRecognizer;
|
||||
@@ -857,12 +859,15 @@ static __weak StreamFrameViewController *VLSharedStreamFrameViewController = nil
|
||||
viewIsBeingResized = false;
|
||||
_magnifierViewportInteractionActive = false;
|
||||
|
||||
_touchDisabled = false;
|
||||
_singleTouchDisabled = false;
|
||||
|
||||
[super viewDidLoad];
|
||||
|
||||
|
||||
[self.navigationController setNavigationBarHidden:YES animated:YES];
|
||||
|
||||
[UIApplication sharedApplication].idleTimerDisabled = YES;
|
||||
|
||||
|
||||
_settings = [[[DataManager alloc] init] getSettings]; //StreamFrameViewController retrieve the settings here.
|
||||
|
||||
_stageLabel = [[UILabel alloc] init];
|
||||
@@ -898,9 +903,9 @@ static __weak StreamFrameViewController *VLSharedStreamFrameViewController = nil
|
||||
|
||||
toolBoxViewController = [[ToolboxViewController alloc] init];
|
||||
toolBoxViewController.specialEntryDelegate = self;
|
||||
|
||||
|
||||
_isRestoringFromPiP = NO;
|
||||
|
||||
|
||||
/*
|
||||
_settings.externalDisplayMode.intValue:
|
||||
0 - stage manager
|
||||
@@ -915,12 +920,12 @@ static __weak StreamFrameViewController *VLSharedStreamFrameViewController = nil
|
||||
[self reConfigStreamViewRealtime]; // call this method again to make sure all gestures are configured & added to the superview(self.view), including the gestures added from inside the streamview.
|
||||
|
||||
if([self isFirstStreaming] || GenericUtils.isFirstStreamingOnMac) [self popFirstStreamingTip];
|
||||
|
||||
|
||||
#if TARGET_OS_TV
|
||||
if (!_menuTapGestureRecognizer || !_menuDoubleTapGestureRecognizer || !_playPauseTapGestureRecognizer) {
|
||||
_menuTapGestureRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(controllerPauseButtonPressed:)];
|
||||
_menuTapGestureRecognizer.allowedPressTypes = @[@(UIPressTypeMenu)];
|
||||
|
||||
|
||||
_playPauseTapGestureRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(controllerPlayPauseButtonPressed:)];
|
||||
_playPauseTapGestureRecognizer.allowedPressTypes = @[@(UIPressTypePlayPause)];
|
||||
|
||||
@@ -933,7 +938,7 @@ static __weak StreamFrameViewController *VLSharedStreamFrameViewController = nil
|
||||
[self.view addGestureRecognizer:_menuTapGestureRecognizer];
|
||||
[self.view addGestureRecognizer:_menuDoubleTapGestureRecognizer];
|
||||
[self.view addGestureRecognizer:_playPauseTapGestureRecognizer];
|
||||
|
||||
|
||||
#else
|
||||
//[self configSwipeGestures]; // swipe & exit gesture configured here
|
||||
//[self configOscLayoutTool]; //_oscLayoutTapRecoginizer will be added or removed to the view here
|
||||
@@ -978,7 +983,7 @@ static __weak StreamFrameViewController *VLSharedStreamFrameViewController = nil
|
||||
selector:@selector(gameProfileSelectorClosed)
|
||||
name:@"GameProfileSelectorCloseNotification"
|
||||
object:nil];
|
||||
|
||||
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self
|
||||
selector:@selector(handleStreamAspectRatioChanged:)
|
||||
name:@"StreamAspectRatioChanged"
|
||||
@@ -1008,13 +1013,13 @@ static __weak StreamFrameViewController *VLSharedStreamFrameViewController = nil
|
||||
[self.view addSubview:_stageLabel];
|
||||
[self.view addSubview:_spinner];
|
||||
[self.view addSubview:_tipLabel];
|
||||
|
||||
|
||||
if ([_settings.renderingBackend intValue] == RENDER_METAL) {
|
||||
// Metal view for video
|
||||
Log(LOG_I, @"StreamFrameViewController creating MetalViewController");
|
||||
self.metalViewController = [[MetalViewController alloc] initWithFrame:self.view.bounds
|
||||
framerate:[self->_settings.framerate floatValue]
|
||||
settings:self->_settings
|
||||
settings:self->_settings
|
||||
metricsHandler:self.imguiView.metricsHandler];
|
||||
self.metalViewController.view.userInteractionEnabled = NO;
|
||||
[self addChildViewController:self.metalViewController];
|
||||
@@ -1022,14 +1027,10 @@ static __weak StreamFrameViewController *VLSharedStreamFrameViewController = nil
|
||||
[self.view insertSubview:self.metalViewController.view atIndex:0];
|
||||
[self.metalViewController didMoveToParentViewController:self];
|
||||
}
|
||||
|
||||
OnScreenWidgetView.gamepadArrivalReported = false;
|
||||
|
||||
OnScreenWidgetView.enableFolderAnimation = false;
|
||||
dispatch_time_t delay = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC));
|
||||
dispatch_after(delay, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
|
||||
OnScreenWidgetView.enableFolderAnimation = true;
|
||||
});
|
||||
ControllerUtil.gamepadArrivalReported = false;
|
||||
|
||||
[OnScreenWidgetView disableFolderAnimationFor:2];
|
||||
}
|
||||
|
||||
- (void)keyboardWillShow:(NSNotification *)notification{
|
||||
@@ -1074,6 +1075,7 @@ static __weak StreamFrameViewController *VLSharedStreamFrameViewController = nil
|
||||
_layoutOnScreenControlsVC.toolbarStackView.hidden = true;
|
||||
_layoutOnScreenControlsVC.toolbarRootView.hidden = true;
|
||||
ProfileSelectorLoadingMode loadingMode = pickProfile ? ProfileSelectorLoadingModePickProfile : ProfileSelectorLoadingModeSelectProfileFromStreamView;
|
||||
_layoutOnScreenControlsVC.profileSelectorLoadingMode = loadingMode;
|
||||
[self presentViewController:_layoutOnScreenControlsVC animated:NO completion:^{
|
||||
[self->_layoutOnScreenControlsVC presentProfileSelectorWith:loadingMode animated:false];
|
||||
}];
|
||||
@@ -1198,6 +1200,7 @@ static __weak StreamFrameViewController *VLSharedStreamFrameViewController = nil
|
||||
// [self->_streamView reloadLegacyWidgets];
|
||||
[self reConfigStreamViewRealtimeAndReloadSettings:NO reloadOnscreenWidgets:_settings.onscreenControls.intValue == OnScreenControlsLevelCustom];
|
||||
// [self->_streamView reloadGameProfile:nil reloadWidgets:true]; //update keyboard buttons here
|
||||
[OnScreenWidgetView disableFolderAnimationFor:2];
|
||||
}
|
||||
|
||||
- (void)handleStreamAspectRatioChanged:(NSNotification *)notification {
|
||||
@@ -2111,8 +2114,8 @@ static __weak StreamFrameViewController *VLSharedStreamFrameViewController = nil
|
||||
[_streamView disablePencilHover];
|
||||
}
|
||||
|
||||
- (void)setAllowSingleTouchEnabled:(BOOL)enabled{
|
||||
[_streamView setAllowSingleTouchEnabled:enabled];
|
||||
- (void)handleDisableSingleTouchButtonUp {
|
||||
[_streamView setAllowSingleTouchEnabled:!_singleTouchDisabled];
|
||||
}
|
||||
|
||||
- (void)replaceBrushWithShortcut:(NSString *)shortcut{
|
||||
@@ -2127,8 +2130,8 @@ static __weak StreamFrameViewController *VLSharedStreamFrameViewController = nil
|
||||
}
|
||||
}
|
||||
|
||||
- (void)toggleTouchWithDisabled:(BOOL)disabled{
|
||||
[_streamView toggleTouchDisabled:disabled];
|
||||
- (void)handleTouchDisableButtonUp {
|
||||
[_streamView toggleTouchDisabled:self.touchDisabled];
|
||||
}
|
||||
|
||||
- (void)presentPressureCurveVC{
|
||||
|
||||
@@ -2648,30 +2648,30 @@
|
||||
}
|
||||
},
|
||||
"DhB-EF-mDt.text" : {
|
||||
"comment" : "Class = \"UILabel\"; text = \"Hover Mode\"; ObjectID = \"DhB-EF-mDt\";",
|
||||
"comment" : "Class = \"UILabel\"; text = \"Pencil Mode\"; ObjectID = \"DhB-EF-mDt\";",
|
||||
"extractionState" : "extracted_with_value",
|
||||
"localizations" : {
|
||||
"en" : {
|
||||
"stringUnit" : {
|
||||
"state" : "new",
|
||||
"value" : "Hover Mode"
|
||||
"value" : "Pencil Mode"
|
||||
}
|
||||
},
|
||||
"zh-Hans" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"state" : "needs_review",
|
||||
"value" : "悬停模式"
|
||||
}
|
||||
},
|
||||
"zh-Hant" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"state" : "needs_review",
|
||||
"value" : "懸停模式"
|
||||
}
|
||||
},
|
||||
"zh-HK" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"state" : "needs_review",
|
||||
"value" : "懸停模式"
|
||||
}
|
||||
}
|
||||
@@ -6311,31 +6311,31 @@
|
||||
}
|
||||
},
|
||||
"t12-bo-icS.segmentTitles[0]" : {
|
||||
"comment" : "Class = \"UISegmentedControl\"; t12-bo-icS.segmentTitles[0] = \"Disabled\"; ObjectID = \"t12-bo-icS\";",
|
||||
"comment" : "Class = \"UISegmentedControl\"; t12-bo-icS.segmentTitles[0] = \"Hovering Disabled\"; ObjectID = \"t12-bo-icS\";",
|
||||
"extractionState" : "extracted_with_value",
|
||||
"localizations" : {
|
||||
"en" : {
|
||||
"stringUnit" : {
|
||||
"state" : "new",
|
||||
"value" : "Disabled"
|
||||
"value" : "Hovering Disabled"
|
||||
}
|
||||
},
|
||||
"zh-Hans" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "关闭"
|
||||
"value" : "关闭悬停"
|
||||
}
|
||||
},
|
||||
"zh-Hant" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "關閉"
|
||||
"value" : "關閉懸停"
|
||||
}
|
||||
},
|
||||
"zh-HK" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "關閉"
|
||||
"value" : "關閉懸停"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -6401,31 +6401,31 @@
|
||||
}
|
||||
},
|
||||
"t12-bo-icS.segmentTitles[3]" : {
|
||||
"comment" : "Class = \"UISegmentedControl\"; t12-bo-icS.segmentTitles[3] = \"Both\"; ObjectID = \"t12-bo-icS\";",
|
||||
"comment" : "Class = \"UISegmentedControl\"; t12-bo-icS.segmentTitles[3] = \"Touch\"; ObjectID = \"t12-bo-icS\";",
|
||||
"extractionState" : "extracted_with_value",
|
||||
"localizations" : {
|
||||
"en" : {
|
||||
"stringUnit" : {
|
||||
"state" : "new",
|
||||
"value" : "Both"
|
||||
"value" : "Touch"
|
||||
}
|
||||
},
|
||||
"zh-Hans" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "同时悬停"
|
||||
"value" : "触控"
|
||||
}
|
||||
},
|
||||
"zh-Hant" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "同時懸停"
|
||||
"value" : "觸控"
|
||||
}
|
||||
},
|
||||
"zh-HK" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "同時懸停"
|
||||
"value" : "觸控"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -7284,4 +7284,4 @@
|
||||
}
|
||||
},
|
||||
"version" : "1.0"
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user