diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml index 21b3a322..f36891b3 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.yml +++ b/.github/ISSUE_TEMPLATE/bug_report.yml @@ -17,7 +17,7 @@ body: attributes: label: The log file and images/videos description: | - The log file called `latestlog.txt` is located under `/var/mobile/Documents/.pojavlauncher`. You will need to enable Hidden Files and Folders in Filza to see the .pojavlauncher directory. | + The log file called `latestlog.txt` is located under `/usr/share/pojavlauncher`. | You can also upload here screenshots or videos of the buggy behavior, if possible. Tip: You can attach files by clicking this area to highlight it and then dragging files in or select them on 🖼 option at the toolbar. diff --git a/.github/ISSUE_TEMPLATE/informational.yml b/.github/ISSUE_TEMPLATE/informational.yml index 4b5222ea..b7e05af0 100644 --- a/.github/ISSUE_TEMPLATE/informational.yml +++ b/.github/ISSUE_TEMPLATE/informational.yml @@ -3,16 +3,6 @@ description: 'Quick docs, when they are needed.' title: "[Info] " labels: [documentation] body: -- type: textarea - id: version - attributes: - label: Describe the bug - description: | - A clear and concise description of what the bug is. - placeholder: 'Example: Login results in a crash' - validations: - required: true - - type: textarea attributes: label: Add some background diff --git a/.github/workflows/development.yml b/.github/workflows/development.yml index 9304db57..461ff823 100644 --- a/.github/workflows/development.yml +++ b/.github/workflows/development.yml @@ -5,7 +5,7 @@ on: jobs: build: - name: The guts + name: Development build runs-on: macOS-11 steps: - name: Set up cache @@ -19,7 +19,7 @@ jobs: - name: Set up build environment uses: maxim-lobanov/setup-xcode@v1 with: - xcode-version: '12.5.1' + xcode-version: '13.2.1' - name: Set up build environment pt. II uses: actions/checkout@v2 @@ -48,15 +48,12 @@ jobs: sudo mkdir -p ~/__cache/procursus/var/cache/apt/archives/partial ~/__cache/procursus/var/lib/apt/lists/partial sudo rsync -aP ~/__cache/procursus /opt sudo /opt/procursus/bin/apt-get update - sudo /opt/procursus/bin/apt-get -V dist-upgrade -y + sudo /opt/procursus/bin/apt-get -V dist-upgrade -y || : sudo /opt/procursus/bin/apt-get -V dist-upgrade -y - name: Build the Debian package run: gmake -j$(sysctl -n hw.ncpu) dsym - - name: Generate dSYM for PojavLauncher - run: dsymutil --arch arm64 Natives/build/PojavLauncher.app/PojavLauncher - - name: Upload regular artifact uses: actions/upload-artifact@v2 with: @@ -73,7 +70,7 @@ jobs: uses: actions/upload-artifact@v2 with: name: PojavLauncher.dSYM - path: Natives/build/PojavLauncher.app/PojavLauncher.dSYM + path: artifacts/PojavLauncher.dSYM - name: Copy Procursus to Cache Location run: | diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 632172ce..3a53c2ed 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -5,7 +5,7 @@ on: jobs: build: - name: The guts + name: Release build runs-on: macOS-11 steps: - name: Set up cache @@ -19,7 +19,7 @@ jobs: - name: Set up build environment uses: maxim-lobanov/setup-xcode@v1 with: - xcode-version: '12.5.1' + xcode-version: '13.2.1' - name: Set up build environment pt. II uses: actions/checkout@v2 @@ -53,10 +53,7 @@ jobs: - name: Build the Debian package run: gmake -j$(sysctl -n hw.ncpu) dsym RELEASE=1 - - - name: Generate dSYM for PojavLauncher - run: dsymutil --arch arm64 Natives/build/PojavLauncher.app/PojavLauncher - + - name: Upload regular artifact uses: actions/upload-artifact@v2 with: @@ -73,7 +70,7 @@ jobs: uses: actions/upload-artifact@v2 with: name: PojavLauncher.dSYM - path: Natives/build/PojavLauncher.app/PojavLauncher.dSYM + path: artifacts/PojavLauncher.dSYM - name: Copy Procursus to Cache Location run: | diff --git a/.gitignore b/.gitignore index 09275183..652f2ade 100644 --- a/.gitignore +++ b/.gitignore @@ -8,5 +8,3 @@ /Natives/resources/*.png .DS_Store /pojavlauncher.xcodeproj -/Natives/resources/Frameworks/libvgpu.dylib - diff --git a/DEBIAN/postinst b/DEBIAN/postinst index 62693fe2..0c449a0c 100755 --- a/DEBIAN/postinst +++ b/DEBIAN/postinst @@ -1,7 +1,5 @@ #!/bin/sh -set -e - if [ -d '/private/preboot/procursus' ]; then export PREFIX=/private/preboot/procursus fi diff --git a/JavaApp/libs/arc_dns_injector.jar b/JavaApp/libs/arc_dns_injector.jar new file mode 100644 index 00000000..3c9ddd6b Binary files /dev/null and b/JavaApp/libs/arc_dns_injector.jar differ diff --git a/JavaApp/src/main/java/com/mojang/text2speech/Text2Speech.java b/JavaApp/src/main/java/com/mojang/text2speech/Text2Speech.java index 3d503e77..959d7083 100644 --- a/JavaApp/src/main/java/com/mojang/text2speech/Text2Speech.java +++ b/JavaApp/src/main/java/com/mojang/text2speech/Text2Speech.java @@ -2,16 +2,5 @@ package com.mojang.text2speech; public class Text2Speech { public static void main(final String[] args) { - System.setProperty("jna.library.path", "./src/natives/resources/"); - final Narrator narrator = Narrator.getNarrator(); - narrator.say("This is a test", false); - - while (true) { - try { - Thread.sleep(100); - } catch (final InterruptedException e) { - e.printStackTrace(); - } - } } } diff --git a/JavaApp/src/main/java/net/kdt/pojavlaunch/JMinecraftVersionList.java b/JavaApp/src/main/java/net/kdt/pojavlaunch/JMinecraftVersionList.java index 98a757d1..65f1d2ed 100644 --- a/JavaApp/src/main/java/net/kdt/pojavlaunch/JMinecraftVersionList.java +++ b/JavaApp/src/main/java/net/kdt/pojavlaunch/JMinecraftVersionList.java @@ -12,51 +12,63 @@ public class JMinecraftVersionList { public Map latest; public Version[] versions; - public static class Version { - // Since 1.13, so it's one of ways to check - public Arguments arguments; + public static class FileProperties { + public String id, sha1, url; + public long size; + } + + public static class Version extends FileProperties { + // Since 1.13, so it's one of ways to check + public Arguments arguments; public AssetIndex assetIndex; public String assets; - public Map downloads; - public String id; - public String inheritsFrom; - public JavaVersionInfo javaVersion; - public DependentLibrary[] libraries; - public String mainClass; - public String minecraftArguments; - public int minimumLauncherVersion; - public DependentLibrary optifineLib; + public Map downloads; + public String inheritsFrom; + public JavaVersionInfo javaVersion; + public DependentLibrary[] libraries; + public LoggingConfig logging; + public String mainClass; + public String minecraftArguments; + public int minimumLauncherVersion; + public DependentLibrary optifineLib; public String releaseTime; public String time; public String type; - public String url; } public static class JavaVersionInfo { public String component; public int majorVersion; } - // Since 1.13 - public static class Arguments { - public Object[] game; - public Object[] jvm; + public static class LoggingConfig { + public LoggingClientConfig client; - public static class ArgValue { - public ArgRules[] rules; - public String value; + public static class LoggingClientConfig { + public String argument; + public FileProperties file; + public String type; + } + } + // Since 1.13 + public static class Arguments { + public Object[] game; + public Object[] jvm; + + public static class ArgValue { + public ArgRules[] rules; + public String value; // TLauncher styled argument... public String[] values; - public static class ArgRules { - public String action; - public String features; - } - } - } - public static class AssetIndex { - public String id, sha1, url; - public long size, totalSize; + public static class ArgRules { + public String action; + public String features; + } + } + } + public static class AssetIndex extends FileProperties { + public long totalSize; } } diff --git a/JavaApp/src/main/java/net/kdt/pojavlaunch/PLaunchApp.java b/JavaApp/src/main/java/net/kdt/pojavlaunch/PLaunchApp.java index e83e8ac8..ed7870a3 100644 --- a/JavaApp/src/main/java/net/kdt/pojavlaunch/PLaunchApp.java +++ b/JavaApp/src/main/java/net/kdt/pojavlaunch/PLaunchApp.java @@ -40,10 +40,38 @@ public class PLaunchApp { UIKit.launchUI(); } + public static String getSelectedVersion() { + try { + String plistContent = Tools.read(Tools.DIR_APP_DATA + "/launcher_preferences.plist"); + plistContent = plistContent.substring(plistContent.indexOf("selected_version") + 27); + return plistContent.substring( + plistContent.indexOf("") + 8, + plistContent.indexOf("")); + } catch (IOException e) { + e.printStackTrace(); + return null; + } + } + // Called from SurfaceViewController public static void launchMinecraft() { - System.out.println("Launching Minecraft " + mVersion.id); try { + if (AccountJNI.CURRENT_ACCOUNT == null) { + AccountJNI.CURRENT_ACCOUNT = MinecraftAccount.load(System.getProperty("pojav.selectedAccount")); + mVersion = Tools.getVersionInfo(getSelectedVersion()); + } + System.out.println("Launching Minecraft " + mVersion.id); + String configPath; + if (mVersion.logging != null) { + if (mVersion.logging.client.file.id.equals("client-1.12.xml")) { + configPath = Tools.DIR_BUNDLE + "/log4j-rce-patch-1.12.xml"; + } else if (mVersion.logging.client.file.id.equals("client-1.7.xml")) { + configPath = Tools.DIR_BUNDLE + "/log4j-rce-patch-1.7.xml"; + } else { + configPath = Tools.DIR_GAME_NEW + "/" + mVersion.logging.client.file.id; + } + System.setProperty("log4j.configurationFile", configPath); + } Tools.launchMinecraft(AccountJNI.CURRENT_ACCOUNT, mVersion); } catch (Throwable th) { Tools.showError(th); @@ -57,18 +85,7 @@ public class PLaunchApp { maxProgress = 0; UIKit.updateProgressSafe(0, "Finding a version"); - String mcver = "1.16.5"; - - try { - String plistContent = Tools.read(Tools.DIR_APP_DATA + "/launcher_preferences.plist"); - plistContent = plistContent.substring(plistContent.indexOf("selected_version") + 27); - mcver = plistContent.substring( - plistContent.indexOf("") + 8, - plistContent.indexOf("")); - } catch (IOException e) { - e.printStackTrace(); - UIKit.updateProgressSafe(0, "Could not parse plist, defaulting to Minecraft 1.16.5"); - } + String mcver = getSelectedVersion(); AccountJNI.CURRENT_ACCOUNT.selectedVersion = mcver; try { @@ -116,6 +133,12 @@ public class PLaunchApp { e.printStackTrace(); } + if (mVersion.logging != null && !mVersion.logging.client.file.id.equals("client-1.12.xml")) { + UIKit.updateProgressSafe(0, "Downloading " + mVersion.logging.client.file.id); + String configPath = Tools.DIR_GAME_NEW + "/" + mVersion.logging.client.file.id; + Tools.downloadFile(mVersion.logging.client.file.url, configPath); + } + maxProgress = mVersion.libraries.length + 1 + (assets == null ? 0 : assets.objects.size()); File outLib; diff --git a/JavaApp/src/main/java/net/kdt/pojavlaunch/PojavClassLoader.java b/JavaApp/src/main/java/net/kdt/pojavlaunch/PojavClassLoader.java index 2a60b9b9..c39679ab 100644 --- a/JavaApp/src/main/java/net/kdt/pojavlaunch/PojavClassLoader.java +++ b/JavaApp/src/main/java/net/kdt/pojavlaunch/PojavClassLoader.java @@ -1,5 +1,7 @@ package net.kdt.pojavlaunch; +import java.io.File; +import java.io.IOException; import java.net.*; /** @@ -12,9 +14,40 @@ public class PojavClassLoader extends URLClassLoader { public PojavClassLoader(ClassLoader parent) { super(new URL[0], parent); } - + @Override public void addURL(URL url) { super.addURL(url); + try { + System.setProperty("java.class.path", System.getProperty("java.class.path") + ":" + new File(url.toURI()).getAbsolutePath()); + } catch (URISyntaxException e) { + e.printStackTrace(); + } + } + + static URL getFileURL(File file) { + try { + file = file.getCanonicalFile(); + } catch (IOException e) {} + + try { + return file.toURL(); + } catch (MalformedURLException e) { + // Should never happen since we specify the protocol... + throw new InternalError(e); + } + } + + /** + * This class loader supports dynamic additions to the class path + * at runtime. + * + * @see java.lang.instrument.Instrumentation#appendToSystemClassPathSearch + */ + private void appendToClassPathForInstrumentation(String path) { + assert(Thread.holdsLock(this)); + + // addURL is a no-op if path already contains the URL + super.addURL(getFileURL(new File(path))); } } \ No newline at end of file diff --git a/JavaApp/src/main/java/net/kdt/pojavlaunch/Tools.java b/JavaApp/src/main/java/net/kdt/pojavlaunch/Tools.java index 8ffcb57b..3cb3c5ce 100644 --- a/JavaApp/src/main/java/net/kdt/pojavlaunch/Tools.java +++ b/JavaApp/src/main/java/net/kdt/pojavlaunch/Tools.java @@ -101,12 +101,29 @@ public final class Tools final String launchClassPath = generateLaunchClassPath(profile.selectedVersion); List javaArgList = new ArrayList(); - + //javaArgList.add(versionInfo.logging.client.argument.replace("${path}", DIR_GAME_NEW.getAbsolutePath() + "/" + mVersion.logging.client.file.id)); javaArgList.add("-cp"); javaArgList.add(launchClassPath); javaArgList.add(versionInfo.mainClass); javaArgList.addAll(Arrays.asList(launchArgs)); + if(profile.username.equals("demo_user")) { + File demoHome = new File(DIR_GAME_HOME + "/demo"); + if(demoHome.exists()) { + for (File demoStuff : demoHome.listFiles()) { demoStuff.delete(); } + } else { + demoHome.mkdirs(); + } + javaArgList.add("-Duser.home=" + DIR_GAME_HOME + "/demo"); + File demoDir = new File(DIR_GAME_NEW + "/demo"); + if(demoDir.exists()) { + for (File demoStuff : demoDir.listFiles()) { demoStuff.delete(); } + } else { + demoDir.mkdirs(); + } + javaArgList.add("-Duser.dir=" + DIR_GAME_NEW + "/demo"); + javaArgList.add("--demo"); + } // Debug /* @@ -133,7 +150,8 @@ public final class Tools // URLClassLoader loader = new URLClassLoader(urlList.toArray(new URL[0]), ClassLoader.getSystemClassLoader()); PojavClassLoader loader = (PojavClassLoader) ClassLoader.getSystemClassLoader(); - + // add launcher.jar itself + loader.addURL(Tools.class.getProtectionDomain().getCodeSource().getLocation().toURI().toURL()); for (String s : launchClassPath.split(":")) { if (!s.isEmpty()) { loader.addURL(new File(s).toURI().toURL()); @@ -160,8 +178,6 @@ public final class Tools if (versionInfo.inheritsFrom != null) { versionName = versionInfo.inheritsFrom; } - - String userType = "mojang"; File gameDir = new File(Tools.DIR_GAME_NEW); gameDir.mkdirs(); @@ -170,12 +186,14 @@ public final class Tools varArgMap.put("auth_access_token", profile.accessToken); varArgMap.put("auth_player_name", username); varArgMap.put("auth_uuid", profile.profileId); + // varArgMap.put("auth_xuid", profile.profileId); // TODO!!! varArgMap.put("assets_root", Tools.ASSETS_PATH); varArgMap.put("assets_index_name", versionInfo.assets); + varArgMap.put("clientid", profile.clientToken); varArgMap.put("game_assets", Tools.ASSETS_PATH); varArgMap.put("game_directory", gameDir.getAbsolutePath()); varArgMap.put("user_properties", "{}"); - varArgMap.put("user_type", userType); + varArgMap.put("user_type", profile.isMicrosoft ? "msa" : "mojang"); varArgMap.put("version_name", versionName); varArgMap.put("version_type", versionInfo.type); @@ -400,7 +418,7 @@ public final class Tools // Support for text2speech is not planned, so skip it for now. for (int i = 0; i < libraries.length; i++) { DependentLibrary libItem = libraries[i]; - if (libItem.name.startsWith("com.mojang.text2speech") || + if (libItem.name.startsWith("com.mojang:text2speech") || libItem.name.startsWith("net.java.jinput") || libItem.name.startsWith("net.java.dev.jna:platform:") || libItem.name.startsWith("org.lwjgl") || @@ -459,7 +477,7 @@ public final class Tools DependentLibrary libAdded = libList.get(i); String libAddedName = libAdded.name.substring(0, libAdded.name.lastIndexOf(":")); - if (libAddedName.equals(libName)) { + if (!libAdded.name.equals(lib.name) && libAddedName.equals(libName)) { System.out.println("Library " + libName + ": Replaced version " + libAdded.name.substring(libAddedName.length() + 1) + " with " + lib.name.substring(libName.length() + 1)); @@ -522,10 +540,10 @@ public final class Tools for (String key : keyArr) { Object value = null; try { - Field fieldA = fromVer.getClass().getDeclaredField(key); + Field fieldA = fromVer.getClass().getField(key); value = fieldA.get(fromVer); if (((value instanceof String) && !((String) value).isEmpty()) || value != null) { - Field fieldB = targetVer.getClass().getDeclaredField(key); + Field fieldB = targetVer.getClass().getField(key); fieldB.set(targetVer, value); } } catch (Throwable th) { diff --git a/JavaApp/src/main/java/net/kdt/pojavlaunch/authenticator/microsoft/MicrosoftAuthTask.java b/JavaApp/src/main/java/net/kdt/pojavlaunch/authenticator/microsoft/MicrosoftAuthTask.java index 046ccbc7..bf5bb7b6 100644 --- a/JavaApp/src/main/java/net/kdt/pojavlaunch/authenticator/microsoft/MicrosoftAuthTask.java +++ b/JavaApp/src/main/java/net/kdt/pojavlaunch/authenticator/microsoft/MicrosoftAuthTask.java @@ -46,6 +46,13 @@ public class MicrosoftAuthTask { acc.profileId = msa.mcUuid; acc.isMicrosoft = true; acc.msaRefreshToken = msa.msRefreshToken; + } else if(msa.doesDemo) { + acc.clientToken = "0"; /* FIXME */ + acc.accessToken = "-1"; // Differentiate from local accounts + acc.username = "demo_user"; + acc.profileId = "25e00594-cf57-3f87-b3af-3f06591be252"; + acc.isMicrosoft = false; + acc.msaRefreshToken = "0"; } acc.save(); diff --git a/JavaApp/src/main/java/net/kdt/pojavlaunch/authenticator/microsoft/Msa.java b/JavaApp/src/main/java/net/kdt/pojavlaunch/authenticator/microsoft/Msa.java index e7b9c667..c2349a7d 100644 --- a/JavaApp/src/main/java/net/kdt/pojavlaunch/authenticator/microsoft/Msa.java +++ b/JavaApp/src/main/java/net/kdt/pojavlaunch/authenticator/microsoft/Msa.java @@ -38,6 +38,7 @@ public class Msa { public String mcToken; public String mcUuid; public boolean doesOwnGame; + public boolean doesDemo; public Msa(MicrosoftAuthTask task, boolean isRefresh, String authCode) throws IOException, JSONException { this.task = task; @@ -270,10 +271,16 @@ public class Msa { // Log.i("MicroAuth","Uuid Minecraft = " + uuidDashes); mcName=name; mcUuid=uuidDashes; - }else{ + } else if(conn.getResponseCode() == 404) { + // Demo mode stuff + doesOwnGame = false; + doesDemo = true; + } else { // Log.i("MicroAuth","It seems that this Microsoft Account does not own the game."); doesOwnGame = false; + doesDemo = false; throwResponseError(conn); + } } @@ -299,9 +306,34 @@ public class Msa { } private static void throwResponseError(HttpURLConnection conn) throws IOException { + String otherErrStr = ""; String errStr = Tools.read(conn.getErrorStream()); // Log.i("MicroAuth","Error code: " + conn.getResponseCode() + ": " + conn.getResponseMessage() + "\n" + errStr); - throw new RuntimeException("MSA Error: " + conn.getResponseCode() + ": " + conn.getResponseMessage() + ", error stream:\n" + errStr); + +// it seems already handled by the demo mode.. +/* + if (errStr.contains("NOT_FOUND") && + errStr.contains("The server has not found anything matching the request URI")) + { + // TODO localize this + otherErrStr = "It seems that this Microsoft Account does not own the game. Make sure that you have bought/migrated to your Microsoft account."; + } else { +*/ + try { + JSONObject jo = new JSONObject(errStr); + switch ((int)(jo.getLong("XErr") - 2148916230l)) { + case 8: // AddChildToFamily + otherErrStr = "This account is under 18 and needs to be added to a Family by an adult before proceed."; + break; + case 3: // CreateAccount + otherErrStr = "The account isn't created yet."; + break; + } + } catch (Throwable th) { // not a JSON? + } + //} + + throw new RuntimeException(otherErrStr + "\n\nMSA Error: " + conn.getResponseCode() + ": " + conn.getResponseMessage() + ", error stream:\n" + errStr); } } diff --git a/JavaApp/src/main/java/net/kdt/pojavlaunch/uikit/AccountJNI.java b/JavaApp/src/main/java/net/kdt/pojavlaunch/uikit/AccountJNI.java index 49b733d1..85090e95 100644 --- a/JavaApp/src/main/java/net/kdt/pojavlaunch/uikit/AccountJNI.java +++ b/JavaApp/src/main/java/net/kdt/pojavlaunch/uikit/AccountJNI.java @@ -17,7 +17,7 @@ public class AccountJNI { public static volatile MinecraftAccount CURRENT_ACCOUNT; // Call back about account credentials for login - public static boolean loginAccount(int type, + public static String loginAccount(int type, String data // One of: // Local username // Mojang json response @@ -61,12 +61,12 @@ public class AccountJNI { break; } - return true; + return CURRENT_ACCOUNT.username; } catch (Throwable th) { Tools.showError(th); } - return false; + return null; } static { diff --git a/JavaApp/src/main/java/net/kdt/pojavlaunch/uikit/UIKit.java b/JavaApp/src/main/java/net/kdt/pojavlaunch/uikit/UIKit.java index 965a849f..c26e3ba9 100644 --- a/JavaApp/src/main/java/net/kdt/pojavlaunch/uikit/UIKit.java +++ b/JavaApp/src/main/java/net/kdt/pojavlaunch/uikit/UIKit.java @@ -12,7 +12,8 @@ public class UIKit { public static final int ACTION_DOWN = 0; public static final int ACTION_UP = 1; public static final int ACTION_MOVE = 2; - + public static final int ACTION_MOVE_MOTION = 3; + private static int guiScale; private static void patch_FlatLAF_setLinux() { @@ -104,7 +105,7 @@ public class UIKit { PLaunchApp.launchMinecraft(); } - public static void callback_SurfaceViewController_onTouch(int event, int x, int y) { + public static void callback_SurfaceViewController_onTouch(int event, float x, float y) { switch (event) { case ACTION_DOWN: case ACTION_UP: @@ -123,6 +124,10 @@ public class UIKit { CallbackBridge.mouseY = y; } break; + + case ACTION_MOVE_MOTION: + CallbackBridge.mouseX += x; + CallbackBridge.mouseY += y; } CallbackBridge.mouseLastX = x; CallbackBridge.mouseLastY = y; diff --git a/JavaApp/src/main/java/net/kdt/pojavlaunch/value/MinecraftAccount.java b/JavaApp/src/main/java/net/kdt/pojavlaunch/value/MinecraftAccount.java index 0bd14439..81f8c346 100644 --- a/JavaApp/src/main/java/net/kdt/pojavlaunch/value/MinecraftAccount.java +++ b/JavaApp/src/main/java/net/kdt/pojavlaunch/value/MinecraftAccount.java @@ -7,7 +7,7 @@ public class MinecraftAccount { public String accessToken = "0"; // access token public String clientToken = "0"; // clientID: refresh and invalidate - public String profileId = "0"; // authenticate UUID + public String profileId = "00000000-0000-0000-0000-000000000000"; // authenticate UUID public String username = "Steve"; public String selectedVersion = "1.7.10"; public boolean isMicrosoft = false; diff --git a/JavaApp/src/main/java/org/lwjgl/glfw/CallbackBridge.java b/JavaApp/src/main/java/org/lwjgl/glfw/CallbackBridge.java index fc85edb3..933cbbbc 100644 --- a/JavaApp/src/main/java/org/lwjgl/glfw/CallbackBridge.java +++ b/JavaApp/src/main/java/org/lwjgl/glfw/CallbackBridge.java @@ -25,7 +25,7 @@ public class CallbackBridge { public static final int ANDROID_TYPE_GRAB_STATE = 0; // Should pending events be limited? - volatile public static List PENDING_EVENT_LIST = new ArrayList<>(); + volatile public static List PENDING_EVENT_LIST = new ArrayList<>(); volatile public static boolean PENDING_EVENT_READY = false; public static final boolean INPUT_DEBUG_ENABLED; @@ -41,15 +41,15 @@ public class CallbackBridge { } // BEGIN launcher side - public static int mouseX, mouseY, mouseLastX, mouseLastY; + public static float mouseX, mouseY, mouseLastX, mouseLastY; public static boolean mouseLeft; - public static StringBuilder DEBUG_STRING = new StringBuilder(); - + //public static StringBuilder DEBUG_STRING = new StringBuilder(); + public static boolean nativeIsGrabbing() { return GLFW.mGLFWIsGrabbing; } - private static void nativeSendCursorPos(int x, int y) { + private static void nativeSendCursorPos(float x, float y) { if (!inputReady) return; GLFW.mGLFWCursorX = x + GLFW.internalGetWindow(GLFW.mainContext).x; GLFW.mGLFWCursorY = y + GLFW.internalGetWindow(GLFW.mainContext).y; @@ -61,26 +61,26 @@ public class CallbackBridge { } private static void nativeSendMouseButton(int button, int action, int mods) { if (!inputReady) return; - PENDING_EVENT_LIST.add(new Integer[]{EVENT_TYPE_MOUSE_BUTTON, button, action, mods, 0}); + PENDING_EVENT_LIST.add(new Object[]{EVENT_TYPE_MOUSE_BUTTON, button, action, mods, 0}); } private static void nativeSendScroll(double xoffset, double yoffset) { if (!inputReady) return; - PENDING_EVENT_LIST.add(new Integer[]{EVENT_TYPE_SCROLL, (int) xoffset, (int) yoffset, 0, 0}); + PENDING_EVENT_LIST.add(new Object[]{EVENT_TYPE_SCROLL, (int) xoffset, (int) yoffset, 0, 0}); } private static void nativeSendScreenSize(int width, int height) { if (!inputReady) return; - PENDING_EVENT_LIST.add(new Integer[]{EVENT_TYPE_FRAMEBUFFER_SIZE, width, height, 0, 0}); - PENDING_EVENT_LIST.add(new Integer[]{EVENT_TYPE_WINDOW_SIZE, width, height, 0, 0}); + PENDING_EVENT_LIST.add(new Object[]{EVENT_TYPE_FRAMEBUFFER_SIZE, width, height, 0, 0}); + PENDING_EVENT_LIST.add(new Object[]{EVENT_TYPE_WINDOW_SIZE, width, height, 0, 0}); } private static void nativeSendWindowPos(int x, int y) { if (!inputReady) return; - PENDING_EVENT_LIST.add(new Integer[]{EVENT_TYPE_WINDOW_POS, x, y, 0, 0}); + PENDING_EVENT_LIST.add(new Object[]{EVENT_TYPE_WINDOW_POS, x, y, 0, 0}); } // volatile private static boolean isGrabbing = false; public static class PusherRunnable implements Runnable { - int button; int x; int y; - public PusherRunnable(int button, int x, int y) { + int button; float x; float y; + public PusherRunnable(int button, float x, float y) { this.button = button; this.x = x; this.y = y; @@ -92,29 +92,29 @@ public class CallbackBridge { putMouseEventWithCoords(button, 0, x, y); } } - public static void putMouseEventWithCoords(int button, int x, int y /* , int dz, long nanos */) { + public static void putMouseEventWithCoords(int button, float x, float y /* , int dz, long nanos */) { new Thread(new PusherRunnable(button,x,y)).run(); } - public static void putMouseEventWithCoords(int button, int state, int x, int y /* , int dz, long nanos */) { + public static void putMouseEventWithCoords(int button, int state, float x, float y /* , int dz, long nanos */) { sendCursorPos(x, y); sendMouseKeycode(button, CallbackBridge.getCurrentMods(), state == 1); } private static boolean threadAttached; - public static void sendCursorPos(int x, int y) { + public static void sendCursorPos(float x, float y) { if (!threadAttached) { threadAttached = true; // CallbackBridge.nativeAttachThreadToOther(true, true /* TODO BaseMainActivity.isInputStackCall */); } - DEBUG_STRING.append("CursorPos=" + x + ", " + y + "\n"); + //DEBUG_STRING.append("CursorPos=" + x + ", " + y + "\n"); mouseX = x; mouseY = y; nativeSendCursorPos(x, y); } public static void sendKeycode(int keycode, char keychar, int scancode, int modifiers, boolean isDown) { - DEBUG_STRING.append("KeyCode=" + keycode + ", Char=" + keychar); + //DEBUG_STRING.append("KeyCode=" + keycode + ", Char=" + keychar); // TODO CHECK: This may cause input issue, not receive input! /* if (!nativeSendCharMods((int) keychar, modifiers) || !nativeSendChar(keychar)) { @@ -128,7 +128,7 @@ public class CallbackBridge { } public static void sendMouseKeycode(int button, int modifiers, boolean isDown) { - DEBUG_STRING.append("MouseKey=" + button + ", down=" + isDown + "\n"); + //DEBUG_STRING.append("MouseKey=" + button + ", down=" + isDown + "\n"); // if (isGrabbing()) DEBUG_STRING.append("MouseGrabStrace: " + android.util.Log.getStackTraceString(new Throwable()) + "\n"); nativeSendMouseButton(button, isDown ? 1 : 0, modifiers); } @@ -139,7 +139,7 @@ public class CallbackBridge { } public static void sendScroll(double xoffset, double yoffset) { - DEBUG_STRING.append("ScrollX=" + xoffset + ",ScrollY=" + yoffset); + //DEBUG_STRING.append("ScrollX=" + xoffset + ",ScrollY=" + yoffset); nativeSendScroll(xoffset, yoffset); } @@ -150,13 +150,7 @@ public class CallbackBridge { public static boolean isGrabbing() { return nativeIsGrabbing(); } - - public static void sendPrepareGrabInitialPos() { - DEBUG_STRING.append("Prepare set grab initial posititon"); - // TODO grab mode - // nativeSendMouseKeycode(-1, CallbackBridge.getCurrentMods(), false); - } - + public static boolean holdingAlt, holdingCapslock, holdingCtrl, holdingNumlock, holdingShift; public static int getCurrentMods() { @@ -176,7 +170,7 @@ public class CallbackBridge { } // END launcher side - public static void sendGrabbing(boolean grab, int xset, int yset) { + public static void sendGrabbing(boolean grab, float xset, float yset) { // sendData(ANDROID_TYPE_GRAB_STATE, Boolean.toString(grab)); if (grab) { @@ -190,8 +184,8 @@ public class CallbackBridge { nativeSetGrabbing(grab, xset, yset); } - // Called from Android side - public static void receiveCallback(int type, int i1, int i2, int i3, int i4) { + // Called from native code + public static void receiveCallback(int type, float i1, float i2, int i3, int i4) { /* if (INPUT_DEBUG_ENABLED) { System.out.println("LWJGL GLFW Callback received type=" + Integer.toString(type) + ", data=" + i1 + ", " + i2 + ", " + i3 + ", " + i4); @@ -199,10 +193,12 @@ public class CallbackBridge { */ if (PENDING_EVENT_READY) { if (type == EVENT_TYPE_CURSOR_POS) { - GLFW.mGLFWCursorX = i1; - GLFW.mGLFWCursorY = i2; + GLFW.mGLFWCursorX = (double) i1; + GLFW.mGLFWCursorY = (double) i2; + } else if (type == EVENT_TYPE_SCROLL) { + PENDING_EVENT_LIST.add(new Object[]{type, i1, i2, i3, i4}); } else { - PENDING_EVENT_LIST.add(new Integer[]{type, i1, i2, i3, i4}); + PENDING_EVENT_LIST.add(new Object[]{type, (int)i1, (int)i2, i3, i4}); } } // else System.out.println("Event input is not ready yet!"); } @@ -214,6 +210,6 @@ public class CallbackBridge { } public static native String nativeClipboard(int action, String copy); - private static native void nativeSetGrabbing(boolean grab, int xset, int yset); + private static native void nativeSetGrabbing(boolean grab, float xset, float yset); } diff --git a/JavaApp/src/main/java/org/lwjgl/glfw/GLFW.java b/JavaApp/src/main/java/org/lwjgl/glfw/GLFW.java index d57e18ea..4ddac5b2 100644 --- a/JavaApp/src/main/java/org/lwjgl/glfw/GLFW.java +++ b/JavaApp/src/main/java/org/lwjgl/glfw/GLFW.java @@ -820,29 +820,18 @@ public class GLFW } width.put(internalGetWindow(window).width); height.put(internalGetWindow(window).height); - } - - public static void glfwGetFramebufferSize(@NativeType("GLFWwindow *") long window, @Nullable @NativeType("int *") int[] width, @Nullable @NativeType("int *") int[] height) { - if (CHECKS) { - // check(window); - checkSafe(width, 1); - checkSafe(height, 1); - } - - width[0] = internalGetWindow(window).width; - height[0] = internalGetWindow(window).height; } - @Nullable + @Nullable @NativeType("GLFWmonitor **") public static PointerBuffer glfwGetMonitors() { PointerBuffer pBuffer = PointerBuffer.allocateDirect(1); - pBuffer.put(glfwGetPrimaryMonitor()); - return pBuffer; + pBuffer.put(glfwGetPrimaryMonitor()); + return pBuffer; } public static long glfwGetPrimaryMonitor() { - // Prevent NULL check + // Prevent NULL check return 1L; } @@ -870,44 +859,17 @@ public class GLFW height.put(mGLFWWindowHeight); } - public static void glfwGetMonitorPos(@NativeType("GLFWmonitor *") long monitor, @Nullable @NativeType("int *") int[] xpos, @Nullable @NativeType("int *") int[] ypos) { - if (CHECKS) { - // check(monitor); - checkSafe(xpos, 1); - checkSafe(ypos, 1); - } - - xpos[0] = 0; - ypos[0] = 0; - } - - /** Array version of: {@link #glfwGetMonitorWorkarea GetMonitorWorkarea} */ - public static void glfwGetMonitorWorkarea(@NativeType("GLFWmonitor *") long monitor, @Nullable @NativeType("int *") int[] xpos, @Nullable @NativeType("int *") int[] ypos, @Nullable @NativeType("int *") int[] width, @Nullable @NativeType("int *") int[] height) { - if (CHECKS) { - // check(monitor); - checkSafe(xpos, 1); - checkSafe(ypos, 1); - checkSafe(width, 1); - checkSafe(height, 1); - } - - xpos[0] = 0; - ypos[0] = 0; - width[0] = mGLFWWindowWidth; - height[0] = mGLFWWindowHeight; - } - @NativeType("GLFWmonitor *") public static long glfwGetWindowMonitor(@NativeType("GLFWwindow *") long window) { return internalGetWindow(window).monitor; } - - public static void glfwSetWindowMonitor(@NativeType("GLFWwindow *") long window, @NativeType("GLFWmonitor *") long monitor, int xpos, int ypos, int width, int height, int refreshRate) { - GLFWWindowProperties properties = internalGetWindow(window); - properties.monitor = monitor; - properties.x = xpos; - properties.y = ypos; - internalChangeMonitorSize(width, height); + + public static void glfwSetWindowMonitor(@NativeType("GLFWwindow *") long window, @NativeType("GLFWmonitor *") long monitor, int xpos, int ypos, int width, int height, int refreshRate) { + GLFWWindowProperties properties = internalGetWindow(window); + properties.monitor = monitor; + properties.x = xpos; + properties.y = ypos; + internalChangeMonitorSize(width, height); } public static int glfwGetWindowAttrib(@NativeType("GLFWwindow *") long window, int attrib) { @@ -1090,7 +1052,7 @@ public class GLFW // Indirect event while (CallbackBridge.PENDING_EVENT_LIST.size() > 0) { - Integer[] dataArr = CallbackBridge.PENDING_EVENT_LIST.remove(0); + Object[] dataArr = CallbackBridge.PENDING_EVENT_LIST.remove(0); if (dataArr == null) { // It should not be null, but still should be catched // System.out.println("GLFW: popped callback is null, skipping"); @@ -1098,53 +1060,53 @@ public class GLFW } for (Long ptr : mGLFWWindowMap.keySet()) { - switch (dataArr[0]) { + switch ((int)dataArr[0]) { case CallbackBridge.EVENT_TYPE_CHAR: if (mGLFWCharCallback != null) { - mGLFWCharCallback.invoke(ptr, dataArr[1]); + mGLFWCharCallback.invoke(ptr, (int)dataArr[1]); } break; case CallbackBridge.EVENT_TYPE_CHAR_MODS: if (mGLFWCharModsCallback != null) { - mGLFWCharModsCallback.invoke(ptr, dataArr[1], dataArr[2]); + mGLFWCharModsCallback.invoke(ptr, (int)dataArr[1], (int)dataArr[2]); } break; case CallbackBridge.EVENT_TYPE_CURSOR_ENTER: if (mGLFWCursorEnterCallback != null) { - mGLFWCursorEnterCallback.invoke(ptr, dataArr[1] == 1); + mGLFWCursorEnterCallback.invoke(ptr, (int)dataArr[1] == 1); } break; case CallbackBridge.EVENT_TYPE_KEY: if (mGLFWKeyCallback != null) { - keyDownBuffer[Math.max(0, dataArr[1]-31)]=(byte)(int)dataArr[3]; - mGLFWKeyCallback.invoke(ptr, dataArr[1], dataArr[2], dataArr[3], dataArr[4]); + keyDownBuffer[Math.max(0, (int)dataArr[1]-31)]=(byte)(int)dataArr[3]; + mGLFWKeyCallback.invoke(ptr, (int)dataArr[1], (int)dataArr[2], (int)dataArr[3], (int)dataArr[4]); } break; case CallbackBridge.EVENT_TYPE_MOUSE_BUTTON: if (mGLFWMouseButtonCallback != null) { - mGLFWMouseButtonCallback.invoke(ptr, dataArr[1], dataArr[2], dataArr[3]); + mGLFWMouseButtonCallback.invoke(ptr, (int)dataArr[1], (int)dataArr[2], (int)dataArr[3]); } break; case CallbackBridge.EVENT_TYPE_SCROLL: if (mGLFWScrollCallback != null) { - mGLFWScrollCallback.invoke(ptr, dataArr[1], dataArr[2]); + mGLFWScrollCallback.invoke(ptr, (double)dataArr[1], (double)dataArr[2]); } break; case CallbackBridge.EVENT_TYPE_WINDOW_POS: - glfwSetWindowPos(ptr, dataArr[1], dataArr[2]); + glfwSetWindowPos(ptr, (int)dataArr[1], (int)dataArr[2]); break; case CallbackBridge.EVENT_TYPE_FRAMEBUFFER_SIZE: case CallbackBridge.EVENT_TYPE_WINDOW_SIZE: - internalChangeMonitorSize(dataArr[1], dataArr[2]); + internalChangeMonitorSize((int)dataArr[1], (int)dataArr[2]); glfwSetWindowSize(ptr, mGLFWWindowWidth, mGLFWWindowHeight); - if (dataArr[0] == CallbackBridge.EVENT_TYPE_FRAMEBUFFER_SIZE && mGLFWFramebufferSizeCallback != null) { + if ((int)dataArr[0] == CallbackBridge.EVENT_TYPE_FRAMEBUFFER_SIZE && mGLFWFramebufferSizeCallback != null) { mGLFWFramebufferSizeCallback.invoke(ptr, mGLFWWindowWidth, mGLFWWindowHeight); - } else if (dataArr[0] == CallbackBridge.EVENT_TYPE_WINDOW_SIZE && mGLFWWindowSizeCallback != null) { + } else if ((int)dataArr[0] == CallbackBridge.EVENT_TYPE_WINDOW_SIZE && mGLFWWindowSizeCallback != null) { mGLFWWindowSizeCallback.invoke(ptr, mGLFWWindowWidth, mGLFWWindowHeight); } break; default: - System.err.println("GLFWEvent: unknown callback type " + dataArr[0]); + System.err.println("GLFWEvent: unknown callback type " + (int)dataArr[0]); break; } } @@ -1156,7 +1118,7 @@ public class GLFW for (Long ptr : mGLFWWindowMap.keySet()) { mGLFWCursorPosCallback.invoke(ptr, mGLFWCursorX, mGLFWCursorY); } - // System.out.println("CursorPos updated to x=" + mGLFWCursorX + ",y=" + mGLFWCursorY); + //System.out.println("CursorPos updated to x=" + mGLFWCursorX + ",y=" + mGLFWCursorY); } } @@ -1302,4 +1264,140 @@ return false; public static boolean glfwGetGamepadState(int jid, GLFWGamepadState state) { return false; } + + /** Array version of: {@link #glfwGetVersion GetVersion} */ + public static void glfwGetVersion(@Nullable @NativeType("int *") int[] major, @Nullable @NativeType("int *") int[] minor, @Nullable @NativeType("int *") int[] rev) { + if (CHECKS) { + checkSafe(major, 1); + checkSafe(minor, 1); + checkSafe(rev, 1); + } + major[0] = GLFW_VERSION_MAJOR; + minor[0] = GLFW_VERSION_MINOR; + rev[0] = GLFW_VERSION_REVISION; + } + + /** Array version of: {@link #glfwGetMonitorPos GetMonitorPos} */ + public static void glfwGetMonitorPos(@NativeType("GLFWmonitor *") long monitor, @Nullable @NativeType("int *") int[] xpos, @Nullable @NativeType("int *") int[] ypos) { + if (CHECKS) { + // check(monitor); + checkSafe(xpos, 1); + checkSafe(ypos, 1); + } + xpos[0] = 0; + ypos[0] = 0; + } + + /** Array version of: {@link #glfwGetMonitorWorkarea GetMonitorWorkarea} */ + public static void glfwGetMonitorWorkarea(@NativeType("GLFWmonitor *") long monitor, @Nullable @NativeType("int *") int[] xpos, @Nullable @NativeType("int *") int[] ypos, @Nullable @NativeType("int *") int[] width, @Nullable @NativeType("int *") int[] height) { + if (CHECKS) { + // check(monitor); + checkSafe(xpos, 1); + checkSafe(ypos, 1); + checkSafe(width, 1); + checkSafe(height, 1); + } + + xpos[0] = 0; + ypos[0] = 0; + width[0] = mGLFWWindowWidth; + height[0] = mGLFWWindowHeight; + } + + /** Array version of: {@link #glfwGetMonitorPhysicalSize GetMonitorPhysicalSize} */ +/* + public static void glfwGetMonitorPhysicalSize(@NativeType("GLFWmonitor *") long monitor, @Nullable @NativeType("int *") int[] widthMM, @Nullable @NativeType("int *") int[] heightMM) { + long __functionAddress = Functions.GetMonitorPhysicalSize; + if (CHECKS) { + check(monitor); + checkSafe(widthMM, 1); + checkSafe(heightMM, 1); + } + invokePPPV(monitor, widthMM, heightMM, __functionAddress); + } +*/ + + /** Array version of: {@link #glfwGetMonitorContentScale GetMonitorContentScale} */ +/* + public static void glfwGetMonitorContentScale(@NativeType("GLFWmonitor *") long monitor, @Nullable @NativeType("float *") float[] xscale, @Nullable @NativeType("float *") float[] yscale) { + long __functionAddress = Functions.GetMonitorContentScale; + if (CHECKS) { + check(monitor); + checkSafe(xscale, 1); + checkSafe(yscale, 1); + } + invokePPPV(monitor, xscale, yscale, __functionAddress); + } +*/ + + /** Array version of: {@link #glfwGetWindowPos GetWindowPos} */ + public static void glfwGetWindowPos(@NativeType("GLFWwindow *") long window, @Nullable @NativeType("int *") int[] xpos, @Nullable @NativeType("int *") int[] ypos) { + if (CHECKS) { + // check(window); + checkSafe(xpos, 1); + checkSafe(ypos, 1); + } + xpos[0] = 0; + ypos[0] = 0; + } + + /** Array version of: {@link #glfwGetWindowSize GetWindowSize} */ + public static void glfwGetWindowSize(@NativeType("GLFWwindow *") long window, @Nullable @NativeType("int *") int[] width, @Nullable @NativeType("int *") int[] height) { + if (CHECKS) { + // check(window); + checkSafe(width, 1); + checkSafe(height, 1); + } + width[0] = internalGetWindow(window).width; + height[0] = internalGetWindow(window).height; + } + + /** Array version of: {@link #glfwGetFramebufferSize GetFramebufferSize} */ + public static void glfwGetFramebufferSize(@NativeType("GLFWwindow *") long window, @Nullable @NativeType("int *") int[] width, @Nullable @NativeType("int *") int[] height) { + if (CHECKS) { + // check(window); + checkSafe(width, 1); + checkSafe(height, 1); + } + width[0] = internalGetWindow(window).width; + height[0] = internalGetWindow(window).height; + } + + /** Array version of: {@link #glfwGetWindowFrameSize GetWindowFrameSize} */ + public static void glfwGetWindowFrameSize(@NativeType("GLFWwindow *") long window, @Nullable @NativeType("int *") int[] left, @Nullable @NativeType("int *") int[] top, @Nullable @NativeType("int *") int[] right, @Nullable @NativeType("int *") int[] bottom) { + if (CHECKS) { + // check(window); + checkSafe(left, 1); + checkSafe(top, 1); + checkSafe(right, 1); + checkSafe(bottom, 1); + } + left[0] = top[0] = 0; + right[0] = internalGetWindow(window).width; + bottom[0] = internalGetWindow(window).height; + } + + /** Array version of: {@link #glfwGetWindowContentScale GetWindowContentScale} */ +/* + public static void glfwGetWindowContentScale(@NativeType("GLFWwindow *") long window, @Nullable @NativeType("float *") float[] xscale, @Nullable @NativeType("float *") float[] yscale) { + long __functionAddress = Functions.GetWindowContentScale; + if (CHECKS) { + check(window); + checkSafe(xscale, 1); + checkSafe(yscale, 1); + } + invokePPPV(window, xscale, yscale, __functionAddress); + } +*/ + + /** Array version of: {@link #glfwGetCursorPos GetCursorPos} */ + public static void glfwGetCursorPos(@NativeType("GLFWwindow *") long window, @Nullable @NativeType("double *") double[] xpos, @Nullable @NativeType("double *") double[] ypos) { + if (CHECKS) { + // check(window); + checkSafe(xpos, 1); + checkSafe(ypos, 1); + } + xpos[0] = mGLFWCursorX; + ypos[0] = mGLFWCursorY; + } } diff --git a/JavaApp/src/main/java/org/lwjgl/glfw/GLFWWindowProperties.java b/JavaApp/src/main/java/org/lwjgl/glfw/GLFWWindowProperties.java index 30ec8cd4..b7f42df8 100644 --- a/JavaApp/src/main/java/org/lwjgl/glfw/GLFWWindowProperties.java +++ b/JavaApp/src/main/java/org/lwjgl/glfw/GLFWWindowProperties.java @@ -5,7 +5,7 @@ import java.util.*; public class GLFWWindowProperties { public int width = GLFW.mGLFWWindowWidth; public int height = GLFW.mGLFWWindowHeight; - public int x, y; + public float x, y; public CharSequence title; public boolean shouldClose, isInitialSizeCalled, isCursorEntered; public long monitor; diff --git a/JavaApp/src/main/java/org/lwjgl/opengl/GLFWInputImplementation.java b/JavaApp/src/main/java/org/lwjgl/opengl/GLFWInputImplementation.java index 25c387eb..308899cf 100644 --- a/JavaApp/src/main/java/org/lwjgl/opengl/GLFWInputImplementation.java +++ b/JavaApp/src/main/java/org/lwjgl/opengl/GLFWInputImplementation.java @@ -178,7 +178,7 @@ public class GLFWInputImplementation implements InputImplementation { last_event_nanos = nanos; } public void putKeyboardEvent(int keycode, byte state, int ch, long nanos, boolean repeat) { - System.out.println("LWJGL2: debug keyboard=" + keycode + ", state=" + state + ", repeat=" + repeat); + //System.out.println("LWJGL2: debug keyboard=" + keycode + ", state=" + state + ", repeat=" + repeat); key_down_buffer[keycode] = state; keyboardEvent.clear(); keyboardEvent.putInt(keycode).put(state).putInt(ch).putLong(nanos).put(repeat ? (byte)1 : (byte)0); diff --git a/Makefile b/Makefile index b8cf6cc3..0a62b62e 100644 --- a/Makefile +++ b/Makefile @@ -2,7 +2,7 @@ SHELL := /bin/bash .SHELLFLAGS = -ec # Prerequisite variables -SOURCEDIR := $(shell pwd) +SOURCEDIR := $(shell printf "%q\n" "$(shell pwd)") OUTPUTDIR := $(SOURCEDIR)/artifacts WORKINGDIR := $(SOURCEDIR)/Natives/build DETECTPLAT := $(shell uname -s) @@ -62,7 +62,15 @@ POJAV_BUNDLE_DYLIBS ?= $(shell cd "$(POJAV_BUNDLE_DIR)/Frameworks" && echo *.dyl POJAV_JRE_DYLIBS ?= $(shell cd "$(POJAV_JRE_DIR)" && find . -name "*.dylib") # Function to use later for checking dependencies -DEPCHECK = $(shell type $(1) >/dev/null 2>&1 && echo 1) +DEPCHECK = $(shell type $(1) >/dev/null 2>&1 && echo 1) + +# Function to modify Info.plist files +INFOPLIST = \ + if [ '$(4)' = '0' ]; then \ + plutil -replace $(1) -string $(2) $(3); \ + else \ + plutil -value $(2) -key $(1) $(3); \ + fi # Function to use for packaging PACKAGING = \ @@ -112,30 +120,40 @@ DIRCHECK = \ # Function to copy + install INSTALL = \ echo 'Please note that this may not work properly. If it doesn'\''t work for you, you can manually extract the .deb in /var/tmp/net.kdt.pojavlauncher.$(1)_$(VERSION)_$(2).deb with dpkg or Filza.'; \ - scp -P $(DEVICE_PORT) $(OUTPUTDIR)/net.kdt.pojavlauncher.$(1)_$(VERSION)_$(2).deb root@$(DEVICE_IP):/var/tmp/net.kdt.pojavlauncher.$(1)_$(VERSION)_$(2).deb; \ - ssh root@$(DEVICE_IP) -p $(DEVICE_PORT) -t "dpkg -i /var/tmp/net.kdt.pojavlauncher.$(1)_$(VERSION)_$(2).deb; uicache -p $(3)/Applications/PojavLauncher.app" + if [ '$(4)' = '0' ]; then \ + scp -P $(DEVICE_PORT) $(OUTPUTDIR)/net.kdt.pojavlauncher.$(1)_$(VERSION)_$(2).deb root@$(DEVICE_IP):/var/tmp/net.kdt.pojavlauncher.$(1)_$(VERSION)_$(2).deb; \ + ssh root@$(DEVICE_IP) -p $(DEVICE_PORT) -t "dpkg -i /var/tmp/net.kdt.pojavlauncher.$(1)_$(VERSION)_$(2).deb; uicache -p $(3)/Applications/PojavLauncher.app"; \ + else \ + sudo dpkg -i $(OUTPUTDIR)/net.kdt.pojavlauncher.$(1)_$(VERSION)_$(2).deb; uicache -p $(3)/Applications/PojavLauncher.app; \ + fi # Function to copy + deploy DEPLOY = \ ldid -S$(SOURCEDIR)/entitlements.xml $(WORKINGDIR)/PojavLauncher.app/PojavLauncher; \ - scp -r -P $(DEVICE_PORT) -o "StrictHostKeyChecking no" -o "UserKnownHostsFile=/dev/null" \ - $(WORKINGDIR)/libOSMesaOverride.dylib.framework \ - $(WORKINGDIR)/PojavCore.framework \ - $(WORKINGDIR)/libawt_xawt.dylib \ - $(WORKINGDIR)/PojavLauncher.app/PojavLauncher \ - $(SOURCEDIR)/JavaApp/local_out/launcher.jar \ - root@$(DEVICE_IP):/var/tmp/; \ - ssh root@$(DEVICE_IP) -p $(DEVICE_PORT) -t " \ - mv /var/tmp/libawt_xawt.dylib $(1)/Applications/PojavLauncher.app/Frameworks/libawt_xawt.dylib && \ - rm -rf $(1)/Applications/PojavLauncher.app/Frameworks/libOSMesaOverride.dylib.framework && \ - mv /var/tmp/libOSMesaOverride.dylib.framework $(1)/Applications/PojavLauncher.app/Frameworks/libOSMesaOverride.dylib.framework && \ - rm -rf $(1)/Applications/PojavLauncher.app/Frameworks/PojavCore.framework && \ - mv /var/tmp/PojavCore.framework $(1)/Applications/PojavLauncher.app/Frameworks/PojavCore.framework && \ - mv /var/tmp/PojavLauncher $(1)/Applications/PojavLauncher.app/PojavLauncher && \ - mv /var/tmp/launcher.jar $(1)/Applications/PojavLauncher.app/libs/launcher.jar && \ - cd $(1)/Applications/PojavLauncher.app/Frameworks && \ - ln -sf libawt_xawt.dylib libawt_headless.dylib && killall PojavLauncher && \ - chown -R 501:501 $(1)/Applications/PojavLauncher.app/*" + if [ '$(2)' = '0' ]; then \ + scp -r -P $(DEVICE_PORT) -o "StrictHostKeyChecking no" -o "UserKnownHostsFile=/dev/null" \ + $(WORKINGDIR)/libOSMesaOverride.dylib.framework \ + $(WORKINGDIR)/libawt_xawt.dylib \ + $(WORKINGDIR)/PojavLauncher.app/PojavLauncher \ + $(SOURCEDIR)/JavaApp/local_out/launcher.jar \ + root@$(DEVICE_IP):/var/tmp/; \ + ssh root@$(DEVICE_IP) -p $(DEVICE_PORT) -t " \ + mv /var/tmp/libawt_xawt.dylib $(1)/Applications/PojavLauncher.app/Frameworks/libawt_xawt.dylib && \ + mv /var/tmp/libOSMesaOverride.dylib.framework $(1)/Applications/PojavLauncher.app/Frameworks/libOSMesaOverride.dylib.framework && \ + mv /var/tmp/PojavLauncher $(1)/Applications/PojavLauncher.app/PojavLauncher && \ + mv /var/tmp/launcher.jar $(1)/Applications/PojavLauncher.app/libs/launcher.jar && \ + cd $(1)/Applications/PojavLauncher.app/Frameworks && \ + ln -sf libawt_xawt.dylib libawt_headless.dylib && \ + chown -R 501:501 $(1)/Applications/PojavLauncher.app/*"; \ + else \ + sudo mv $(WORKINGDIR)/libawt_xawt.dylib $(1)/Applications/PojavLauncher.app/Frameworks/libawt_xawt.dylib; \ + sudo mv $(WORKINGDIR)/libOSMesaOverride.dylib.framework $(1)/Applications/PojavLauncher.app/Frameworks/libOSMesaOverride.dylib.framework; \ + sudo mv $(WORKINGDIR)/PojavLauncher $(1)/Applications/PojavLauncher.app/PojavLauncher; \ + sudo mv $(WORKINGDIR)/launcher.jar $(1)/Applications/PojavLauncher.app/libs/launcher.jar; \ + cd $(1)/Applications/PojavLauncher.app/Frameworks; \ + sudo ln -sf libawt_xawt.dylib libawt_headless.dylib; \ + sudo chown -R 501:501 $(1)/Applications/PojavLauncher.app/*; \ + fi # Make sure everything is already available for use. Error if they require something ifeq ($(call HAS_COMMAND,cmake --version),1) @@ -164,6 +182,16 @@ ifeq ($(call HAS_COMMAND,dpkg-deb --version),1) $(error You need to install dpkg-dev) endif +ifeq ($(call HAS_COMMAND,nproc --version),1) +ifeq ($(call HAS_COMMAND,gnproc --version),1) +$(warning Unable to determine number of threads, defaulting to 2.) +JOBS ?= 2 +else +JOBS ?= $(shell gnproc) +endif +else +JOBS ?= $(shell nproc) +endif # Now for the actual Makefile recipes. # all - runs clean, native, java, extras, and package. @@ -187,6 +215,7 @@ check: @printf 'SOURCEDIR - $(SOURCEDIR)\n' @printf 'WORKINGDIR - $(WORKINGDIR)\n' @printf 'OUTPUTDIR - $(OUTPUTDIR)\n' + @printf 'JOBS - $(JOBS)\n' @printf 'VERSION - $(VERSION)\n' @printf 'COMMIT - $(COMMIT)\n' @printf 'RELEASE - $(RELEASE)\n' @@ -213,7 +242,9 @@ native: -DCONFIG_COMMIT="$(COMMIT)" \ -DCONFIG_RELEASE=$(RELEASE) \ .. - @cd $(WORKINGDIR) && cmake --build . --config $(CMAKE_BUILD_TYPE) --target awt_headless awt_xawt libOSMesaOverride.dylib PojavLauncher + + @cmake --build $(WORKINGDIR) --config $(CMAKE_BUILD_TYPE) -j$(JOBS) + # --target awt_headless awt_xawt libOSMesaOverride.dylib PojavLauncher @rm $(WORKINGDIR)/libawt_headless.dylib @echo 'Building PojavLauncher $(VERSION) - NATIVES - End' @@ -264,9 +295,9 @@ deb: native java extras @echo 'Building PojavLauncher $(VERSION) - DEB - Start' -#ipa: native java extras -# echo 'Building PojavLauncher $(VERSION) - IPA - Start' -# cd $(OUTPUTDIR); \ +ipa: native java extras + echo 'Building PojavLauncher $(VERSION) - IPA - Start' + cd $(OUTPUTDIR); \ $(call DIRCHECK,$(OUTPUTDIR)/Payload); \ cp -R $(POJAV_BUNDLE_DIR) $(OUTPUTDIR)/Payload; \ rm -rf $(OUTPUTDIR)/Payload/PojavLauncher.app/Frameworks/*.dylib; \ @@ -279,43 +310,47 @@ deb: native java extras $(call DIRCHECK,$(OUTPUTDIR)/IPABuilder); \ mkdir -p $(OUTPUTDIR)/IPABuilder/{OpenJDK/{Frameworks,jre/lib/jli,jre/lib/server},PojavCore/Frameworks}; \ cd $(OUTPUTDIR)/IPABuilder/OpenJDK/Frameworks; \ + touch $(OUTPUTDIR)/IPABuilder/int.txt; \ for dylib in $(POJAV_JRE_DYLIBS); do \ dylib_name=$$(basename $$dylib); \ - mkdir -p $${dylib_name}.framework; \ - cd $${dylib_name}.framework; \ + mkdir -p $$dylib_name.framework; \ + cd $$dylib_name.framework; \ cp $(SOURCEDIR)/depends/Info.plist Info.plist; \ - defaults write "$$PWD/Info.plist" CFBundleExecutable $$dylib_name; \ - defaults write "$$PWD/Info.plist" CFBundleIdentifier "net.kdt.pojavlauncher.openjdk8_$$dylib_name"; \ - defaults write "$$PWD/Info.plist" CFBundleName $$dylib_name; \ + plist=$$(pwd)/Info.plist; \ + $(call INFOPLIST,CFBundleExecutable,$$dylib_name,$$plist,$(IOS)); \ + $(call INFOPLIST,CFBundleName,$$dylib_name,$$plist,$(IOS)); \ + $(call INFOPLIST,CFBundleIdentifier,"net.kdt.pojavlauncher.$$dylib_name",$$plist,$(IOS)); \ mv $(OUTPUTDIR)/Payload/PojavLauncher.app/jre/$$dylib $$dylib_name; \ - RPATH_LIST+="-add_rpath @loader_path/../${dylib_name}.framework "; \ + RPATH_LIST+="-add_rpath @loader_path/../$$dylib_name.framework "; \ + echo "-add_rpath @loader_path/../$$dylib_name.framework " >> $(OUTPUTDIR)/IPABuilder/int.txt; \ cd ..; \ echo "- (JRE) Finished $$dylib_name"; \ done; \ for dylib in $(POJAV_JRE_DYLIBS); do \ dylib_name=$$(basename $$dylib); \ - install_name_tool $$RPATH_LIST $${dylib_name}.framework/$${dylib_name}; \ + install_name_tool $$(cat $(OUTPUTDIR)/IPABuilder/int.txt | sort | uniq) $$dylib_name.framework/$$dylib_name; \ done; \ - mv $(OUTPUTDIR)/OpenJDK/Frameworks/* $(OUTPUTDIR)/Payload/PojavLauncher.app/Frameworks; \ + mv $(OUTPUTDIR)/IPABuilder/OpenJDK/Frameworks/* $(OUTPUTDIR)/Payload/PojavLauncher.app/Frameworks; \ cd $(OUTPUTDIR)/IPABuilder/PojavCore/Frameworks; \ - for dylib in $(POJAV_BUNDLE_DIR); do \ + for dylib in $(POJAV_BUNDLE_DYLIBS); do \ dylib_name=$$(basename $$dylib); \ - mkdir -p $${dylib_name}.framework; \ - cd $${dylib_name}.framework; \ + mkdir -p $$dylib_name.framework; \ + cd $$dylib_name.framework; \ + plist=$$(pwd)/Info.plist; \ cp $(SOURCEDIR)/depends/Info.plist Info.plist; \ - defaults write "$$PWD/Info.plist" CFBundleExecutable $$dylib_name; \ - defaults write "$$PWD/Info.plist" CFBundleIdentifier "net.kdt.pojavlauncher.$dylib_name"; \ - defaults write "$$PWD/Info.plist" CFBundleName $$dylib_name; \ - cp $$POJAV_BUNDLE_DIR/Frameworks/$$dylib_name $$dylib_name; \ + $(call INFOPLIST,CFBundleExecutable,$$dylib_name,$$plist,$(IOS)); \ + $(call INFOPLIST,CFBundleName,$$dylib_name,$$plist,$(IOS)); \ + $(call INFOPLIST,CFBundleIdentifier,"net.kdt.pojavlauncher.$$dylib_name",$$plist,$(IOS)); \ + cp $(POJAV_BUNDLE_DIR)/Frameworks/$$dylib_name $$dylib_name; \ cd ..; \ echo "- (PojavCore) Finished $$dylib_name"; \ done; \ rm -r $(OUTPUTDIR)/IPABuilder/PojavCore/Frameworks/libawt_headless.dylib.framework; \ - mv $(OUTPUTDIR)/IPABuilder/PojavCore/Frameworks/* Payload/PojavLauncher.app/Frameworks; \ - ldid -Sentitlements.xml Payload/PojavLauncher.app; \ - rm -f *.ipa; \ - zip --symlinks -r net.kdt.pojavlauncher-$(VERSION).ipa Payload* -# @echo 'Building PojavLauncher $(VERSION) - IPA - End' + mv $(OUTPUTDIR)/IPABuilder/PojavCore/Frameworks/* $(OUTPUTDIR)/Payload/PojavLauncher.app/Frameworks; \ + ldid -S$(SOURCEDIR)/entitlements.xml $(OUTPUTDIR)/Payload/PojavLauncher.app; \ + rm -f $(OUTPUTDIR)/*.ipa; \ + zip --symlinks -r $(OUTPUTDIR)/net.kdt.pojavlauncher-$(VERSION).ipa $(OUTPUTDIR)/Payload/* + @echo 'Building PojavLauncher $(VERSION) - IPA - End' install: deb @echo 'Building PojavLauncher $(VERSION) - INSTALL - Start' @@ -340,23 +375,23 @@ install: deb @echo 'Building PojavLauncher $(VERSION) - INSTALL - End' deploy: deb - @echo 'Building PojavLauncher $(VERSION) - DEPLOY - End' + @echo 'Building PojavLauncher $(VERSION) - DEPLOY - Start' @if [ '$(DEVICE_IP)' != '' ]; then \ if [ '$(ROOTLESS)' = '1' ]; then \ - $(call DEPLOY,$(IOS15PREF)); \ + $(call DEPLOY,$(IOS15PREF),$(IOS)); \ else \ - $(call DEPLOY); \ + $(call DEPLOY,'/',$(IOS)); \ fi; \ else \ echo 'You need to run '\''export DEVICE_IP='\'' to use make deploy.'; \ echo 'If you specified a different port for your device to listen for SSH connections, you need to run '\''export DEVICE_PORT='\'' as well.'; \ fi; - @echo 'Building PojavLauncher $(VERSION) - DEB - End' + @echo 'Building PojavLauncher $(VERSION) - DEPLOY - End' dsym: deb @echo 'Building PojavLauncher $(VERSION) - DSYM - Start' @cd $(OUTPUTDIR) && dsymutil --arch arm64 $(OUTPUTDIR)/PojavLauncher.app/PojavLauncher - @cp -r $(OUTPUTDIR)/PojavLauncher.app/PojavLauncher.dSYM $(OUTPUTDIR) + @cp -r $(OUTPUTDIR)/PojavLauncher.app/PojavLauncher.dSYM $(OUTPUTDIR)/PojavLauncher.dSYM @echo 'Building PojavLauncher $(VERSION) - DSYM - Start' clean: diff --git a/Natives/AppDelegate.m b/Natives/AppDelegate.m index a4041080..5d4e26b9 100644 --- a/Natives/AppDelegate.m +++ b/Natives/AppDelegate.m @@ -1,6 +1,7 @@ #import "AppDelegate.h" #import "LoginViewController.h" #import "SceneDelegate.h" +#import "ios_uikit_bridge.h" @implementation AppDelegate @@ -8,10 +9,8 @@ if (@available(iOS 13.0, *)) { } else { - LoginViewController *vc = [[LoginViewController alloc] init]; - UINavigationController *nav = [[UINavigationController alloc] initWithRootViewController:vc]; self.window = ([[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]]); - self.window.rootViewController = nav; + launchInitialViewController(self.window); [self.window makeKeyAndVisible]; } diff --git a/Natives/BKSSystemService.h b/Natives/BKSSystemService.h new file mode 100644 index 00000000..b44e4088 --- /dev/null +++ b/Natives/BKSSystemService.h @@ -0,0 +1,9 @@ +#import + +@interface BKSSystemService : NSObject + +- (unsigned int)createClientPort; +- (void)openApplication:(NSString *)app options:(id)arg2 withResult:(id)arg3 ; +- (void)openURL:(NSURL *)url application:(NSString *)app options:(id)options clientPort:(unsigned int)port withResult:(id)result; + +@end diff --git a/Natives/CMakeLists.txt b/Natives/CMakeLists.txt index 9868db9a..50acf0ee 100644 --- a/Natives/CMakeLists.txt +++ b/Natives/CMakeLists.txt @@ -1,10 +1,17 @@ cmake_minimum_required(VERSION 3.6) project(PojavLauncher) -set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fcommon -fobjc-arc -ObjC -I'${CMAKE_CURRENT_LIST_DIR}/resources/Frameworks/MetalANGLE.framework/Headers' -I'${CMAKE_CURRENT_LIST_DIR}/external/DBNumberedSlider/Classes' -I'${CMAKE_CURRENT_LIST_DIR}/external/fishhook' -I'${CMAKE_CURRENT_LIST_DIR}/external_include'" -) +set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fcommon -fobjc-arc -ObjC") set(CMAKE_C_FLAGS_DEBUG "-funwind-tables -g") +include_directories( + "resources/Frameworks/Alderis.framework/Headers" + "resources/Frameworks/MetalANGLE.framework/Headers" + "external/DBNumberedSlider/Classes" + "external/fishhook" + "external/zink" +) + # For cacio support library set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -rpath /usr/lib/jvm/java-8-openjdk/lib") @@ -36,6 +43,7 @@ find_library(OSMESA_LIB libOSMesa.8.dylib) add_library(libOSMesaOverride.dylib SHARED gl_mesa3d_patch.m) set_target_properties(libOSMesaOverride.dylib PROPERTIES FRAMEWORK TRUE + MACOSX_FRAMEWORK_IDENTIFIER dylib.mesa3d.libOSMesaOverride ) target_link_libraries(libOSMesaOverride.dylib ${OSMESA_LIB}) @@ -50,6 +58,7 @@ add_executable(PojavLauncher CustomControlsViewController.m FileListViewController.m JavaGUIViewController.m + KeyboardInput.m LauncherFAQViewController.m LauncherPreferences.m LauncherPreferencesViewController.m @@ -69,12 +78,17 @@ add_executable(PojavLauncher log.m utils.m ) + target_link_libraries(PojavLauncher "-F'${CMAKE_CURRENT_LIST_DIR}/build'" + "-F'${CMAKE_CURRENT_LIST_DIR}/resources/Frameworks'" "-framework AuthenticationServices" "-framework CoreGraphics" + "-framework GameController" "-framework QuartzCore" "-framework UIKit" + "-framework SafariServices" + "-framework WebKit" ) set_target_properties(PojavLauncher PROPERTIES MACOSX_BUNDLE TRUE diff --git a/Natives/CustomControlsViewController.m b/Natives/CustomControlsViewController.m index ffc767cd..3b9b8e16 100644 --- a/Natives/CustomControlsViewController.m +++ b/Natives/CustomControlsViewController.m @@ -1,3 +1,5 @@ +#import "Alderis.h" +#import "Alderis-Swift.h" #import "CustomControlsViewController.h" #import "DBNumberedSlider.h" #import "FileListViewController.h" @@ -7,6 +9,8 @@ #import "customcontrols/ControlDrawer.h" #import "customcontrols/CustomControlsUtils.h" +#include + #include "glfw_keycodes.h" #include "utils.h" @@ -14,10 +18,6 @@ BOOL shouldDismissPopover = YES; int width; NSMutableArray *keyCodeMap, *keyValueMap; -CGFloat clamp(CGFloat x, CGFloat lower, CGFloat upper) { - return fmin(upper, fmax(x, lower)); -} - @interface ControlLayout () @end @implementation ControlLayout @@ -92,6 +92,7 @@ CGFloat clamp(CGFloat x, CGFloat lower, CGFloat upper) { longpressGesture.minimumPressDuration = 0.5; [self.offsetView addGestureRecognizer:longpressGesture]; self.currentFileName = [getPreference(@"default_ctrl") stringByDeletingPathExtension]; + [self initKeyCodeMap]; [self loadControlFile:[NSString stringWithFormat:@"%s/%@", getenv("POJAV_PATH_CONTROL"), getPreference(@"default_ctrl")]]; } @@ -108,23 +109,23 @@ CGFloat clamp(CGFloat x, CGFloat lower, CGFloat upper) { if (cc_error) { NSLog(@"Error: could not read %@: %@", controlFilePath, cc_error.localizedDescription); showDialog(self, @"Error", [NSString stringWithFormat:@"Could not read %@: %@", controlFilePath, cc_error.localizedDescription]); - } else { - NSData* cc_objc_data = [cc_data dataUsingEncoding:NSUTF8StringEncoding]; - self.cc_dictionary = [NSJSONSerialization JSONObjectWithData:cc_objc_data options:NSJSONReadingMutableContainers error:&cc_error]; - if (cc_error) { - showDialog(self, @"Error parsing JSON", cc_error.localizedDescription); - } else { - loadControlObject(self.offsetView, self.cc_dictionary, ^void(ControlButton* button) { - [button addGestureRecognizer:[[UITapGestureRecognizer alloc] - initWithTarget:self action:@selector(showControlPopover:)]]; - [button addGestureRecognizer:[[UIPanGestureRecognizer alloc] - initWithTarget:self action:@selector(onTouch:)]]; - }); - } + return; } - [self initKeyCodeMap]; -} + NSData* cc_objc_data = [cc_data dataUsingEncoding:NSUTF8StringEncoding]; + self.cc_dictionary = [NSJSONSerialization JSONObjectWithData:cc_objc_data options:NSJSONReadingMutableContainers error:&cc_error]; + if (cc_error) { + showDialog(self, @"Error parsing JSON", cc_error.localizedDescription); + return; + } + + loadControlObject(self.offsetView, self.cc_dictionary, ^void(ControlButton* button) { + [button addGestureRecognizer:[[UITapGestureRecognizer alloc] + initWithTarget:self action:@selector(showControlPopover:)]]; + [button addGestureRecognizer:[[UIPanGestureRecognizer alloc] + initWithTarget:self action:@selector(onTouch:)]]; + }); +} - (void)showControlPopover:(UIGestureRecognizer *)sender { self.currentGesture = sender; @@ -351,19 +352,10 @@ CGFloat clamp(CGFloat x, CGFloat lower, CGFloat upper) { - (void)actionMenuBtnEdit { shouldDismissPopover = NO; CCMenuViewController *vc = [[CCMenuViewController alloc] init]; - vc.modalPresentationStyle = UIModalPresentationPopover; - vc.preferredContentSize = CGSizeMake(350, 250); - UIPopoverPresentationController *popoverController = [vc popoverPresentationController]; - popoverController.sourceView = self.currentGesture.view; - if ([self.currentGesture isKindOfClass:[UILongPressGestureRecognizer class]]) { - CGPoint point = [self.currentGesture locationInView:self.currentGesture.view]; - popoverController.sourceRect = self.selectedPoint; - } else { + vc.modalPresentationStyle = UIModalPresentationFormSheet; + if (![self.currentGesture isKindOfClass:[UILongPressGestureRecognizer class]]) { vc.targetButton = (ControlButton *)self.currentGesture.view; - popoverController.sourceRect = self.currentGesture.view.bounds; } - popoverController.permittedArrowDirections = UIPopoverArrowDirectionAny; - popoverController.delegate = self; [self presentViewController:vc animated:YES completion:nil]; } @@ -520,18 +512,20 @@ CGFloat clamp(CGFloat x, CGFloat lower, CGFloat upper) { CGFloat currentY; -@interface CCMenuViewController () { +@interface CCMenuViewController () { } @property(nonatomic) NSArray* arrOrientation; +@property UITextField *activeField; @property(nonatomic) UIScrollView* scrollView; @property(nonatomic) UITextField *editName, *editSizeWidth, *editSizeHeight, *editDynamicX, *editDynamicY; @property(nonatomic) UITextView* editMapping; @property(nonatomic) UIPickerView* pickerMapping; @property(nonatomic) UISegmentedControl* ctrlOrientation; @property(nonatomic) UISwitch *switchToggleable, *switchMousePass, *switchSwipeable, *switchDynamicPos; -@property(nonatomic) UIColorWell API_AVAILABLE(ios(14.0)) *colorWellBackground, *colorWellStroke; +@property(nonatomic) UIColorWell API_AVAILABLE(ios(14.0)) *colorWellINTBackground, *colorWellINTStroke; +@property(nonatomic) HBColorWell *colorWellEXTBackground, *colorWellEXTStroke; @property(nonatomic) DBNumberedSlider *sliderStrokeWidth, *sliderCornerRadius, *sliderOpacity; @end @@ -549,27 +543,37 @@ CGFloat currentY; - (void)viewDidLoad { [super viewDidLoad]; + [self registerForKeyboardNotifications]; currentY = 6.0; - self.view.frame = CGRectMake(0, 0, self.preferredContentSize.width, self.preferredContentSize.height); + if (self.view.bounds.origin.x == 0) { + CGFloat x = self.view.bounds.size.width/10.0; + CGFloat y = self.view.bounds.size.height/10.0; + self.view.bounds = CGRectMake(-x, -y, self.view.bounds.size.width - x * 2.0, self.view.bounds.size.height - y * 2.0); + //self.view.layer.cornerRadius = self.view.bounds.size.height/2; + //self.view.layer.masksToBounds = YES; + } + UIVisualEffectView *blurView = [[UIVisualEffectView alloc] initWithEffect:[UIBlurEffect effectWithStyle:UIBlurEffectStyleRegular]]; + blurView.frame = CGRectMake(0, 0, self.view.bounds.size.width, self.view.bounds.size.height); + [self.view addSubview:blurView]; UIBarButtonItem *btnFlexibleSpace = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace target:self action:nil]; - UIToolbar *popoverToolbar = [[UIToolbar alloc] initWithFrame:CGRectMake(0.0, 0.0, self.preferredContentSize.width, 44.0)]; + UIToolbar *popoverToolbar = [[UIToolbar alloc] initWithFrame:CGRectMake(0.0, 0.0, self.view.bounds.size.width, 44.0)]; UIBarButtonItem *popoverCancelButton = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemCancel target:self action:@selector(actionEditCancel)]; UIBarButtonItem *popoverDoneButton = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemDone target:self action:@selector(actionEditFinish)]; popoverToolbar.items = @[popoverCancelButton, btnFlexibleSpace, popoverDoneButton]; [self.view addSubview:popoverToolbar]; - self.scrollView = [[UIScrollView alloc] initWithFrame:CGRectMake(5.0, popoverToolbar.frame.size.height, self.preferredContentSize.width - 10.0, self.preferredContentSize.height - popoverToolbar.frame.size.height)]; + self.scrollView = [[UIScrollView alloc] initWithFrame:CGRectMake(5.0, popoverToolbar.frame.size.height, self.view.bounds.size.width - 10.0, self.view.bounds.size.height - popoverToolbar.frame.size.height)]; [self.view addSubview:self.scrollView]; - UIToolbar *editPickToolbar = [[UIToolbar alloc] initWithFrame:CGRectMake(0.0, 0.0, self.view.frame.size.width, 44.0)]; + UIToolbar *editPickToolbar = [[UIToolbar alloc] initWithFrame:CGRectMake(0.0, 0.0, self.view.bounds.size.width, 44.0)]; UIBarButtonItem *editDoneButton = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemDone target:self action:@selector(closeTextField)]; editPickToolbar.items = @[btnFlexibleSpace, editDoneButton]; - CGFloat width = self.view.frame.size.width - 10.0; - CGFloat height = self.view.frame.size.height - 10.0; + CGFloat width = self.view.bounds.size.width - 10.0; + CGFloat height = self.view.bounds.size.height - 10.0; // Property: Name @@ -670,12 +674,20 @@ CGFloat currentY; currentY += labelName.frame.size.height + 12.0; UILabel *labelBGColor = [self addLabel:@"Background color"]; if(@available(iOS 14.0, *)) { - self.colorWellBackground = [[UIColorWell alloc] initWithFrame:CGRectMake(width - 42.0, currentY - 5.0, 30.0, 30.0)]; - self.colorWellBackground.selectedColor = self.targetButton.backgroundColor; - [self.scrollView addSubview:self.colorWellBackground]; + self.colorWellINTBackground = [[UIColorWell alloc] initWithFrame:CGRectMake(width - 42.0, currentY - 5.0, 30.0, 30.0)]; + self.colorWellINTBackground.selectedColor = self.targetButton.backgroundColor; + [self.scrollView addSubview:self.colorWellINTBackground]; } else { - - // TODO: color picker for iOS < 14.0 + if (!dlopen("Alderis.framework/Alderis", RTLD_NOW)) { + NSLog(@"Cannot load Alderis framework: %s", dlerror()); + } + + self.colorWellEXTBackground = [[NSClassFromString(@"HBColorWell") alloc] initWithFrame:CGRectMake(width - 42.0, currentY - 5.0, 30.0, 30.0)]; + self.colorWellEXTBackground.color = self.targetButton.backgroundColor; + self.colorWellEXTBackground.isDragInteractionEnabled = YES; + self.colorWellEXTBackground.isDropInteractionEnabled = YES; + [self.colorWellEXTBackground addTarget:self action:@selector(presentColorPicker:) forControlEvents:UIControlEventTouchUpInside]; + [self.scrollView addSubview:self.colorWellEXTBackground]; } @@ -695,14 +707,16 @@ CGFloat currentY; currentY += labelName.frame.size.height + 12.0; UILabel *labelStrokeColor = [self addLabel:@"Stroke color"]; if(@available(iOS 14.0, *)) { - self.colorWellStroke = [[UIColorWell alloc] initWithFrame:CGRectMake(width - 42.0, currentY - 5.0, 30.0, 30.0)]; - self.colorWellStroke.supportsAlpha = NO; - self.colorWellStroke.selectedColor = [[UIColor alloc] initWithCGColor:self.targetButton.layer.borderColor]; - [self.scrollView addSubview:self.colorWellStroke]; - [self sliderValueChanged:self.sliderStrokeWidth]; + self.colorWellINTStroke = [[UIColorWell alloc] initWithFrame:CGRectMake(width - 42.0, currentY - 5.0, 30.0, 30.0)]; + self.colorWellINTStroke.selectedColor = [[UIColor alloc] initWithCGColor:self.targetButton.layer.borderColor]; + self.colorWellINTStroke.supportsAlpha = NO; } else { - // TODO: color picker for iOS < 14.0 + self.colorWellEXTStroke = [[NSClassFromString(@"HBColorWell") alloc] initWithFrame:CGRectMake(width - 42.0, currentY - 5.0, 30.0, 30.0)]; + self.colorWellEXTStroke.color = [[UIColor alloc] initWithCGColor:self.targetButton.layer.borderColor]; + [self.colorWellEXTStroke addTarget:self action:@selector(presentColorPicker:) forControlEvents:UIControlEventTouchUpInside]; + [self.scrollView addSubview:self.colorWellEXTStroke]; } + [self sliderValueChanged:self.sliderStrokeWidth]; // Property: Corner radius @@ -763,14 +777,81 @@ CGFloat currentY; currentY += labelName.frame.size.height + 12.0; - self.scrollView.contentSize = CGSizeMake(self.scrollView.contentSize.width, currentY + 100.0); + self.scrollView.contentSize = CGSizeMake(self.scrollView.contentSize.width, currentY); } -- (void)viewSafeAreaInsetsDidChange { - [super viewSafeAreaInsetsDidChange]; - self.scrollView.contentInset = self.view.safeAreaInsets; - self.scrollView.frame = CGRectMake(self.scrollView.frame.origin.x, self.scrollView.frame.origin.y + self.view.safeAreaInsets.top, self.scrollView.frame.size.width + self.view.safeAreaInsets.left, self.scrollView.frame.size.height + self.view.safeAreaInsets.bottom); - self.view.subviews[0].frame = CGRectOffset(self.view.subviews[0].frame, self.view.safeAreaInsets.left, self.view.safeAreaInsets.top); +#pragma mark - Alderis functions +// HBColorWell +- (void)presentColorPicker:(HBColorWell *)sender { + HBColorPickerViewController *vc = [[NSClassFromString(@"HBColorPickerViewController") alloc] init]; + vc.delegate = self; + vc.popoverPresentationController.sourceView = sender; + vc.configuration = [[NSClassFromString(@"HBColorPickerConfiguration") alloc] initWithColor:sender.color]; + if (sender == self.colorWellEXTBackground) { + vc.configuration.title = @"Background color"; + vc.configuration.supportsAlpha = YES; + } else if (sender == self.colorWellEXTStroke) { + vc.configuration.title = @"Stroke color"; + vc.configuration.supportsAlpha = NO; + } else { + NSLog(@"Unknown color well: %@", sender); + abort(); + } + [self presentViewController:vc animated:YES completion:nil]; +} + +// HBColorPickerDelegate +- (void)colorPicker:(HBColorPickerViewController *)picker didSelectColor:(UIColor *)color { + if ([picker.configuration.title isEqualToString:@"Background color"]) { + self.colorWellEXTBackground.color = color; + } else if ([picker.configuration.title isEqualToString:@"Stroke color"]) { + self.colorWellEXTStroke.color = color; + } else { + NSLog(@"Unknown color well: %@", picker.configuration.title); + abort(); + } +} + +#pragma mark - Keyboard observer functions +- (void)registerForKeyboardNotifications +{ + [[NSNotificationCenter defaultCenter] addObserver:self + selector:@selector(keyboardWasShown:) + name:UIKeyboardDidShowNotification object:nil]; + + [[NSNotificationCenter defaultCenter] addObserver:self + selector:@selector(keyboardWillBeHidden:) + name:UIKeyboardWillHideNotification object:nil]; + +} + +- (void)keyboardWasShown:(NSNotification*)aNotification +{ + NSDictionary* info = [aNotification userInfo]; + CGSize kbSize = [[info objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue].size; + UIEdgeInsets contentInsets = UIEdgeInsetsMake(0.0, 0.0, kbSize.height, 0.0); + self.scrollView.contentInset = contentInsets; + self.scrollView.scrollIndicatorInsets = contentInsets; + CGRect aRect = self.view.bounds; + aRect.size.height = self.view.frame.size.height - kbSize.height; + if (!CGRectContainsPoint(aRect, self.activeField.frame.origin) ) { + [self.scrollView scrollRectToVisible:self.activeField.frame animated:YES]; + } +} + +- (void)keyboardWillBeHidden:(NSNotification*)aNotification +{ + UIEdgeInsets contentInsets = UIEdgeInsetsZero; + self.scrollView.contentInset = contentInsets; + self.scrollView.scrollIndicatorInsets = contentInsets; +} + +- (void)textFieldDidBeginEditing:(UITextField *)textField { + self.activeField = textField; +} + + - (void)textFieldDidEndEditing:(UITextField *)textField { + self.activeField = nil; } #pragma mark - Control editor @@ -799,8 +880,11 @@ CGFloat currentY; self.targetButton.properties[@"passThruEnabled"] = @(self.switchMousePass.isOn); self.targetButton.properties[@"isSwipeable"] = @(self.switchSwipeable.isOn); if(@available(iOS 14.0, *)) { - self.targetButton.properties[@"bgColor"] = @(convertUIColor2ARGB(self.colorWellBackground.selectedColor)); - self.targetButton.properties[@"strokeColor"] = @(convertUIColor2RGB(self.colorWellStroke.selectedColor)); + self.targetButton.properties[@"bgColor"] = @(convertUIColor2ARGB(self.colorWellINTBackground.selectedColor)); + self.targetButton.properties[@"strokeColor"] = @(convertUIColor2RGB(self.colorWellINTStroke.selectedColor)); + } else { + self.targetButton.properties[@"bgColor"] = @(convertUIColor2ARGB(self.colorWellEXTBackground.color)); + self.targetButton.properties[@"strokeColor"] = @(convertUIColor2RGB(self.colorWellEXTStroke.color)); } self.targetButton.properties[@"strokeWidth"] = @((NSInteger) self.sliderStrokeWidth.value); self.targetButton.properties[@"cornerRadius"] = @((NSInteger) self.sliderCornerRadius.value); @@ -816,9 +900,9 @@ CGFloat currentY; [sender setValue:(NSInteger)sender.value animated:NO]; if (sender.tag == TAG_SLIDER_STROKEWIDTH) { if(@available(iOS 14.0, *)) { - self.colorWellStroke.enabled = sender.value != 0; + self.colorWellINTStroke.enabled = sender.value != 0; } else { - // TODO + self.colorWellEXTStroke.enabled = sender.value != 0; } } } diff --git a/Natives/FileListViewController.h b/Natives/FileListViewController.h index 3b2972c3..61a2c8d8 100644 --- a/Natives/FileListViewController.h +++ b/Natives/FileListViewController.h @@ -3,6 +3,7 @@ @interface FileListViewController : UITableViewController @property NSString* listPath; +@property (nonatomic, copy) void (^whenDelete)(NSString* name); @property(nonatomic, copy) void (^whenItemSelected)(NSString* name); @end diff --git a/Natives/FileListViewController.m b/Natives/FileListViewController.m index a1bb967b..4fb074cd 100644 --- a/Natives/FileListViewController.m +++ b/Natives/FileListViewController.m @@ -69,7 +69,11 @@ NSString *str = [self.fileList objectAtIndex:indexPath.row]; NSFileManager *fm = [NSFileManager defaultManager]; - [fm removeItemAtPath:[NSString stringWithFormat:@"%@/%@.json", self.listPath, str] error:nil]; + NSString *path = [NSString stringWithFormat:@"%@/%@.json", self.listPath, str]; + if (self.whenDelete != nil) { + self.whenDelete(path); + } + [fm removeItemAtPath:path error:nil]; [self.fileList removeObjectAtIndex:indexPath.row]; [tableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationFade]; } diff --git a/Natives/Info.plist b/Natives/Info.plist index 236c6941..11924bbe 100644 --- a/Natives/Info.plist +++ b/Natives/Info.plist @@ -8,20 +8,6 @@ PojavLauncher CFBundleExecutable PojavLauncher - CFBundleIdentifier - net.kdt.pojavlauncher - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - PojavLauncher - CFBundlePackageType - APPL - CFBundleShortVersionString - 2.1 - CFBundleSignature - ???? - CFBundleVersion - 2 CFBundleIcons CFBundlePrimaryIcon @@ -47,8 +33,37 @@ AppIcon - UIApplicationSupportsIndirectInputEvents + CFBundleIdentifier + net.kdt.pojavlauncher + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + PojavLauncher + CFBundlePackageType + APPL + CFBundleShortVersionString + 2.1 + CFBundleSignature + ???? + CFBundleURLTypes + + + CFBundleURLName + net.kdt.pojavlauncher.urlscheme + CFBundleURLSchemes + + pojavlauncher + + + + CFBundleVersion + 2 + LSRequiresIPhoneOS + LSSupportsOpeningDocumentsInPlace + + MinimumOSVersion + 12.0 UIApplicationSceneManifest UIApplicationSupportsMultipleScenes @@ -66,21 +81,19 @@ - LSRequiresIPhoneOS - - MinimumOSVersion - 12.0 - LSSupportsOpeningDocumentsInPlace + UIApplicationSupportsIndirectInputEvents UIFileSharingEnabled + UILaunchStoryboardName + LaunchScreen UIRequiredDeviceCapabilities arm64 metal - UILaunchStoryboardName - LaunchScreen + UIStatusBarHidden + UISupportedInterfaceOrientations UIInterfaceOrientationLandscapeLeft @@ -91,8 +104,6 @@ UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight - UIStatusBarHidden - UIViewControllerBasedStatusBarAppearance diff --git a/Natives/JavaLauncher.h b/Natives/JavaLauncher.h index df52ab8d..ce0e43b1 100644 --- a/Natives/JavaLauncher.h +++ b/Natives/JavaLauncher.h @@ -1,7 +1,7 @@ #pragma once -#include +#include -static bool started = false; +static BOOL started = NO; int launchJVM(int argc, char *argv[]); diff --git a/Natives/JavaLauncher.m b/Natives/JavaLauncher.m index b35ba4ea..83584872 100644 --- a/Natives/JavaLauncher.m +++ b/Natives/JavaLauncher.m @@ -69,9 +69,10 @@ typedef jint JLI_Launch_func(int argc, char ** argv, /* main argc, argc */ int main(int argc, char * argv[]); static int (*orig_dladdr)(const void* addr, Dl_info* info); -static void* (*orig_mmap)(void *addr, size_t len, int prot, int flags, int fd, off_t offset); +static void* (*orig_dlopen)(const char* path, int mode); +//static void* (*orig_mmap)(void *addr, size_t len, int prot, int flags, int fd, off_t offset); static char* (*orig_realpath)(const char *restrict path, char *restrict resolved_path); -static void (*orig_sys_icache_invalidate)(void *start, size_t len); +//static void (*orig_sys_icache_invalidate)(void *start, size_t len); static int margc = 0; static char* margv[1000]; @@ -93,15 +94,52 @@ NSString *allocmem_pre; NSString *multidir_pre; int hooked_dladdr(const void* addr, Dl_info* info) { + //NSLog(@"hook dladdr(%p, %p)", addr, info); int retVal = orig_dladdr(addr, info); if (addr == main) { - NSLog(@"hooked dladdr"); + //NSLog(@"hooked dladdr"); info->dli_fname = getenv("JAVA_EXT_EXECNAME"); - NSLog(@"name = %s", info->dli_fname); + } else if (retVal != 0) { + //NSLog(@"hooked dladdr"); + char *libname = basename((char *)info->dli_fname); + char src[2048], dst[2048]; + sprintf((char *)src, "%s/Frameworks", getenv("BUNDLE_PATH")); + if (0 == strncmp(info->dli_fname, src, strlen(src))) { + if (0 == strncmp(libname, "libjli.dylib", 12)) { + info->dli_fname = getenv("INTERNAL_JLI_PATH"); + } else if (0 == strncmp(libname, "libjvm.dylib", 12)) { + sprintf((char *)dst, "%s/lib/server/libjvm.dylib", getenv("JAVA_HOME")); + info->dli_fname = (char *)dst; + } + } } + //if (retVal) NSLog(@"dli_fname=%s", info->dli_fname); return retVal; } +void* hooked_dlopen(const char* path, int mode) { + void *handle = orig_dlopen(path, mode); + if (handle) { + return handle; + } + + char src[2048], dst[2048]; + sprintf((char *)src, "%s/Frameworks", getenv("BUNDLE_PATH")); + //NSLog(@"path=%s, src=%s, length=%lu, compare=%d", path, src, strlen(src), strncmp(path, src, strlen(src))); + if (!strncmp(path, src, strlen(src))) { + //NSLog(@"hooked dlopen %s", path); + char *libname = basename((char *)path); + sprintf((char *)dst, "%s/%s.framework/%s", src, libname, libname); + handle = orig_dlopen(dst, mode); + if (handle) { + dlerror(); // clear error + } + } + + return handle; +} + +/* void *hooked_mmap(void *addr, size_t len, int prot, int flags, int fd, off_t offset) { NSLog(@"mmap(%p, %ld, %d, %d, %d, %lld)", addr, len, prot, flags, fd, offset); @@ -113,10 +151,11 @@ void *hooked_mmap(void *addr, size_t len, int prot, int flags, int fd, off_t off // raise(SIGINT); return orig_mmap(addr, len, prot, flags, fd, offset); } +*/ char *hooked_realpath(const char *restrict path, char *restrict resolved_path) { - NSLog(@"hooked realpath %s", path); - if (!strncmp(javaHome, path, strlen(javaHome))) { + //NSLog(@"hook realpath %s", path); + if (0 == strncmp(path, javaHome, strlen(javaHome))) { strcpy(resolved_path, path); return resolved_path; } else { @@ -124,11 +163,13 @@ char *hooked_realpath(const char *restrict path, char *restrict resolved_path) { } } +/* void hooked_sys_icache_invalidate(void *start, size_t len) { // mprotect(start, 16384, PROT_EXEC | PROT_READ); // NSLog(@"mprotect errno %d", errno); orig_sys_icache_invalidate(start, len); } +*/ static void *logger_thread() { ssize_t rsize; @@ -153,17 +194,16 @@ static void *logger_thread() { void init_hookFunctions() { // if (!started && strncmp(argv[0], "/Applications", 13)) - { - // Jailed only: hook some functions for symlinked JRE home dir - int retval = rebind_symbols((struct rebinding[4]){ - //{"dlopen", hooked_dlopen, (void *)&orig_dlopen}, - {"dladdr", hooked_dladdr, (void *)&orig_dladdr}, - {"mmap", hooked_mmap, (void *)&orig_mmap}, - {"realpath", hooked_realpath, (void *)&orig_realpath}, - {"sys_icache_invalidate", hooked_sys_icache_invalidate, (void *)&orig_sys_icache_invalidate} - }, 4); - NSLog(@"hook retval = %d", retval); - } + // Jailed only: hook some functions for symlinked JRE home dir + int retval = rebind_symbols((struct rebinding[3]){ + {"dladdr", hooked_dladdr, (void *)&orig_dladdr}, + {"dlopen", hooked_dlopen, (void *)&orig_dlopen}, + //{"realpath", hooked_realpath, (void *)&orig_realpath}, + {"realpath$DARWIN_EXTSN", hooked_realpath, (void *)&orig_realpath} + //{"mmap", hooked_mmap, (void *)&orig_mmap}, + //{"sys_icache_invalidate", hooked_sys_icache_invalidate, (void *)&orig_sys_icache_invalidate} + }, 3); + NSLog(@"hook retval = %d", retval); } void init_loadCustomEnv() { @@ -196,12 +236,15 @@ void init_loadCustomJvmFlags() { BOOL isFirstArg = YES; for (NSString *jvmarg in [jvmargs componentsSeparatedByString:@" -"]) { if ([jvmarg length] == 0) continue; + //margv[margc] = (char *) [jvmarg UTF8String]; + if (isFirstArg) { isFirstArg = NO; margv[margc] = (char *) [jvmarg UTF8String]; } else { margv[margc] = (char *) [[@"-" stringByAppendingString:jvmarg] UTF8String]; } + NSLog(@"[Pre-init] Added custom JVM flag: %s", margv[margc]); ++margc; } @@ -229,30 +272,14 @@ void init_logDeviceAndVer (char *argument) { const char *deviceSoftware = [[[UIDevice currentDevice] systemVersion] cStringUsingEncoding:NSUTF8StringEncoding]; // Jailbreak - const char *deviceJailbreak; + const char *jbStrap; if (strncmp(argument, "/Applications", 13) == 0) { - if ([[NSFileManager defaultManager] fileExistsAtPath:@"/taurine"]) { - deviceJailbreak = "Taurine"; - } else if ([[NSFileManager defaultManager] fileExistsAtPath:@"/odyssey"]) { - deviceJailbreak = "Odyssey"; - } else if ([[NSFileManager defaultManager] fileExistsAtPath:@"/chimera"]) { - if ([[NSFileManager defaultManager] fileExistsAtPath:@"/.procursus_strapped"]) { - deviceJailbreak = "Chimera"; - } else { - deviceJailbreak = "Chimera <1.4"; - } + if ([[NSFileManager defaultManager] fileExistsAtPath:@"/.procursus_strapped"]) { + jbStrap = "Procursus"; } else { - if ([[NSFileManager defaultManager] fileExistsAtPath:@"/private/etc/apt/undecimus"]) { - deviceJailbreak = "unc0ver"; - } else if ([[NSFileManager defaultManager] fileExistsAtPath:@"/binpack/lib/dyld"]) { - if ([[NSFileManager defaultManager] fileExistsAtPath:@"/.procursus_strapped"]) { - deviceJailbreak = "odysseyra1n"; - } else { - deviceJailbreak = "checkra1n"; - } - } + jbStrap = "Other"; } - debug("[Pre-Init] %s with iOS %s (%s)", deviceHardware, deviceSoftware, deviceJailbreak); + debug("[Pre-Init] %s with iOS %s (%s)", deviceHardware, deviceSoftware, jbStrap); } else { debug("[Pre-Init] %s with iOS %s", deviceHardware, deviceSoftware); } @@ -263,10 +290,39 @@ void init_logDeviceAndVer (char *argument) { setenv("POJAV_DETECTEDHW", deviceHardware, 1); setenv("POJAV_DETECTEDSW", deviceSoftware, 1); if (strncmp(argument, "/Applications", 13) == 0) { - setenv("POJAV_DETECTEDJB", deviceJailbreak, 1); + setenv("POJAV_DETECTEDJB", jbStrap, 1); } } +void init_redirectStdio(char* homeDir) { + debug("[Pre-init] Staring logging STDIO as jrelog:V\n"); + // Redirect stdio to latestlog.txt + char newname[2048]; + sprintf(newname, "%s/latestlog.old.txt", homeDir); + rename(log_path, newname); + FILE* logFile = fopen(log_path, "w"); + if (!logFile) { + debug("[Pre-init] Error: failed to open %s: %s", log_path, strerror(errno)); + assert(0 && "Failed to open latestlog.txt. Check oslog for more details."); + } + log_fd = fileno(logFile); + setvbuf(stdout, 0, _IOLBF, 0); // make stdout line-buffered + setvbuf(stderr, 0, _IONBF, 0); // make stderr unbuffered + + /* create the pipe and redirect stdout and stderr */ + pipe(pfd); + dup2(pfd[1], 1); + dup2(pfd[1], 2); + + /* spawn the logging thread */ + if(pthread_create(&logger, 0, logger_thread, 0) == -1) { + char *fail_str = "Failed to start logging!"; + write(log_fd, fail_str, strlen(fail_str)); + close(log_fd); + } + pthread_detach(logger); +} + void environmentFailsafes(char *argv[]) { if (strncmp(argv[0], "/Applications", 13) == 0) { if (0 == access("/usr/lib/jvm/java-8-openjdk/", F_OK)) { @@ -284,14 +340,16 @@ void environmentFailsafes(char *argv[]) { javaHome = [javaHome_pre cStringUsingEncoding:NSUTF8StringEncoding]; setPreference(@"java_home", javaHome_pre); } else { - javaHome = calloc(1, 2048); - sprintf((char *)javaHome, "%s/jre", homeDir); + asprintf((char **)&javaHome, "%s/jre", homeDir); } } int launchJVM(int argc, char *argv[]) { if (0 != [[NSFileManager defaultManager] fileExistsAtPath:@"/var/mobile/Documents/.pojavlauncher"] && 0 == [[NSFileManager defaultManager] fileExistsAtPath:@"/var/mobile/Documents/.pojavlauncher/migration_complete"]) { NSString *newDir = @"/usr/share/pojavlauncher"; + if([[[UIDevice currentDevice] systemVersion] containsString:@"15."]) { + newDir = @"/private/preboot/procursus/usr/share/pojavlauncher"; + } NSString *oldDir = @"/var/mobile/Documents/.pojavlauncher"; NSFileManager *fm = [NSFileManager defaultManager]; NSArray *files = [fm contentsOfDirectoryAtPath:oldDir error:nil]; @@ -301,7 +359,7 @@ int launchJVM(int argc, char *argv[]) { [fm removeItemAtPath:oldDir error:nil]; symlink([newDir cStringUsingEncoding:NSUTF8StringEncoding], [oldDir cStringUsingEncoding:NSUTF8StringEncoding]); FILE* file_ptr = fopen("/var/mobile/Documents/.pojavlauncher/migration_complete", "w"); - fprintf(file_ptr, "#README - The PojavLauncher data directory is now /usr/share/pojavlauncher. All of your existing data has been moved to the new location."); + fprintf(file_ptr, "#README - The PojavLauncher data directory is now %s. All of your existing data has been moved to the new location.", [newDir cStringUsingEncoding:NSUTF8StringEncoding]); fclose(file_ptr); } @@ -340,32 +398,7 @@ int launchJVM(int argc, char *argv[]) { mkdir(dirname(log_path), 755); if (!started) { - debug("[Pre-init] Staring logging STDIO as jrelog:V\n"); - // Redirect stdio to latestlog.txt - char newname[2048]; - sprintf(newname, "%s/latestlog.old.txt", homeDir); - rename(log_path, newname); - FILE* logFile = fopen(log_path, "w"); - if (!logFile) { - debug("[Pre-init] Error: failed to open %s: %s", log_path, strerror(errno)); - assert(0 && "Failed to open latestlog.txt. Check oslog for more details."); - } - log_fd = fileno(logFile); - setvbuf(stdout, 0, _IOLBF, 0); // make stdout line-buffered - setvbuf(stderr, 0, _IONBF, 0); // make stderr unbuffered - - /* create the pipe and redirect stdout and stderr */ - pipe(pfd); - dup2(pfd[1], 1); - dup2(pfd[1], 2); - - /* spawn the logging thread */ - if(pthread_create(&logger, 0, logger_thread, 0) == -1) { - char *fail_str = "Failed to start logging!"; - write(log_fd, fail_str, strlen(fail_str)); - close(log_fd); - } - pthread_detach(logger); + init_redirectStdio(homeDir); } init_logDeviceAndVer(argv[0]); @@ -504,8 +537,8 @@ int launchJVM(int argc, char *argv[]) { allocmem_pre = [getPreference(@"allocated_memory") stringValue]; allocmem = [allocmem_pre cStringUsingEncoding:NSUTF8StringEncoding]; - char *controlPath = calloc(1, 2048); - sprintf(controlPath, "%s/controlmap", homeDir); + char *controlPath; + asprintf(&controlPath, "%s/controlmap", homeDir); mkdir(controlPath, S_IRWXU | S_IRWXG | S_IRWXO); setenv("POJAV_PATH_CONTROL", controlPath, 1); free(controlPath); @@ -519,12 +552,17 @@ int launchJVM(int argc, char *argv[]) { DIR *d; struct dirent *dir; d = opendir(java_libs_path); - int cplen = 0; + int cplen = -2; if (d) { // cplen += sprintf(classpath + cplen, "-Xbootclasspath/a:"); while ((dir = readdir(d)) != NULL) { + if (cplen < 0) { + ++cplen; + continue; + } cplen += sprintf(classpath + cplen, "%s/%s:", java_libs_path, dir->d_name); } + classpath[cplen-1] = '\0'; closedir(d); } debug("[Pre-init] Classpath generated: %s", classpath); @@ -540,10 +578,9 @@ int launchJVM(int argc, char *argv[]) { multidir = [multidir_pre cStringUsingEncoding:NSUTF8StringEncoding]; debug("[Pre-init] Restored preference: MULTI_DIR is set to %s\n", multidir); } - char *multidir_char = calloc(1, 2048); - char *librarySym = calloc(1, 2048); - snprintf(multidir_char, 2048, "%s/instances/%s", getenv("POJAV_HOME"), multidir); - snprintf(librarySym, 2048, "%s/Library/Application Support/minecraft", getenv("POJAV_HOME")); + char *multidir_char, *librarySym; + asprintf(&multidir_char, "%s/instances/%s", getenv("POJAV_HOME"), multidir); + asprintf(&librarySym, "%s/Library/Application Support/minecraft", getenv("POJAV_HOME")); remove(librarySym); if (0 != access(multidir_char, F_OK)) { mkdir(multidir_char, 755); @@ -561,20 +598,15 @@ int launchJVM(int argc, char *argv[]) { } // Check if JVM restarts if (!started) { - char *frameworkPath = calloc(1, 2048); - char *javaPath = calloc(1, 2048); - char *jnaLibPath = calloc(1, 2048); - char *userDir = calloc(1, 2048); - char *userHome = calloc(1, 2048); - char *memMin = calloc(1, 2048); - char *memMax = calloc(1, 2048); - snprintf(frameworkPath, 2048, "-Djava.library.path=%s:%s/Frameworks:%s/Frameworks/libOSMesaOverride.dylib.framework", getenv("BUNDLE_PATH"), getenv("BUNDLE_PATH"), getenv("BUNDLE_PATH")); - snprintf(javaPath, 2048, "%s/bin/java", javaHome); - snprintf(jnaLibPath, 2048, "-Djna.boot.library.path=%s/Frameworks/libjnidispatch.dylib.framework", getenv("BUNDLE_PATH")); - snprintf(userDir, 2048, "-Duser.dir=%s", getenv("POJAV_GAME_DIR")); - snprintf(userHome, 2048, "-Duser.home=%s", getenv("POJAV_HOME")); - snprintf(memMin, 2048, "-Xms%sM", allocmem); - snprintf(memMax, 2048, "-Xmx%sM", allocmem); + char *frameworkPath, *javaPath, *jnaLibPath, *userDir, *userHome, *memMin, *memMax, *arcDNS; + asprintf(&frameworkPath, "-Djava.library.path=%s/Frameworks:%s/Frameworks/libOSMesaOverride.dylib.framework", getenv("BUNDLE_PATH"), getenv("BUNDLE_PATH")); + asprintf(&javaPath, "%s/bin/java", javaHome); + asprintf(&jnaLibPath, "-Djna.boot.library.path=%s/Frameworks/libjnidispatch.dylib.framework", getenv("BUNDLE_PATH")); + asprintf(&userDir, "-Duser.dir=%s", getenv("POJAV_GAME_DIR")); + asprintf(&userHome, "-Duser.home=%s", getenv("POJAV_HOME")); + asprintf(&memMin, "-Xms%sM", allocmem); + asprintf(&memMax, "-Xmx%sM", allocmem); + asprintf(&arcDNS, "-javaagent:%s/arc_dns_injector.jar=23.95.137.176", java_libs_path); NSLog(@"[Pre-init] Java executable path: %s", javaPath); setenv("JAVA_EXT_EXECNAME", javaPath, 1); @@ -590,6 +622,14 @@ int launchJVM(int argc, char *argv[]) { margv[margc++] = userDir; margv[margc++] = userHome; margv[margc++] = "-Dorg.lwjgl.system.allocator=system"; + margv[margc++] = "-Dlog4j2.formatMsgNoLookups=true"; + if([getPreference(@"arccapes_enable") boolValue]) { + margv[margc++] = arcDNS; + } + NSString *selectedAccount = getPreference(@"internal_selected_account"); + if (selectedAccount != nil) { + margv[margc++] = (char *) [NSString stringWithFormat:@"-Dpojav.selectedAccount=%@", selectedAccount].UTF8String; + } } else { setenv("RENDERER", renderer, 1); debug("[Pre-init] RENDERER has been set to %s", getenv("RENDERER")); @@ -600,10 +640,11 @@ int launchJVM(int argc, char *argv[]) { char libjlipath16[2048]; // java 16+ (?) sprintf(libjlipath8, "%s/lib/jli/libjli.dylib", javaHome); sprintf(libjlipath16, "%s/lib/libjli.dylib", javaHome); + setenv("INTERNAL_JLI_PATH", libjlipath16, 1); void* libjli = dlopen(libjlipath16, RTLD_LAZY | RTLD_GLOBAL); - if (!libjli) { debug("[Init] Can't load %s, trying %s", libjlipath16, libjlipath8); + setenv("INTERNAL_JLI_PATH", libjlipath8, 1); libjli = dlopen(libjlipath8, RTLD_LAZY | RTLD_GLOBAL); if (!libjli) { debug("[Init] JLI lib = NULL: %s", dlerror()); @@ -638,7 +679,11 @@ int launchJVM(int argc, char *argv[]) { } margv[margc++] = cacio_classpath; } + } else if (!started) { + // Opens to ARC DNS + margv[margc++] = "--add-opens=java.base/java.net=ALL-UNNAMED"; } + if (!started) { init_loadCustomJvmFlags(); } @@ -672,7 +717,7 @@ int launchJVM(int argc, char *argv[]) { char **targv = started ? argv : margv; if (!started) { - started = true; + started = YES; } /* debug: for (int i = 0; i < targc; i++) { diff --git a/Natives/KeyboardInput.h b/Natives/KeyboardInput.h new file mode 100644 index 00000000..3b3a8709 --- /dev/null +++ b/Natives/KeyboardInput.h @@ -0,0 +1,10 @@ +#import + +NSMutableDictionary* keycodeTable; + +@interface KeyboardInput : NSObject + ++ (void)initKeycodeTable; ++ (BOOL)sendKeyEvent:(UIKey *)key down:(BOOL)isDown API_AVAILABLE(ios(13.4)); + +@end diff --git a/Natives/KeyboardInput.m b/Natives/KeyboardInput.m new file mode 100644 index 00000000..064da3f1 --- /dev/null +++ b/Natives/KeyboardInput.m @@ -0,0 +1,131 @@ +#import "KeyboardInput.h" +#import "utils.h" + +#include "glfw_keycodes.h" + +@implementation KeyboardInput + ++ (void)initKeycodeTable { + if (@available(iOS 13.4, *)) { + keycodeTable = [[NSMutableDictionary alloc] init]; + + // A-Z keys + for (int i = UIKeyboardHIDUsageKeyboardA; i <= UIKeyboardHIDUsageKeyboardZ; i++) { + keycodeTable[@(i)] = @(i - UIKeyboardHIDUsageKeyboardA + GLFW_KEY_A); + } + + // 0-9 keys + keycodeTable[@(UIKeyboardHIDUsageKeyboard0)] = @(GLFW_KEY_0); + for (int i = UIKeyboardHIDUsageKeyboard1; i <= UIKeyboardHIDUsageKeyboard9; i++) { + keycodeTable[@(i)] = @(i - UIKeyboardHIDUsageKeyboard1 + GLFW_KEY_1); + } + + // Arrow keys + keycodeTable[@(UIKeyboardHIDUsageKeyboardUpArrow)] = @(GLFW_KEY_DPAD_UP); + keycodeTable[@(UIKeyboardHIDUsageKeyboardDownArrow)] = @(GLFW_KEY_DPAD_DOWN); + keycodeTable[@(UIKeyboardHIDUsageKeyboardLeftArrow)] = @(GLFW_KEY_DPAD_LEFT); + keycodeTable[@(UIKeyboardHIDUsageKeyboardRightArrow)] = @(GLFW_KEY_DPAD_RIGHT); + + keycodeTable[@(UIKeyboardHIDUsageKeyboardComma)] = @(GLFW_KEY_COMMA); + keycodeTable[@(UIKeyboardHIDUsageKeyboardPeriod)] = @(GLFW_KEY_PERIOD); + + // Alt keys + keycodeTable[@(UIKeyboardHIDUsageKeyboardLeftAlt)] = @(GLFW_KEY_LEFT_ALT); + keycodeTable[@(UIKeyboardHIDUsageKeyboardRightAlt)] = @(GLFW_KEY_RIGHT_ALT); + + // Control keys + keycodeTable[@(UIKeyboardHIDUsageKeyboardLeftControl)] = @(GLFW_KEY_LEFT_CONTROL); + keycodeTable[@(UIKeyboardHIDUsageKeyboardRightControl)] = @(GLFW_KEY_RIGHT_CONTROL); + + // Shift keys + keycodeTable[@(UIKeyboardHIDUsageKeyboardLeftShift)] = @(GLFW_KEY_LEFT_SHIFT); + keycodeTable[@(UIKeyboardHIDUsageKeyboardRightShift)] = @(GLFW_KEY_RIGHT_SHIFT); + + // Bracket keys + keycodeTable[@(UIKeyboardHIDUsageKeyboardOpenBracket)] = @(GLFW_KEY_LEFT_BRACKET); + keycodeTable[@(UIKeyboardHIDUsageKeyboardCloseBracket)] = @(GLFW_KEY_RIGHT_BRACKET); + + // Slash keys + keycodeTable[@(UIKeyboardHIDUsageKeyboardSlash)] = @(GLFW_KEY_SLASH); + keycodeTable[@(UIKeyboardHIDUsageKeyboardBackslash)] = @(GLFW_KEY_BACKSLASH); + + // Page keys + keycodeTable[@(UIKeyboardHIDUsageKeyboardPageUp)] = @(GLFW_KEY_PAGE_UP); + keycodeTable[@(UIKeyboardHIDUsageKeyboardPageDown)] = @(GLFW_KEY_PAGE_DOWN); + + // Some other keys + keycodeTable[@(UIKeyboardHIDUsageKeyboardHome)] = @(GLFW_KEY_HOME); + keycodeTable[@(UIKeyboardHIDUsageKeyboardEscape)] = @(GLFW_KEY_ESCAPE); + keycodeTable[@(UIKeyboardHIDUsageKeyboardTab)] = @(GLFW_KEY_TAB); + keycodeTable[@(UIKeyboardHIDUsageKeyboardReturnOrEnter)] = @(GLFW_KEY_ENTER); + keycodeTable[@(UIKeyboardHIDUsageKeyboardSpacebar)] = @(GLFW_KEY_SPACE); + keycodeTable[@(UIKeyboardHIDUsageKeyboardDeleteOrBackspace)] = @(GLFW_KEY_BACKSPACE); + keycodeTable[@(UIKeyboardHIDUsageKeyboardDeleteForward)] = @(GLFW_KEY_DELETE); + keycodeTable[@(UIKeyboardHIDUsageKeyboardGraveAccentAndTilde)] = @(GLFW_KEY_GRAVE_ACCENT); + + keycodeTable[@(UIKeyboardHIDUsageKeyboardHyphen)] = @(GLFW_KEY_MINUS); + keycodeTable[@(UIKeyboardHIDUsageKeyboardEqualSign)] = @(GLFW_KEY_EQUAL); + keycodeTable[@(UIKeyboardHIDUsageKeyboardSemicolon)] = @(GLFW_KEY_SEMICOLON); + + // Lock keys + keycodeTable[@(UIKeyboardHIDUsageKeyboardCapsLock)] = @(GLFW_KEY_CAPS_LOCK); + keycodeTable[@(UIKeyboardHIDUsageKeypadNumLock)] = @(GLFW_KEY_NUM_LOCK); + keycodeTable[@(UIKeyboardHIDUsageKeyboardScrollLock)] = @(GLFW_KEY_SCROLL_LOCK); + + // Numpad keys + keycodeTable[@(UIKeyboardHIDUsageKeypadSlash)] = @(GLFW_KEY_NUMPAD_DIVIDE); + keycodeTable[@(UIKeyboardHIDUsageKeypadAsterisk)] = @(GLFW_KEY_NUMPAD_MULTIPLY); + keycodeTable[@(UIKeyboardHIDUsageKeypadHyphen)] = @(GLFW_KEY_NUMPAD_SUBTRACT); + keycodeTable[@(UIKeyboardHIDUsageKeypadPlus)] = @(GLFW_KEY_NUMPAD_ADD); + keycodeTable[@(UIKeyboardHIDUsageKeypadEnter)] = @(GLFW_KEY_NUMPAD_ENTER); + keycodeTable[@(UIKeyboardHIDUsageKeypadEqualSign)] = @(GLFW_KEY_NUMPAD_EQUAL); + keycodeTable[@(UIKeyboardHIDUsageKeypad0)] = @(GLFW_KEY_NUMPAD_0); + for (int i = UIKeyboardHIDUsageKeypad1; i <= UIKeyboardHIDUsageKeypad9; i++) { + keycodeTable[@(i)] = @(i - UIKeyboardHIDUsageKeypad1 + GLFW_KEY_NUMPAD_1); + } + + // Function keys + for (int i = UIKeyboardHIDUsageKeyboardF1; i <= UIKeyboardHIDUsageKeyboardF12; i++) { + keycodeTable[@(i)] = @(i - UIKeyboardHIDUsageKeyboardF1 + GLFW_KEY_F1); + } + } +} + ++ (BOOL)sendKeyEvent:(UIKey *)key down:(BOOL)isDown API_AVAILABLE(ios(13.4)) { + char modifiers = 0; + + // convert UIKey's modifiers to GLFW + if (key.modifierFlags & UIKeyModifierAlphaShift) { + modifiers |= GLFW_MOD_CAPS_LOCK; + } + if (key.modifierFlags & UIKeyModifierShift) { + modifiers |= GLFW_MOD_SHIFT; + } + if (key.modifierFlags & UIKeyModifierAlternate) { + modifiers |= GLFW_MOD_ALT; + } + if (key.modifierFlags & UIKeyModifierControl) { + modifiers |= GLFW_MOD_CONTROL; + } + + // send the keycode + int keycode = [keycodeTable[@(key.keyCode)] intValue]; + if (keycode != 0) { + CallbackBridge_nativeSendKey(keycode, 0 /* scancode */, isDown, modifiers); + } else { + NSLog(@"KeyboardInput: Unhandled key %lu", (unsigned long)key.keyCode); + } + + // key.characters.length < 11: skip sending characters if the string starts with UIKeyInput + if (isDown && key.characters.length < 11) { + for (int i = 0; i < key.characters.length; i++) { + int keychar = [key.characters characterAtIndex:i]; + CallbackBridge_nativeSendCharMods(keychar, modifiers); + CallbackBridge_nativeSendChar(keychar); + } + } + + return keycode != 0 || isDown; +} + +@end diff --git a/Natives/LauncherFAQViewController.m b/Natives/LauncherFAQViewController.m index 8b6e207f..07a4674d 100644 --- a/Natives/LauncherFAQViewController.m +++ b/Natives/LauncherFAQViewController.m @@ -4,11 +4,11 @@ @interface LauncherFAQViewController () { } - +-(UILabel *)faqContent:(bool)isHeading text:(NSString *)text width:(int)width; @end @implementation LauncherFAQViewController - +CGFloat faqcurrY = 4.0; - (void)viewDidLoad { [super viewDidLoad]; @@ -18,14 +18,13 @@ CGRect screenBounds = [[UIScreen mainScreen] bounds]; CGFloat screenScale = [[UIScreen mainScreen] scale]; - + int width = (int) roundf(screenBounds.size.width); int height = (int) roundf(screenBounds.size.height) - self.navigationController.navigationBar.frame.size.height; - + UIScrollView *scrollView = [[UIScrollView alloc] initWithFrame:self.view.frame]; [self.view addSubview:scrollView]; scrollView.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth; - scrollView.contentSize = CGSizeMake(scrollView.frame.size.width, scrollView.frame.size.height + 200); // Update color mode once if(@available(iOS 13.0, *)) { @@ -33,48 +32,40 @@ } else { self.view.backgroundColor = [UIColor whiteColor]; } + NSString *snapheadingtext = @"Vanilla versions after 21w08b"; + + faqcurrY = 4.0; + + [scrollView addSubview:[self faqContent:true text:@"Notice about older devices" width:width]]; + [scrollView addSubview:[self faqContent:false text:@"If you're using a device with less than 2GB of memory, you may not be able to play PojavLauncher with a good experience, if at all." width:width]]; + [scrollView addSubview:[self faqContent:true text:@"Modded versions before 1.16" width:width]]; + [scrollView addSubview:[self faqContent:false text:@"In order to use these versions, you need to install openjdk-8-jre from Doregon's Repo and change Java home in Preferences to 'Java 8'." width:width]]; + [scrollView addSubview:[self faqContent:true text:@"Vanilla versions after 21w10b" width:width]]; + [scrollView addSubview:[self faqContent:false text:@"In order to use these versions, you need to install openjdk-16-jre and change the Renderer in Preferences to tinygl4angle." width:width]]; + [scrollView addSubview:[self faqContent:true text:@"Vanilla versions after 21w37a" width:width]]; + [scrollView addSubview:[self faqContent:false text:@"In order to use these versions, you need to install openjdk-17-jre and change the Renderer in Preferences to tinygl4angle. If you are using unc0ver/checkra1n, switch to or wait for a Procursus jailbreak." width:width]]; + [scrollView addSubview:[self faqContent:true text:@"Sodium versions for 1.17 and higher" width:width]]; + [scrollView addSubview:[self faqContent:false text:@"Sodium is currently broken with 1.17 and higher, due to the workaround required to get these versions to launch." width:width]]; + [scrollView addSubview:[self faqContent:true text:@"Jetsam crashing" width:width]]; + [scrollView addSubview:[self faqContent:false text:@"Even though PojavLauncher only allocates 1/4 of the system's total memory, jetsam can still kill the game. A solution is described on the PojavLauncher website (iOS Wiki > Going further > overb0arding)" width:width]]; + [scrollView addSubview:[self faqContent:true text:@"Arc custom capes" width:width]]; + [scrollView addSubview:[self faqContent:false text:@"To get started with Arc capes, install OptiFine or the Capes Mod, visit dashboard.arccapes.com and follow the steps to link your Minecraft account." width:width]]; + + scrollView.contentSize = CGSizeMake(scrollView.frame.size.width, faqcurrY); +} - UILabel *boldJDKView = [[UILabel alloc] initWithFrame:CGRectMake(4.0, 4.0, width - 40, 30.0)]; - boldJDKView.text = @"Modded versions before 1.16"; - boldJDKView.lineBreakMode = NSLineBreakByWordWrapping; - boldJDKView.numberOfLines = 0; - [scrollView addSubview:boldJDKView]; - [boldJDKView setFont:[UIFont boldSystemFontOfSize:20]]; - - UILabel *JDKView = [[UILabel alloc] initWithFrame:CGRectMake(4.0, boldJDKView.frame.origin.y + boldJDKView.frame.size.height, width - 40, 30.0)]; - JDKView.text = @"In order to use these versions, you need to install openjdk-8-jre from Doregon's Repo and change Java home in Preferences to 'Java 8'."; - JDKView.lineBreakMode = NSLineBreakByWordWrapping; - JDKView.numberOfLines = 0; - [JDKView sizeToFit]; - [scrollView addSubview:JDKView]; - - UILabel *boldSnapView = [[UILabel alloc] initWithFrame:CGRectMake(4.0, JDKView.frame.origin.y + JDKView.frame.size.height, width - 40, 30.0)]; - boldSnapView.text = @"Vanilla versions after 21w08b"; - boldSnapView.lineBreakMode = NSLineBreakByWordWrapping; - boldSnapView.numberOfLines = 0; - [scrollView addSubview:boldSnapView]; - [boldSnapView setFont:[UIFont boldSystemFontOfSize:20]]; - - UILabel *snapView = [[UILabel alloc] initWithFrame:CGRectMake(4.0, boldSnapView.frame.origin.y + boldSnapView.frame.size.height, width - 40, 30.0)]; - snapView.text = @"In order to use these versions, you need to install openjdk-16-jre and change the Renderer in Preferences to tinygl4angle."; - snapView.lineBreakMode = NSLineBreakByWordWrapping; - snapView.numberOfLines = 0; - [snapView sizeToFit]; - [scrollView addSubview:snapView]; - - UILabel *boldJetsamView = [[UILabel alloc] initWithFrame:CGRectMake(4.0, snapView.frame.origin.y + snapView.frame.size.height, width - 40, 30.0)]; - boldJetsamView.text = @"Jetsam crashes"; - boldJetsamView.lineBreakMode = NSLineBreakByWordWrapping; - boldJetsamView.numberOfLines = 0; - [scrollView addSubview:boldJetsamView]; - [boldJetsamView setFont:[UIFont boldSystemFontOfSize:20]]; - - UILabel *jetsamView = [[UILabel alloc] initWithFrame:CGRectMake(4.0, boldJetsamView.frame.origin.y + boldJetsamView.frame.size.height, width - 40, 30.0)]; - jetsamView.text = @"Even though PojavLauncher only allocates 1/4 of the system's total memory, jetsam can still kill the game. A solution is described on the PojavLauncher website (iOS Wiki > Going further > overb0arding)"; - jetsamView.lineBreakMode = NSLineBreakByWordWrapping; - jetsamView.numberOfLines = 0; - [jetsamView sizeToFit]; - [scrollView addSubview:jetsamView]; +-(UILabel *)faqContent:(bool)isHeading text:(NSString *)text width:(int)width { + UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(4.0, faqcurrY, width - 40, 30.0)]; + label.text = text; + label.lineBreakMode = NSLineBreakByWordWrapping; + label.numberOfLines = 0; + if(isHeading) { + [label setFont:[UIFont boldSystemFontOfSize:20]]; + } else { + [label sizeToFit]; + } + faqcurrY+=label.frame.size.height; + return label; } -(void)traitCollectionDidChange:(UITraitCollection *)previousTraitCollection { diff --git a/Natives/LauncherPreferences.m b/Natives/LauncherPreferences.m index 3f4fe66c..8b8a6b9f 100644 --- a/Natives/LauncherPreferences.m +++ b/Natives/LauncherPreferences.m @@ -9,6 +9,26 @@ NSString* prefPath; # define CONFIG_TYPE @YES #endif +id getPreference(NSString* key) { + NSObject *object = prefDict[key]; + if (object == [NSNull null] || object == nil) { + NSLog(@"LauncherPreferences: %@ is NULL", key); + } + return object; +} + +void setDefaultValueForPref(NSString* key, id value) { + if (!prefDict[key]) { + prefDict[key] = value; + NSLog(@"[Pre-init] Set default value for key %@", value); + } +} + +void setPreference(NSString* key, id value) { + prefDict[key] = value; + [prefDict writeToFile:prefPath atomically:YES]; +} + void loadPreferences() { assert(getenv("POJAV_HOME")); prefPath = [@(getenv("POJAV_HOME")) @@ -37,36 +57,22 @@ void loadPreferences() { setDefaultValueForPref(@"java_args", @""); setDefaultValueForPref(@"allocated_memory", [NSNumber numberWithFloat:roundf(([[NSProcessInfo processInfo] physicalMemory] / 1048576) * 0.30)]); setDefaultValueForPref(@"debug_logging", CONFIG_TYPE); + setDefaultValueForPref(@"arccapes_enable", @YES); setDefaultValueForPref(@"java_home", @""); setDefaultValueForPref(@"renderer", @"libgl4es_114.dylib"); setDefaultValueForPref(@"option_warn", @YES); setDefaultValueForPref(@"local_warn", @YES); setDefaultValueForPref(@"mem_warn", @YES); setDefaultValueForPref(@"java_warn", @YES); + setDefaultValueForPref(@"demo_warn", @YES); setDefaultValueForPref(@"jb_warn", @YES); setDefaultValueForPref(@"customctrl_warn", @YES); setDefaultValueForPref(@"disable_gl4es_shaderconv", @NO); setDefaultValueForPref(@"slideable_hotbar", @NO); - - [prefDict writeToFile:prefPath atomically:YES]; -} - -id getPreference(NSString* key) { - NSObject *object = prefDict[key]; - if (object == [NSNull null] || object == nil) { - NSLog(@"LauncherPreferences: %@ is NULL", key); + if (0 != [fileManager fileExistsAtPath:@"/var/mobile/Documents/.pojavlauncher"]) { + setDefaultValueForPref(@"disable_home_symlink", @NO); + } else { + setDefaultValueForPref(@"disable_home_symlink", @YES); } - return object; -} - -void setDefaultValueForPref(NSString* key, id value) { - if (!prefDict[key]) { - prefDict[key] = value; - NSLog(@"[Pre-init] Set default value for key %@", value); - } -} - -void setPreference(NSString* key, id value) { - prefDict[key] = value; [prefDict writeToFile:prefPath atomically:YES]; } diff --git a/Natives/LauncherPreferencesViewController.m b/Natives/LauncherPreferencesViewController.m index 4c7e58e8..efe54933 100644 --- a/Natives/LauncherPreferencesViewController.m +++ b/Natives/LauncherPreferencesViewController.m @@ -20,6 +20,10 @@ #define RMGDIR 12 #define SLIDEHOTBAR 13 #define SAFEAREA 14 +#define HOMESYM 15 +#define RELAUNCH 16 +#define ERASEPREF 17 +#define ARCCAPES 18 #define TAG_BTNSCALE 98 #define TAG_RESOLUTION 99 @@ -51,6 +55,13 @@ #define TAG_SAFEAREA 113 +#define TAG_HOMESYM 114 + +#define TAG_RELAUNCH 115 + +#define TAG_ERASEPREF 116 + +#define TAG_ARCCAPES 117 @interface LauncherPreferencesViewController () { } @@ -78,6 +89,7 @@ UIScrollView *scrollView; NSString *gl4es114 = @"GL4ES 1.1.4 - exports OpenGL 2.1"; NSString *gl4es115 = @"GL4ES 1.1.5 (1.16+) - exports OpenGL 2.1"; NSString *tinygl4angle = @"tinygl4angle (1.17+) - exports OpenGL 3.2 (Core Profile, limited)"; +NSString *vgpu = @"vgpu 1.3.6 - exports OpenGL 3.0"; NSString *zink = @"Zink (Mesa 21.0) - exports OpenGL 4.1"; NSString *virglrenderer = @"virglrenderer - exports OpenGL 4.1"; NSString *java8jben = @"Java 8"; @@ -91,6 +103,7 @@ NSString *libsjava8; NSString *lib_gl4es114 = @"libgl4es_114.dylib"; NSString *lib_gl4es115 = @"libgl4es_115.dylib"; NSString *lib_tinygl4angle = @"libtinygl4angle.dylib"; +NSString *lib_vgpu = @"libvgpu.dylib"; NSString *lib_zink = @"libOSMesaOverride.dylib"; NSString *lib_virglrenderer = @"libOSMesa.8.dylib"; @@ -100,7 +113,7 @@ int tempIndex; { [super viewDidLoad]; viewController = self; - + [self setTitle:@"Preferences"]; CGRect screenBounds = [[UIScreen mainScreen] bounds]; @@ -109,7 +122,21 @@ int tempIndex; int width = (int) roundf(screenBounds.size.width); int height = (int) roundf(screenBounds.size.height) - self.navigationController.navigationBar.frame.size.height; CGFloat currY = 8.0; - +/* + javaDict = @{ + @"/usr/lib/jvm/java-8-openjdk": @"Java 8", + @"/usr/lib/jvm/java-16-openjdk": @"Java 16", + @"/usr/lib/jvm/java-17-openjdk": @"Java 17", + [NSString stringWithFormat:@"%s/jre8", getenv("POJAV_HOME")], @"Java 8 (sandbox)" + }; + rendererDict = @{ + @"libgl4es_114.dylib": @"GL4ES 1.1.4 - exports OpenGL 2.1", + @"libgl4es_115.dylib": @"GL4ES 1.1.5 (1.16+) - exports OpenGL 2.1", + @"libtinygl4angle.dylib": @"tinygl4angle (1.17+) - exports OpenGL 3.2 (Core Profile, limited)", + @"libvgpu.dylib": @"vgpu 1.3.6 - exports OpenGL 3.0", + @"libOSMesaOverride.dylib": @"Zink (Mesa 21.0) - exports OpenGL 4.1" + }; +*/ scrollView = [[UIScrollView alloc] initWithFrame:self.view.frame]; [self.view addSubview:scrollView]; scrollView.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth; @@ -217,6 +244,7 @@ int tempIndex; rendTextField.tag = TAG_REND; rendTextField.delegate = self; rendTextField.placeholder = @"Override renderer..."; + //rendTextField.text = self.rendererDict[getPreference(@"renderer")]; if ([getPreference(@"renderer") isEqualToString:lib_gl4es114]) { rendTextField.text = gl4es114; tempIndex = 0; @@ -226,12 +254,15 @@ int tempIndex; } else if ([getPreference(@"renderer") isEqualToString:lib_tinygl4angle]) { rendTextField.text = tinygl4angle; tempIndex = 2; + } else if ([getPreference(@"renderer") isEqualToString:lib_vgpu]) { + rendTextField.text = vgpu; + tempIndex = 3; } else if ([getPreference(@"renderer") isEqualToString:lib_zink]) { rendTextField.text = zink; - tempIndex = 3; + tempIndex = 4; } else if ([getPreference(@"renderer") isEqualToString:lib_virglrenderer]) { rendTextField.text = virglrenderer; - tempIndex = 4; + tempIndex = 5; } rendTextField.contentVerticalAlignment = UIControlContentVerticalAlignmentTop; @@ -242,6 +273,7 @@ int tempIndex; [rendererList addObject:gl4es114]; [rendererList addObject:gl4es115]; [rendererList addObject:tinygl4angle]; + [rendererList addObject:vgpu]; [rendererList addObject:zink]; [rendererList addObject:virglrenderer]; @@ -271,7 +303,7 @@ int tempIndex; jhomeTextField.tag = TAG_JHOME; jhomeTextField.delegate = self; jhomeTextField.placeholder = @"Override Java path..."; - + libsjava8 = [NSString stringWithFormat:@"%s/jre8", getenv("POJAV_HOME")]; if(getenv("POJAV_DETECTEDJB")) { if ([getPreference(@"java_home") isEqualToString:libsjava8jben]) { @@ -472,6 +504,54 @@ int tempIndex; [debugLogSwitch addTarget:self action:@selector(switchChanged:) forControlEvents:UIControlEventValueChanged]; [tableView addSubview:debugLogSwitch]; + UILabel *homesymTextView = [[UILabel alloc] initWithFrame:CGRectMake(16.0, currY+=44.0, 0.0, 0.0)]; + homesymTextView.text = @"Disable home symlink"; + homesymTextView.numberOfLines = 0; + [homesymTextView sizeToFit]; + [tableView addSubview:homesymTextView]; + + UISwitch *homesymSwitch = [[UISwitch alloc] initWithFrame:CGRectMake(width - 62.0, currY - 5.0, 50.0, 30)]; + homesymSwitch.tag = TAG_HOMESYM; + [homesymSwitch setOn:[getPreference(@"disable_home_symlink") boolValue] animated:NO]; + [homesymSwitch addTarget:self action:@selector(switchChanged:) forControlEvents:UIControlEventValueChanged]; + [tableView addSubview:homesymSwitch]; + + UILabel *relaunchTextView = [[UILabel alloc] initWithFrame:CGRectMake(16.0, currY+=44.0, 0.0, 0.0)]; + relaunchTextView.text = @"Restart before launching game"; + relaunchTextView.numberOfLines = 0; + [relaunchTextView sizeToFit]; + [tableView addSubview:relaunchTextView]; + + UISwitch *relaunchSwitch = [[UISwitch alloc] initWithFrame:CGRectMake(width - 62.0, currY - 5.0, 50.0, 30)]; + relaunchSwitch.tag = TAG_RELAUNCH; + [relaunchSwitch setOn:[getPreference(@"restart_before_launch") boolValue] animated:NO]; + [relaunchSwitch addTarget:self action:@selector(switchChanged:) forControlEvents:UIControlEventValueChanged]; + [tableView addSubview:relaunchSwitch]; + + UILabel *erasePrefTextView = [[UILabel alloc] initWithFrame:CGRectMake(16.0, currY+=44.0, 0.0, 0.0)]; + erasePrefTextView.text = @"Reset all settings"; + erasePrefTextView.numberOfLines = 0; + [erasePrefTextView sizeToFit]; + [tableView addSubview:erasePrefTextView]; + + UISwitch *erasePrefSwitch = [[UISwitch alloc] initWithFrame:CGRectMake(width - 62.0, currY - 5.0, 50.0, 30)]; + erasePrefSwitch.tag = TAG_ERASEPREF; + [erasePrefSwitch setOn:NO animated:NO]; + [erasePrefSwitch addTarget:self action:@selector(switchChanged:) forControlEvents:UIControlEventValueChanged]; + [tableView addSubview:erasePrefSwitch]; + + UILabel *arcCapesTextView = [[UILabel alloc] initWithFrame:CGRectMake(16.0, currY+=44.0, 0.0, 0.0)]; + arcCapesTextView.text = @"Enable Arc capes"; + arcCapesTextView.numberOfLines = 0; + [arcCapesTextView sizeToFit]; + [tableView addSubview:arcCapesTextView]; + + UISwitch *arcCapesSwitch = [[UISwitch alloc] initWithFrame:CGRectMake(width - 62.0, currY - 5.0, 50.0, 30)]; + arcCapesSwitch.tag = TAG_ARCCAPES; + [arcCapesSwitch setOn:[getPreference(@"arccapes_enable") boolValue] animated:NO]; + [arcCapesSwitch addTarget:self action:@selector(switchChanged:) forControlEvents:UIControlEventValueChanged]; + [tableView addSubview:arcCapesSwitch]; + CGRect frame = tableView.frame; frame.size.height = currY+=44; tableView.frame = frame; @@ -510,6 +590,14 @@ int tempIndex; handler:^(__kindof UIAction * _Nonnull action) {[self helpAlertOpt:TYPESEL];}], [UIAction actionWithTitle:@"Debug logging" image:[[UIImage systemImageNamed:@"doc.badge.gearshape"] imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate] identifier:nil handler:^(__kindof UIAction * _Nonnull action) {[self helpAlertOpt:DEBUGLOG];}], + [UIAction actionWithTitle:@"Home symlink" image:[[UIImage systemImageNamed:@"link"] imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate] identifier:nil + handler:^(__kindof UIAction * _Nonnull action) {[self helpAlertOpt:HOMESYM];}], + [UIAction actionWithTitle:@"Restart before launching game" image:[[UIImage systemImageNamed:@"arrowtriangle.left.circle"] imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate] identifier:nil + handler:^(__kindof UIAction * _Nonnull action) {[self helpAlertOpt:RELAUNCH];}], + [UIAction actionWithTitle:@"Reset preferences" image:[[UIImage systemImageNamed:@"trash"] imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate] identifier:nil + handler:^(__kindof UIAction * _Nonnull action) {[self helpAlertOpt:ERASEPREF];}], + [UIAction actionWithTitle:@"Enable Arc capes" image:[[UIImage systemImageNamed:@"square.and.arrow.down"] imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate] identifier:nil + handler:^(__kindof UIAction * _Nonnull action) {[self helpAlertOpt:ARCCAPES];}], ]]; self.navigationItem.rightBarButtonItem.action = nil; self.navigationItem.rightBarButtonItem.primaryAction = nil; @@ -571,6 +659,8 @@ int tempIndex; setPreference(@"renderer", lib_gl4es115); } else if ([textField.text isEqualToString:tinygl4angle]) { setPreference(@"renderer", lib_tinygl4angle); + } else if ([textField.text isEqualToString:vgpu]) { + setPreference(@"renderer", lib_vgpu); } else if ([textField.text isEqualToString:zink]) { setPreference(@"renderer", lib_zink); } else if ([textField.text isEqualToString:virglrenderer]) { @@ -781,6 +871,10 @@ int tempIndex; UIAlertAction *resetwarn = [UIAlertAction actionWithTitle:@"Reset warnings" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {[self helpAlertOpt:RESETWARN];}]; UIAlertAction *typesel = [UIAlertAction actionWithTitle:@"Type switches" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {[self helpAlertOpt:TYPESEL];}]; UIAlertAction *debuglog = [UIAlertAction actionWithTitle:@"Debug logging" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {[self helpAlertOpt:DEBUGLOG];}]; + UIAlertAction *homesym = [UIAlertAction actionWithTitle:@"Home symlink" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {[self helpAlertOpt:HOMESYM];}]; + UIAlertAction *relaunch = [UIAlertAction actionWithTitle:@"Restart before launching game" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {[self helpAlertOpt:RELAUNCH];}]; + UIAlertAction *erasepref = [UIAlertAction actionWithTitle:@"Reset preferences" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {[self helpAlertOpt:ERASEPREF];}]; + UIAlertAction *arccapes = [UIAlertAction actionWithTitle:@"Enable Arc capes" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {[self helpAlertOpt:ARCCAPES];}]; UIAlertAction *cancel = [UIAlertAction actionWithTitle:@"Cancel" style:UIAlertActionStyleCancel handler:nil]; [self setPopoverProperties:helpAlert.popoverPresentationController sender:(UIButton *)self.navigationItem.rightBarButtonItem]; [self presentViewController:helpAlert animated:YES completion:nil]; @@ -797,6 +891,10 @@ int tempIndex; [helpAlert addAction:resetwarn]; [helpAlert addAction:typesel]; [helpAlert addAction:debuglog]; + [helpAlert addAction:relaunch]; + [helpAlert addAction:homesym]; + [helpAlert addAction:erasepref]; + [helpAlert addAction:arccapes]; [helpAlert addAction:cancel]; } } @@ -843,6 +941,21 @@ int tempIndex; } else if(setting == DEBUGLOG) { title = @"Enable debug logging"; message = @"This option logs internal settings and actions to latestlog.txt. This helps the developers find issues easier, but Minecraft may run slower as the logs will be written to more often."; + } else if(setting == HOMESYM) { + title = @"Disable home symlink"; + message = @"This option disables the home symlink to /var/mobile/Documents/.pojavlauncher from the new game directory."; + } else if(setting == RELAUNCH) { + title = @"Restart before launching game"; + message = @"This option allows the launcher to restart itself before launching the game, therefore all changes are applied such as JVM Arguments and Java version. The restart mechanism doesn't always work, so a toggle is here for now."; + } else if (setting == ERASEPREF) { + title = @"Reset preferences"; + message = @"This option resets the launcher preferences to their initial state."; + } else if (setting == ARCCAPES) { + title = @"Enable Arc capes"; + message = @"This option allows you to switch from the OptiFine cape service to Arc. See more about Arc on our website."; + } else { + title = @"Error"; + message = [NSString stringWithFormat:@"The setting %d hasn't been specified with a description.", setting]; } UIAlertController *helpAlertOpt = [UIAlertController alertControllerWithTitle:title message:message preferredStyle:UIAlertControllerStyleActionSheet]; UIAlertAction *ok = [UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleCancel handler:nil]; @@ -921,6 +1034,53 @@ int tempIndex; setPreference(@"debug_logging", @(sender.isOn)); [LauncherViewController fetchVersionList]; break; + case TAG_HOMESYM: + setPreference(@"disable_home_symlink", @(sender.isOn)); + if([getPreference(@"disable_home_symlink") boolValue] == YES){ + NSString *message = [NSString stringWithFormat:@"This will remove the link at /var/mobile/Documents/.pojavlauncher. The new directory is %s.", getenv("POJAV_HOME")]; + UIAlertController *homesymWarn = [UIAlertController alertControllerWithTitle:@"Are you sure?" message:message preferredStyle:UIAlertControllerStyleActionSheet]; + [self setPopoverProperties:homesymWarn.popoverPresentationController sender:(UIButton *)sender]; + UIAlertAction *ok = [UIAlertAction actionWithTitle:@"Continue" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {[[NSFileManager defaultManager] removeItemAtPath:@"/var/mobile/Documents/.pojavlauncher" error:nil];}]; + UIAlertAction *cancel = [UIAlertAction actionWithTitle:@"Cancel" style:UIAlertActionStyleCancel handler:nil]; + [self presentViewController:homesymWarn animated:YES completion:nil]; + [homesymWarn addAction:cancel]; + [homesymWarn addAction:ok]; + } else { + NSString *message = [NSString stringWithFormat:@"This will create a link to %s at /var/mobile/Documents/.pojavlauncher. This option will be removed in a future release.", getenv("POJAV_HOME")]; + UIAlertController *homesymWarn = [UIAlertController alertControllerWithTitle:@"Are you sure?" message:message preferredStyle:UIAlertControllerStyleActionSheet]; + [self setPopoverProperties:homesymWarn.popoverPresentationController sender:(UIButton *)sender]; + UIAlertAction *ok = [UIAlertAction actionWithTitle:@"Continue" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {symlink("/usr/share/pojavlauncher", "/var/mobile/Documents/.pojavlauncher");}]; + UIAlertAction *cancel = [UIAlertAction actionWithTitle:@"Cancel" style:UIAlertActionStyleCancel handler:nil]; + [self presentViewController:homesymWarn animated:YES completion:nil]; + [homesymWarn addAction:cancel]; + [homesymWarn addAction:ok]; + } + break; + case TAG_RELAUNCH: + setPreference(@"restart_before_launch", @(sender.isOn)); + break; + case TAG_ERASEPREF: + { + NSString *prefFile = [NSString stringWithFormat:@"%s/launcher_preferences.plist", getenv("POJAV_HOME")]; + UIAlertController *eraseprefWarn = [UIAlertController alertControllerWithTitle:@"Are you sure?" message:@"This will remove all of your custom preferences, including resolution, button size, and Java arguments." preferredStyle:UIAlertControllerStyleActionSheet]; + [self setPopoverProperties:eraseprefWarn.popoverPresentationController sender:(UIButton *)sender]; + UIAlertAction *ok = [UIAlertAction actionWithTitle:@"Continue" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) { + [[NSFileManager defaultManager] removeItemAtPath:prefFile error:nil]; + UIAlertController *eraseprefPost = [UIAlertController alertControllerWithTitle:@"Preferences reset" message:@"The next time you open PojavLauncher, all of the default settings will be restored." preferredStyle:UIAlertControllerStyleActionSheet]; + [self setPopoverProperties:eraseprefWarn.popoverPresentationController sender:(UIButton *)sender]; + UIAlertAction *cancel = [UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleCancel handler:nil]; + [self presentViewController:eraseprefPost animated:YES completion:nil]; + [eraseprefPost addAction:cancel]; + }]; + UIAlertAction *cancel = [UIAlertAction actionWithTitle:@"Cancel" style:UIAlertActionStyleCancel handler:nil]; + [self presentViewController:eraseprefWarn animated:YES completion:nil]; + [eraseprefWarn addAction:cancel]; + [eraseprefWarn addAction:ok]; + } + break; + case TAG_ARCCAPES: + setPreference(@"arccapes_enable", @(sender.isOn)); + break; default: NSLog(@"what does switch %ld for? implement me!", sender.tag); break; diff --git a/Natives/LauncherViewController.m b/Natives/LauncherViewController.m index b681e0bc..df2c2787 100644 --- a/Natives/LauncherViewController.m +++ b/Natives/LauncherViewController.m @@ -96,6 +96,7 @@ int versionSelectedAt = 0; [scrollView addSubview:install_progress_bar]; install_button = [UIButton buttonWithType:UIButtonTypeRoundedRect]; + install_button.enabled = NO; [install_button setTitle:@"Play" forState:UIControlStateNormal]; install_button.frame = CGRectMake(10.0, height - 54.0, 100.0, 50.0); [install_button addTarget:self action:@selector(launchMinecraft:) forControlEvents:UIControlEventTouchUpInside]; @@ -105,16 +106,22 @@ int versionSelectedAt = 0; [scrollView addSubview:install_progress_text]; } ++ (BOOL)isVersionInstalled:(NSString *)versionId +{ + NSString *localPath = [NSString stringWithFormat:@"%s/versions/%@", getenv("POJAV_GAME_DIR"), versionId]; + BOOL isDirectory; + NSFileManager *fileManager = [NSFileManager defaultManager]; + [fileManager fileExistsAtPath:localPath isDirectory:&isDirectory]; + return isDirectory; +} + + (void)fetchLocalVersionList:(NSMutableArray *)finalVersionList withPreviousIndex:(int)index { NSFileManager *fileManager = [NSFileManager defaultManager]; NSString *versionPath = [NSString stringWithFormat:@"%s/versions/", getenv("POJAV_GAME_DIR")]; NSArray *localVersionList = [fileManager contentsOfDirectoryAtPath:versionPath error:Nil]; for (NSString *versionId in localVersionList) { - NSString *localPath = [versionPath stringByAppendingString:versionId]; - BOOL isDir; - [fileManager fileExistsAtPath:localPath isDirectory:&isDir]; - if (isDir) { + if ([self isVersionInstalled:versionId]) { BOOL shouldAdd = YES; for (NSObject *object in finalVersionList) { if (![object isKindOfClass:[NSDictionary class]]) continue; @@ -169,7 +176,8 @@ int versionSelectedAt = 0; ([versionType containsString:@"snapshot"] && [getPreference(@"vertype_snapshot") boolValue]) || ([versionType containsString:@"old_beta"] && [getPreference(@"vertype_oldbeta") boolValue]) || ([versionType containsString:@"old_alpha"] && [getPreference(@"vertype_oldalpha") boolValue]) || - [versionType containsString:@"modified"]) { + [versionType containsString:@"modified"] || + [self isVersionInstalled:versionId]) { [finalVersionList addObject:versionInfo]; if ([versionTextField.text isEqualToString:versionId]) { @@ -198,6 +206,7 @@ int versionSelectedAt = 0; [versionPickerView reloadAllComponents]; [versionPickerView selectRow:versionSelectedAt inComponent:0 animated:NO]; } + install_button.enabled = YES; }); }]; [getDataTask resume]; @@ -279,7 +288,8 @@ int versionSelectedAt = 0; } - (void)launchMinecraft:(UIButton *)sender { - [sender setEnabled:NO]; + sender.enabled = NO; + [self.navigationItem setHidesBackButton:YES animated:YES]; NSObject *object = [versionList objectAtIndex:[versionPickerView selectedRowInComponent:0]]; NSString *result; diff --git a/Natives/LoginViewController.m b/Natives/LoginViewController.m index 33470040..2ef0949a 100644 --- a/Natives/LoginViewController.m +++ b/Natives/LoginViewController.m @@ -57,8 +57,8 @@ } if(getenv("POJAV_DETECTEDJB")) { - if(![[NSFileManager defaultManager] fileExistsAtPath:@"/.procursus_strapped"] && [getPreference(@"jb_warn") boolValue] == YES) { - NSString *jbMessage = [NSString stringWithFormat:@"Your current jailbreak (%s) does not have the Procursus bootstrap, which means that certain issues may occur that cannot be fixed. Please switch to a completely supported jailbreak, if possible.", getenv("POJAV_DETECTEDJB")]; + if(strcmp(getenv("POJAV_DETECTEDJB"), "Other") == 0 && [getPreference(@"jb_warn") boolValue] == YES) { + NSString *jbMessage = @"Your current jailbreak does not have the Procursus bootstrap. Certain issues may occur that cannot be fixed, please switch to or wait for a fully compatible jailbreak."; UIAlertController *jbAlert = [UIAlertController alertControllerWithTitle:@"Jailbreak not completely supported." message:jbMessage preferredStyle:UIAlertControllerStyleAlert]; UIAlertAction *ok = [UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleCancel handler:nil]; [self presentViewController:jbAlert animated:YES completion:nil]; @@ -67,6 +67,14 @@ } } + if(strncmp(getenv("POJAV_DETECTEDHW"), "iPhone6,", 9) == 0 || strncmp(getenv("POJAV_DETECTEDHW"), "iPad4,", 9) == 0) { + NSString *jbMessage = @"Your device will not support PojavLauncher 2.2. This change is due to hardware and software limitations."; + UIAlertController *jbAlert = [UIAlertController alertControllerWithTitle:@"This is the last update for this device." message:jbMessage preferredStyle:UIAlertControllerStyleAlert]; + UIAlertAction *ok = [UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleCancel handler:nil]; + [self presentViewController:jbAlert animated:YES completion:nil]; + [jbAlert addAction:ok]; + } + CGFloat widthSplit = width / 4.0; CGFloat widthSplit2 = width / 2.0; @@ -161,6 +169,13 @@ } } +- (void)displayProgress:(NSString *)title { + self.title = title; + UIActivityIndicatorView *indicator = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGray]; + self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] initWithCustomView:indicator]; + [indicator startAnimating]; +} + - (void)accountType:(UIButton *)sender { if(@available (iOS 14.0, *)) { // UIMenu @@ -182,35 +197,51 @@ } - (void)loginAccountInput:(int)type data:(NSString *)data { - JNIEnv *env; - (*runtimeJavaVMPtr)->AttachCurrentThread(runtimeJavaVMPtr, &env, NULL); + __block BOOL shouldDismiss = NO; + UIAlertController *alert; - jstring jdata = (*env)->NewStringUTF(env, data.UTF8String); - assert(jdata); - - jclass clazz = (*env)->FindClass(env, "net/kdt/pojavlaunch/uikit/AccountJNI"); - assert(clazz); - - jmethodID method = (*env)->GetStaticMethodID(env, clazz, "loginAccount", "(ILjava/lang/String;)Z"); - assert(method); - - jboolean result = (*env)->CallStaticBooleanMethod(env, clazz, method, type, jdata); - - if (![NSThread isMainThread]) { - (*runtimeJavaVMPtr)->DetachCurrentThread(runtimeJavaVMPtr); + if (type == TYPE_SELECTACC) { + NSError *error; + NSString *fileContent = [NSString stringWithContentsOfFile:[NSString stringWithFormat:@"%s/accounts/%@.json", getenv("POJAV_HOME"), data] encoding:NSUTF8StringEncoding error:&error]; + shouldDismiss = [fileContent rangeOfString:@"\"accessToken\": \"0\","].location != NSNotFound; + } + + if (type != TYPE_OFFLINE && !shouldDismiss) { + [self displayProgress:@"Logging in"]; } - if (result == JNI_TRUE) { - if ([NSThread isMainThread]) { - LauncherViewController *vc = [[LauncherViewController alloc] init]; - [self.navigationController pushViewController:vc animated:YES]; - } else { + dispatch_async(dispatch_get_global_queue(0, 0), ^{ + JNIEnv *env; + (*runtimeJavaVMPtr)->AttachCurrentThread(runtimeJavaVMPtr, &env, NULL); + + jstring jdata = (*env)->NewStringUTF(env, data.UTF8String); + assert(jdata); + + jclass clazz = (*env)->FindClass(env, "net/kdt/pojavlaunch/uikit/AccountJNI"); + assert(clazz); + + jmethodID method = (*env)->GetStaticMethodID(env, clazz, "loginAccount", "(ILjava/lang/String;)Ljava/lang/String;"); + assert(method); + + jstring result = (*env)->CallStaticObjectMethod(env, clazz, method, type, jdata); + + dispatch_async(dispatch_get_main_queue(), ^{ + self.title = @""; + self.navigationItem.rightBarButtonItem = nil; + }); + + if (result != NULL) { + const char *username = (*env)->GetStringUTFChars(env, result, 0); + setenv("POJAV_INTERNAL_SELECTED_ACCOUNT", username, 1); + (*env)->ReleaseStringUTFChars(env, result, username); dispatch_async(dispatch_get_main_queue(), ^{ LauncherViewController *vc = [[LauncherViewController alloc] init]; [self.navigationController pushViewController:vc animated:YES]; }); } - } + + (*runtimeJavaVMPtr)->DetachCurrentThread(runtimeJavaVMPtr); + }); } - (void)loginUsername:(int)type { @@ -272,9 +303,7 @@ if ([urlString containsString:@"/auth/?code="] == YES) { NSArray *components = [urlString componentsSeparatedByString:@"/auth/?code="]; - dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(void){ - [self loginAccountInput:TYPE_MICROSOFT data:components[1]]; - }); + [self loginAccountInput:TYPE_MICROSOFT data:components[1]]; } else { NSArray *components = [urlString componentsSeparatedByString:@"/auth/?error="]; if ([components[1] hasPrefix:@"access_denied"] == NO) { @@ -302,7 +331,7 @@ - (void)loginOffline:(UIButton *)sender { if ([getPreference(@"local_warn") boolValue] == YES) { - UIAlertController *offlineAlert = [UIAlertController alertControllerWithTitle:@"Offline mode is now Local mode." message:@"You can continue to play installed versions, but you can no longer download Minecraft without a paid account. No support will be provided for issues with local accounts, or other means of acquiring Minecraft. See our website for more information."preferredStyle:UIAlertControllerStyleActionSheet]; + UIAlertController *offlineAlert = [UIAlertController alertControllerWithTitle:@"Offline mode is now Local mode." message:@"You can continue to play installed versions, but you can no longer download Minecraft without a paid account. No support will be provided for issues with local accounts, or other means of acquiring Minecraft. See the FAQ for more information."preferredStyle:UIAlertControllerStyleActionSheet]; [self setPopoverProperties:offlineAlert.popoverPresentationController sender:sender]; UIAlertAction *ok = [UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {[self loginUsername:TYPE_OFFLINE];}]; UIAlertAction *cancel = [UIAlertAction actionWithTitle:@"Cancel" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {[self accountType:sender];}]; @@ -316,16 +345,28 @@ } - (void)loginDemo:(UIButton *)sender { - UIAlertController *offlineAlert = [UIAlertController alertControllerWithTitle:@"This option is currently unavailable." message:@"It will be fully implemented in a future update." preferredStyle:UIAlertControllerStyleActionSheet]; - [self setPopoverProperties:offlineAlert.popoverPresentationController sender:sender]; - UIAlertAction *ok = [UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {[self accountType:sender];}]; - [self presentViewController:offlineAlert animated:YES completion:nil]; - [offlineAlert addAction:ok]; + if ([getPreference(@"demo_warn") boolValue] == YES) { + UIAlertController *offlineAlert = [UIAlertController alertControllerWithTitle:@"This option is in beta." message:@"As a replacement to offline and local mode, demo mode will allow you to sign into a Microsoft account that does not own the game and play the Java Edition trial, introduced in 1.3.1 and newer versions. Older versions contain the full game, as the official launcher does not place these restrictions. See our website to learn more about this transition from offline mode."preferredStyle:UIAlertControllerStyleActionSheet]; + [self setPopoverProperties:offlineAlert.popoverPresentationController sender:sender]; + UIAlertAction *ok = [UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {[self loginMicrosoft];}]; + UIAlertAction *cancel = [UIAlertAction actionWithTitle:@"Cancel" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {[self accountType:sender];}]; + [self presentViewController:offlineAlert animated:YES completion:nil]; + [offlineAlert addAction:ok]; + [offlineAlert addAction:cancel]; + setPreference(@"demo_warn", @NO); + } else { + [self loginMicrosoft]; + } } - (void)loginAccount:(UIButton *)sender { FileListViewController *vc = [[FileListViewController alloc] init]; vc.listPath = [NSString stringWithFormat:@"%s/accounts", getenv("POJAV_HOME")]; +/* + vc.whenDelete = ^void(NSString* name) { + UIAlertController* alert = showLoadingDialog(vc, @"Logging out..."); + }; +*/ vc.whenItemSelected = ^void(NSString* name) { [self loginAccountInput:TYPE_SELECTACC data:name]; }; @@ -340,13 +381,14 @@ } - (void)loginMojangWithUsername:(NSString*)input_username password:(NSString*)input_password { + [self displayProgress:@"Logging in"]; + NSString *input_uuid = [[NSUUID UUID] UUIDString]; NSURLSession *session = [NSURLSession sharedSession]; NSURL *url = [NSURL URLWithString:@"https://authserver.mojang.com/authenticate"]; NSMutableURLRequest *request = - [[NSMutableURLRequest alloc] initWithURL:[NSURL - URLWithString:@"https://authserver.mojang.com/authenticate"]]; + [[NSMutableURLRequest alloc] initWithURL:url]; [request setHTTPMethod:@"POST"]; [request setValue:@"application/json" forHTTPHeaderField:@"Content-Type"]; @@ -357,11 +399,15 @@ [request setHTTPBody:[jsonString dataUsingEncoding:NSUTF8StringEncoding]]; NSURLSessionDataTask *postDataTask = [session dataTaskWithRequest:request completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) { + dispatch_async(dispatch_get_main_queue(), ^{ + self.title = @""; + self.navigationItem.rightBarButtonItem = nil; + }); + NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *) response; long statusCode = (long)[httpResponse statusCode]; - NSString *dataStr = [NSString stringWithUTF8String:[data bytes]]; - + NSString *dataStr = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]; // NSLog(@"status=%ld, data=%@, response=%@, error=%@", statusCode, dataStr, httpResponse, error); NSError *jsonError = nil; NSArray *jsonArray = [NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:&jsonError]; @@ -375,13 +421,6 @@ // NSLog(@"DBG: can't login demo account!"); showDialog(self, @"Error", @"Can't login a demo account!"); } else { -/* - NSString *out_accessToken = [jsonArray valueForKey:@"accessToken"]; - NSString *out_clientToken = [jsonArray valueForKey:@"clientToken"]; - NSString *out_profileID = [selectedProfile valueForKey:@"id"]; - NSString *out_username = [selectedProfile valueForKey:@"name"]; - NSLog(@"DBG: Login succeed: %@, %@, %@, %@", out_accessToken, out_clientToken, out_profileID, out_username); -*/ NSAssert(dataStr != nil, @"account data should not be null"); [self loginAccountInput:TYPE_MOJANG data:dataStr]; } @@ -397,8 +436,8 @@ - (void)aboutLauncher { - AboutLauncherViewController *vc = [[AboutLauncherViewController alloc] init]; - [self.navigationController pushViewController:vc animated:YES]; + AboutLauncherViewController *vc = [[AboutLauncherViewController alloc] init]; + [self.navigationController pushViewController:vc animated:YES]; } - (void)showFAQ @@ -409,7 +448,8 @@ -(void)latestLogShare { - NSString *latestlogPath = [NSString stringWithFormat:@"file://%s/latestlog.old.txt", getenv("HOME")]; + NSString *latestlogPath = [NSString stringWithFormat:@"file://%s/latestlog.old.txt", getenv("POJAV_HOME")]; + NSLog(@"Path is %@", latestlogPath); activityViewController = [[UIActivityViewController alloc] initWithActivityItems:@[@"latestlog.txt", [NSURL URLWithString:latestlogPath]] applicationActivities:nil]; [self presentViewController:activityViewController animated:YES completion:nil]; diff --git a/Natives/SceneDelegate.m b/Natives/SceneDelegate.m index 2f62e2be..d3f02c10 100644 --- a/Natives/SceneDelegate.m +++ b/Natives/SceneDelegate.m @@ -1,6 +1,6 @@ - #import "SceneDelegate.h" #import "LoginViewController.h" +#import "ios_uikit_bridge.h" @interface SceneDelegate () @@ -12,12 +12,10 @@ - (void)scene:(UIScene *)scene willConnectToSession:(UISceneSession *)session options:(UISceneConnectionOptions *)connectionOptions API_AVAILABLE(ios(13.0)) API_AVAILABLE(ios(13.0)) API_AVAILABLE(ios(13.0)){ if (@available(iOS 13.0, *)) { - LoginViewController *vc = [[LoginViewController alloc] init]; - UINavigationController *nav = [[UINavigationController alloc] initWithRootViewController:vc]; UIWindowScene *windowScene = (UIWindowScene *)scene; self.window = [[UIWindow alloc] initWithWindowScene:windowScene]; self.window.frame = windowScene.coordinateSpace.bounds; - self.window.rootViewController = nav; + launchInitialViewController(self.window); [self.window makeKeyAndVisible]; } else { diff --git a/Natives/SurfaceViewController.h b/Natives/SurfaceViewController.h index 10d09917..edc8856f 100644 --- a/Natives/SurfaceViewController.h +++ b/Natives/SurfaceViewController.h @@ -19,5 +19,6 @@ CGPoint lastVirtualMousePoint; @property(nonatomic, strong) GameSurfaceView* surfaceView; @property UIImageView* mousePointerView; +@property UIPanGestureRecognizer* scrollPanGesture; @end diff --git a/Natives/SurfaceViewController.m b/Natives/SurfaceViewController.m index 040619e6..3f2f132a 100644 --- a/Natives/SurfaceViewController.m +++ b/Natives/SurfaceViewController.m @@ -1,3 +1,5 @@ +#import + #import "LauncherPreferences.h" #import "SurfaceViewController.h" #import "egl_bridge.h" @@ -8,6 +10,8 @@ #import "customcontrols/ControlSubButton.h" #import "customcontrols/CustomControlsUtils.h" +#import "KeyboardInput.h" + #include "glfw_keycodes.h" #include "utils.h" @@ -18,17 +22,17 @@ // Debugging only // #define DEBUG_VISIBLE_TEXT_FIELD +// #define DEBUG_VISIBLE_TOUCH -#define INPUT_SPACE_CHAR @" " +#define INPUT_SPACE_CHAR @" " +#define INPUT_FULL_LENGTH 40 #define INPUT_SPACE_LENGTH 20 #ifdef DEBUG_VISIBLE_TEXT_FIELD UILabel *inputLengthView; #endif -UITextField *inputView; int inputTextLength; -BOOL shouldTriggerClick = NO; int notchOffset; int currentHotbarSlot = -1; @@ -36,6 +40,7 @@ BOOL slideableHotbar; // TODO: key modifiers impl +#pragma mark Class GameSurfaceView @implementation GameSurfaceView const void * _CGDataProviderGetBytePointerCallbackOSMESA(void *info) { return gbuffer; @@ -76,17 +81,51 @@ const void * _CGDataProviderGetBytePointerCallbackOSMESA(void *info) { return CAMetalLayer.class; } } + @end + +#pragma mark Class TrackedTextField +@interface TrackedTextField : UITextField +@property int lastPosition; +@property UITextPosition* lockPos; +@end + +@implementation TrackedTextField +- (UITextPosition *)closestPositionToPoint:(CGPoint)point { + UITextPosition *position = [super closestPositionToPoint:point]; + int start = [self offsetFromPosition:self.beginningOfDocument toPosition:position]; + if (start - self.lastPosition != 0) { + int key = (start - self.lastPosition > 0) ? GLFW_KEY_DPAD_RIGHT : GLFW_KEY_DPAD_LEFT; + CallbackBridge_nativeSendKey(key, 0, 1, 0); + CallbackBridge_nativeSendKey(key, 0, 0, 0); + } + self.lastPosition = start; + return [self positionFromPosition:self.beginningOfDocument offset:clamp(start, 20, self.text.length - 20)]; +} + +- (void)setText:(NSString *)text { + [super setText:text]; + self.lockPos = [self positionFromPosition:self.beginningOfDocument offset:20]; + self.selectedTextRange = [self textRangeFromPosition:self.lockPos toPosition:self.lockPos]; +} +@end + + +#pragma mark Class SurfaceViewController @interface SurfaceViewController () { } +@property TrackedTextField *inputView; @property(nonatomic, strong) NSMutableDictionary* cc_dictionary; @property(nonatomic, strong) NSMutableArray* swipeableButtons; @property(nonatomic, strong) NSMutableArray* togglableVisibleButtons; @property ControlButton* swipingButton; +@property UITouch *primaryTouch, *hotbarTouch; +@property id mouseConnectCallback, mouseDisconnectCallback; -- (void)setupGL; +@property CGRect clickRange; +@property BOOL shouldTriggerClick; @end @@ -98,9 +137,13 @@ const void * _CGDataProviderGetBytePointerCallbackOSMESA(void *info) { viewController = self; isControlModifiable = NO; + setPreference(@"internal_selected_account", nil); + [[UIApplication sharedApplication] setIdleTimerDisabled:YES]; [self setNeedsUpdateOfScreenEdgesDeferringSystemGestures]; [self setNeedsUpdateOfHomeIndicatorAutoHidden]; + [self.navigationItem setHidesBackButton:YES animated:YES]; + [self.navigationController setNavigationBarHidden:YES animated:YES]; CGRect screenBounds = [[UIScreen mainScreen] bounds]; CGFloat screenScale = [[UIScreen mainScreen] scale]; @@ -116,9 +159,8 @@ const void * _CGDataProviderGetBytePointerCallbackOSMESA(void *info) { savedWidth = roundf(width * screenScale); savedHeight = roundf(height * screenScale); - NSLog(@"Debug: Creating surfaceView"); self.surfaceView = [[GameSurfaceView alloc] initWithFrame:self.view.frame]; - NSLog(@"Debug: surfaceView=%@", self.surfaceView); + self.surfaceView.multipleTouchEnabled = YES; self.surfaceView.layer.contentsScale = screenScale * resolutionScale; self.surfaceView.layer.magnificationFilter = self.surfaceView.layer.minificationFilter = kCAFilterNearest; [self.view addSubview:self.surfaceView]; @@ -131,9 +173,10 @@ const void * _CGDataProviderGetBytePointerCallbackOSMESA(void *info) { notchOffset = insets.left; width = width - notchOffset * 2; CGFloat buttonScale = [getPreference(@"button_scale") floatValue] / 100.0; - + UITapGestureRecognizer *tapGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(surfaceOnClick:)]; + tapGesture.allowedTouchTypes = @[@(UITouchTypeDirect)]; tapGesture.delegate = self; tapGesture.numberOfTapsRequired = 1; tapGesture.numberOfTouchesRequired = 1; @@ -142,37 +185,36 @@ const void * _CGDataProviderGetBytePointerCallbackOSMESA(void *info) { UITapGestureRecognizer *doubleTapGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(surfaceOnDoubleClick:)]; + doubleTapGesture.allowedTouchTypes = @[@(UITouchTypeDirect)]; doubleTapGesture.delegate = self; doubleTapGesture.numberOfTapsRequired = 2; doubleTapGesture.numberOfTouchesRequired = 1; doubleTapGesture.cancelsTouchesInView = NO; [self.surfaceView addGestureRecognizer:doubleTapGesture]; + if (@available(iOS 13.0, *)) { + UIHoverGestureRecognizer *hoverGesture = [[UIHoverGestureRecognizer alloc] + initWithTarget:self action:@selector(surfaceOnHover:)]; + [self.surfaceView addGestureRecognizer:hoverGesture]; + } + UILongPressGestureRecognizer *longpressGesture = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(surfaceOnLongpress:)]; + longpressGesture.allowedTouchTypes = @[@(UITouchTypeDirect)]; + longpressGesture.cancelsTouchesInView = NO; longpressGesture.delegate = self; longpressGesture.minimumPressDuration = [getPreference(@"time_longPressTrigger") floatValue] / 1000; [self.surfaceView addGestureRecognizer:longpressGesture]; - UIPanGestureRecognizer *scrollPanGesture = [[UIPanGestureRecognizer alloc] + self.scrollPanGesture = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(surfaceOnTouchesScroll:)]; - scrollPanGesture.delegate = self; - scrollPanGesture.allowedTouchTypes = @[@(UITouchTypeDirect)]; - scrollPanGesture.minimumNumberOfTouches = 2; - scrollPanGesture.maximumNumberOfTouches = 2; - [self.surfaceView addGestureRecognizer:scrollPanGesture]; + self.scrollPanGesture.allowedTouchTypes = @[@(UITouchTypeDirect)]; + self.scrollPanGesture.delegate = self; + self.scrollPanGesture.minimumNumberOfTouches = 2; + self.scrollPanGesture.maximumNumberOfTouches = 2; if (@available(iOS 13.4, *)) { [self.surfaceView addInteraction:[[UIPointerInteraction alloc] initWithDelegate:self]]; - - UIPanGestureRecognizer *mouseWheelGesture = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(surfaceOnMouseScroll:)]; - mouseWheelGesture.delegate = self; - mouseWheelGesture.allowedScrollTypesMask = UIScrollTypeMaskDiscrete; - mouseWheelGesture.allowedTouchTypes = @[@(UITouchTypeIndirectPointer)]; - mouseWheelGesture.cancelsTouchesInView = NO; - mouseWheelGesture.delaysTouchesBegan = NO; - mouseWheelGesture.delaysTouchesEnded = NO; - [self.surfaceView addGestureRecognizer:mouseWheelGesture]; } // Virtual mouse @@ -184,23 +226,20 @@ const void * _CGDataProviderGetBytePointerCallbackOSMESA(void *info) { [self.view addSubview:self.mousePointerView]; #ifndef DEBUG_VISIBLE_TEXT_FIELD - inputView = [[UITextField alloc] initWithFrame:CGRectMake(0, 0, 1, 1)]; - inputView.backgroundColor = [UIColor colorWithWhite:0.0f alpha:0.0f]; + self.inputView = [[TrackedTextField alloc] initWithFrame:CGRectMake(0, -1, 1, 1)]; #else - inputView = [[UITextField alloc] initWithFrame:CGRectMake(0, 0, 1, 1)]; - inputView.backgroundColor = [UIColor colorWithWhite:0.0f alpha:0.5f]; + self.inputView = [[TrackedTextField alloc] initWithFrame:CGRectMake(5 * 2 + 160.0, 5 * 2 + 30.0, 200.0, 30.0)]; + self.inputView.backgroundColor = [UIColor colorWithWhite:0.0f alpha:0.5f]; + self.inputView.font = [self.inputView.font fontWithSize:20]; - inputLengthView = [[UILabel alloc] initWithFrame:CGRectMake(5 * 2 + rectBtnWidth, 5 * 2 + rectBtnHeight, rectBtnWidth, rectBtnHeight)]; + inputLengthView = [[UILabel alloc] initWithFrame:CGRectMake(5 * 2 + 80.0, 5 * 2 + 30.0, 80.0, 30.0)]; inputLengthView.text = @"length=?"; inputLengthView.backgroundColor = [UIColor colorWithWhite:1.0f alpha:0.6f]; [self.view addSubview:inputLengthView]; #endif - inputView.delegate = self; - [inputView addTarget:self action:@selector(inputViewDidChange) forControlEvents:UIControlEventEditingChanged]; - [inputView addTarget:self action:@selector(inputViewDidClick) forControlEvents:UIControlEventTouchDown]; - - // Custom button - // ADD_BUTTON(@"F1", f1, CGRectMake(5, 5, width, height)); + self.inputView.delegate = self; + self.inputView.lastPosition = 20; + [self.inputView addTarget:self action:@selector(inputViewDidChange) forControlEvents:UIControlEventEditingChanged]; NSString *controlFilePath = [NSString stringWithFormat:@"%s/%@", getenv("POJAV_PATH_CONTROL"), (NSString *)getPreference(@"default_ctrl")]; @@ -226,9 +265,6 @@ const void * _CGDataProviderGetBytePointerCallbackOSMESA(void *info) { BOOL isToggleCtrlBtn = NO; for (int i = 0; i < 4; i++) { int keycodeInt = [button.properties[@"keycodes"][i] intValue]; - if (keycodeInt == SPECIALBTN_KEYBOARD) { - inputView.frame = button.frame; - } if (keycodeInt == SPECIALBTN_TOGGLECTRL) { isToggleCtrlBtn = YES; } @@ -252,13 +288,35 @@ const void * _CGDataProviderGetBytePointerCallbackOSMESA(void *info) { } } - [self.view addSubview:inputView]; + [KeyboardInput initKeycodeTable]; + if (@available(iOS 14.0, tvOS 14.0, *)) { + self.mouseConnectCallback = [[NSNotificationCenter defaultCenter] addObserverForName:GCMouseDidConnectNotification object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *note) { + NSLog(@"Input: Mouse connected!"); + GCMouse* mouse = note.object; + [self registerMouseCallbacks: mouse]; + [self setNeedsUpdateOfPrefersPointerLocked]; + }]; + self.mouseDisconnectCallback = [[NSNotificationCenter defaultCenter] addObserverForName:GCMouseDidDisconnectNotification object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *note) { + NSLog(@"Input: Mouse disconnected!"); + GCMouse* mouse = note.object; + mouse.mouseInput.mouseMovedHandler = nil; + mouse.mouseInput.leftButton.pressedChangedHandler = nil; + mouse.mouseInput.middleButton.pressedChangedHandler = nil; + mouse.mouseInput.rightButton.pressedChangedHandler = nil; + [self setNeedsUpdateOfPrefersPointerLocked]; + }]; + if (GCMouse.current != nil) { + [self registerMouseCallbacks: GCMouse.current]; + } + } + + [self.view addSubview:self.inputView]; [self executebtn_special_togglebtn:0]; // [self setPreferredFramesPerSecond:1000]; - [self setupGL]; + callback_SurfaceViewController_launchMinecraft(savedWidth * resolutionScale, savedHeight * resolutionScale); } - (UIRectEdge)preferredScreenEdgesDeferringSystemGestures { @@ -269,11 +327,13 @@ const void * _CGDataProviderGetBytePointerCallbackOSMESA(void *info) { return NO; } -- (void)setupGL { - callback_SurfaceViewController_launchMinecraft(savedWidth * resolutionScale, savedHeight * resolutionScale); +#pragma mark - Input: send touch utilities + + +- (BOOL)isTouchInactive:(UITouch *)touch { + return touch == nil || touch.phase == UITouchPhaseEnded || touch.phase == UITouchPhaseCancelled; } -#pragma mark - Input: send touch utilities - (void)sendTouchPoint:(CGPoint)location withEvent:(int)event { @@ -284,17 +344,13 @@ const void * _CGDataProviderGetBytePointerCallbackOSMESA(void *info) { if (event == ACTION_MOVE) { virtualMouseFrame.origin.x += location.x - lastVirtualMousePoint.x; virtualMouseFrame.origin.y += location.y - lastVirtualMousePoint.y; - if (virtualMouseFrame.origin.x < 0) { - virtualMouseFrame.origin.x = 0; - } else if (virtualMouseFrame.origin.x > self.view.frame.size.width) { - virtualMouseFrame.origin.x = self.view.frame.size.width; - } - if (virtualMouseFrame.origin.y < 0) { - virtualMouseFrame.origin.y = 0; - } else if (virtualMouseFrame.origin.y > self.view.frame.size.height) { - virtualMouseFrame.origin.y = self.view.frame.size.height; - } + } else if (event == ACTION_MOVE_MOTION) { + event = ACTION_MOVE; + virtualMouseFrame.origin.x += location.x; + virtualMouseFrame.origin.y += location.y; } + virtualMouseFrame.origin.x = clamp(virtualMouseFrame.origin.x, 0, self.view.frame.size.width); + virtualMouseFrame.origin.y = clamp(virtualMouseFrame.origin.y, 0, self.view.frame.size.height); lastVirtualMousePoint = location; self.mousePointerView.frame = virtualMouseFrame; callback_SurfaceViewController_onTouch(event, virtualMouseFrame.origin.x * screenScale, virtualMouseFrame.origin.y * screenScale); @@ -305,31 +361,39 @@ const void * _CGDataProviderGetBytePointerCallbackOSMESA(void *info) { callback_SurfaceViewController_onTouch(event, location.x * screenScale, location.y * screenScale); } +#pragma mark - Input: on-surface functions + - (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer { return YES; } -- (void)sendTouchEvent:(NSSet *)touches withUIEvent:(UIEvent *)uievent withEvent:(int)event +- (void)sendTouchEvent:(UITouch *)touchEvent withUIEvent:(UIEvent *)uievent withEvent:(int)event { - UITouch* touchEvent = [touches anyObject]; CGPoint locationInView = [touchEvent locationInView:self.view]; - BOOL isTouchTypeIndirect = NO; - if (@available(iOS 13.4, *)) { - if (touchEvent.type == UITouchTypeIndirectPointer) { - isTouchTypeIndirect = YES; - } - } - if (touchEvent.view == self.surfaceView) { - if (slideableHotbar && !isTouchTypeIndirect) { + switch (event) { + case ACTION_DOWN: + self.clickRange = CGRectMake(locationInView.x - 2, locationInView.y - 2, 5, 5); + self.shouldTriggerClick = YES; + + break; + + case ACTION_MOVE: + if (self.shouldTriggerClick && !CGRectContainsPoint(self.clickRange, locationInView)) { + self.shouldTriggerClick = NO; + } + break; + } + + if (touchEvent == self.hotbarTouch && slideableHotbar && ![self isTouchInactive:self.hotbarTouch]) { CGFloat screenScale = [[UIScreen mainScreen] scale]; int slot = callback_SurfaceViewController_touchHotbar(locationInView.x * screenScale, locationInView.y * screenScale); if (slot != -1 && currentHotbarSlot != slot && (event == ACTION_DOWN || currentHotbarSlot != -1)) { currentHotbarSlot = slot; - Java_org_lwjgl_glfw_CallbackBridge_nativeSendKey(NULL, NULL, slot, 0, 1, 0); - Java_org_lwjgl_glfw_CallbackBridge_nativeSendKey(NULL, NULL, slot, 0, 0, 0); + CallbackBridge_nativeSendKey(slot, 0, 1, 0); + CallbackBridge_nativeSendKey(slot, 0, 0, 0); return; } /* else if ((event == ACTION_MOVE || event == ACTION_UP) && slot == -1 && currentHotbarSlot != -1) { return; @@ -338,64 +402,89 @@ const void * _CGDataProviderGetBytePointerCallbackOSMESA(void *info) { if (event == ACTION_DOWN && slot == -1) { currentHotbarSlot = -1; } - + /* if (currentHotbarSlot != -1) { return; } + */ + return; } - - [self sendTouchPoint:locationInView withEvent:event]; - if (!isTouchTypeIndirect) { - switch (event) { - case ACTION_DOWN: - touchesMovedCount = 0; - shouldTriggerClick = YES; - break; - - case ACTION_MOVE: - // TODO: better handling this - if (touchesMovedCount >= 1) { - shouldTriggerClick = NO; - } else ++touchesMovedCount; - break; - } - } else if (@available(iOS 13.4, *)) { - // Recheck @available for suppressing compile warnings - - // Mouse clicks are handled here - int held = event == ACTION_MOVE || event == ACTION_UP; - shouldTriggerClick = NO; - for (int i = 1; i <= 5; ++i) { - if ((uievent.buttonMask & (1 << ((i)-1))) != 0) { - // iOS button index = GLFW button index + 1; - Java_org_lwjgl_glfw_CallbackBridge_nativeSendMouseButton(NULL, NULL, i - 1, held, 0); - } - } + if (touchEvent == self.primaryTouch) { + if ([self isTouchInactive:self.primaryTouch]) return; // FIXME: should be? ACTION_UP will never be sent + [self sendTouchPoint:locationInView withEvent:event]; } } } -#pragma mark - Input: on-surface gestures +- (void)pressesBegan:(NSSet *)presses withEvent:(UIPressesEvent *)event { + BOOL handled = NO; + + if (@available(iOS 13.4, *)) { + for (UIPress *press in presses) { + if (press.key != nil && [KeyboardInput sendKeyEvent:press.key down:YES]) { + handled = YES; + } + } + } + + if (!handled) { + [super pressesBegan:presses withEvent:event]; + } +} + +- (void)pressesEnded:(NSSet *)presses withEvent:(UIPressesEvent *)event { + BOOL handled = NO; + + if (@available(iOS 13.4, *)) { + for (UIPress *press in presses) { + if (press.key != nil && [KeyboardInput sendKeyEvent:press.key down:NO]) { + handled = YES; + } + } + } + + if (!handled) { + [super pressesEnded:presses withEvent:event]; + } +} + +- (void)registerMouseCallbacks:(GCMouse *)mouse API_AVAILABLE(ios(14.0)) { + NSLog(@"Input: Got mouse %@", mouse); + mouse.mouseInput.leftButton.pressedChangedHandler = ^(GCControllerButtonInput * _Nonnull button, float value, BOOL pressed) { + CallbackBridge_nativeSendMouseButton(GLFW_MOUSE_BUTTON_LEFT, pressed, 0); + }; + mouse.mouseInput.middleButton.pressedChangedHandler = ^(GCControllerButtonInput * _Nonnull button, float value, BOOL pressed) { + CallbackBridge_nativeSendMouseButton(GLFW_MOUSE_BUTTON_MIDDLE, pressed, 0); + }; + mouse.mouseInput.rightButton.pressedChangedHandler = ^(GCControllerButtonInput * _Nonnull button, float value, BOOL pressed) { + CallbackBridge_nativeSendMouseButton(GLFW_MOUSE_BUTTON_RIGHT, pressed, 0); + }; + + mouse.mouseInput.scroll.xAxis.valueChangedHandler = ^(GCControllerAxisInput * _Nonnull axis, float value) { + CallbackBridge_nativeSendScroll(value, 0); + }; + mouse.mouseInput.scroll.yAxis.valueChangedHandler = ^(GCControllerAxisInput * _Nonnull axis, float value) { + CallbackBridge_nativeSendScroll(0, value); + }; + +} - (void)surfaceOnClick:(UITapGestureRecognizer *)sender { - if (sender.state == UIGestureRecognizerStateRecognized && - shouldTriggerClick == YES) { - CGFloat screenScale = [[UIScreen mainScreen] scale]; - CGPoint location = [sender locationInView:[sender.view superview]]; - currentHotbarSlot = callback_SurfaceViewController_touchHotbar(location.x * screenScale, location.y * screenScale); - + if (!self.shouldTriggerClick) return; + + if (sender.state == UIGestureRecognizerStateRecognized) { if (currentHotbarSlot == -1) { - inputView.text = INPUT_SPACE_CHAR; + self.inputView.text = INPUT_SPACE_CHAR; inputTextLength = 0; - Java_org_lwjgl_glfw_CallbackBridge_nativeSendMouseButton(NULL, NULL, + CallbackBridge_nativeSendMouseButton( isGrabbing == JNI_TRUE ? GLFW_MOUSE_BUTTON_RIGHT : GLFW_MOUSE_BUTTON_LEFT, 1, 0); - Java_org_lwjgl_glfw_CallbackBridge_nativeSendMouseButton(NULL, NULL, + CallbackBridge_nativeSendMouseButton( isGrabbing == JNI_TRUE ? GLFW_MOUSE_BUTTON_RIGHT : GLFW_MOUSE_BUTTON_LEFT, 0, 0); } else { - Java_org_lwjgl_glfw_CallbackBridge_nativeSendKey(NULL, NULL, currentHotbarSlot, 0, 1, 0); - Java_org_lwjgl_glfw_CallbackBridge_nativeSendKey(NULL, NULL, currentHotbarSlot, 0, 0, 0); + CallbackBridge_nativeSendKey(currentHotbarSlot, 0, 1, 0); + CallbackBridge_nativeSendKey(currentHotbarSlot, 0, 0, 0); } } } @@ -406,8 +495,8 @@ const void * _CGDataProviderGetBytePointerCallbackOSMESA(void *info) { CGPoint location = [sender locationInView:[sender.view superview]]; int hotbarSlot = callback_SurfaceViewController_touchHotbar(location.x * screenScale * resolutionScale, location.y * screenScale * resolutionScale); if (hotbarSlot != -1 && currentHotbarSlot == hotbarSlot) { - Java_org_lwjgl_glfw_CallbackBridge_nativeSendKey(NULL, NULL, GLFW_KEY_F, 0, 1, 0); - Java_org_lwjgl_glfw_CallbackBridge_nativeSendKey(NULL, NULL, GLFW_KEY_F, 0, 0, 0); + CallbackBridge_nativeSendKey(GLFW_KEY_F, 0, 1, 0); + CallbackBridge_nativeSendKey(GLFW_KEY_F, 0, 0, 0); } } } @@ -416,7 +505,7 @@ const void * _CGDataProviderGetBytePointerCallbackOSMESA(void *info) { if (@available(iOS 13.0, *)) { CGPoint point = [sender locationInView:self.surfaceView]; // NSLog(@"Mouse move!!"); - // NSLog(@"Mouse pos = %d, %d", point.x, point.y); + // NSLog(@"Mouse pos = %f, %f", point.x, point.y); switch (sender.state) { case UIGestureRecognizerStateBegan: [self sendTouchPoint:point withEvent:ACTION_DOWN]; @@ -437,64 +526,41 @@ const void * _CGDataProviderGetBytePointerCallbackOSMESA(void *info) { -(void)surfaceOnLongpress:(UILongPressGestureRecognizer *)sender { - CGFloat screenScale = [[UIScreen mainScreen] scale]; - CGPoint location = [sender locationInView:[sender.view superview]]; if (!slideableHotbar) { + CGFloat screenScale = [[UIScreen mainScreen] scale]; + CGPoint location = [sender locationInView:[sender.view superview]]; currentHotbarSlot = callback_SurfaceViewController_touchHotbar(location.x * screenScale * resolutionScale, location.y * screenScale * resolutionScale); } if (sender.state == UIGestureRecognizerStateBegan) { + self.shouldTriggerClick = NO; if (currentHotbarSlot == -1) { - inputView.text = INPUT_SPACE_CHAR; + self.inputView.text = INPUT_SPACE_CHAR; inputTextLength = 0; - Java_org_lwjgl_glfw_CallbackBridge_nativeSendMouseButton(NULL, NULL, GLFW_MOUSE_BUTTON_LEFT, 1, 0); + CallbackBridge_nativeSendMouseButton(GLFW_MOUSE_BUTTON_LEFT, 1, 0); } else { - Java_org_lwjgl_glfw_CallbackBridge_nativeSendKey(NULL, NULL, GLFW_KEY_Q, 0, 1, 0); + CallbackBridge_nativeSendKey(GLFW_KEY_Q, 0, 1, 0); } } else if (sender.state == UIGestureRecognizerStateChanged) { - if (currentHotbarSlot == -1) { - [self sendTouchPoint:location withEvent:ACTION_MOVE]; - } + // Nothing to do here, already handled in touchesMoved } else { if (sender.state == UIGestureRecognizerStateCancelled || sender.state == UIGestureRecognizerStateFailed || sender.state == UIGestureRecognizerStateEnded) { if (currentHotbarSlot == -1) { - inputView.text = INPUT_SPACE_CHAR; + self.inputView.text = INPUT_SPACE_CHAR; inputTextLength = 0; - Java_org_lwjgl_glfw_CallbackBridge_nativeSendMouseButton(NULL, NULL, GLFW_MOUSE_BUTTON_LEFT, 0, 0); + CallbackBridge_nativeSendMouseButton(GLFW_MOUSE_BUTTON_LEFT, 0, 0); } else { - Java_org_lwjgl_glfw_CallbackBridge_nativeSendKey(NULL, NULL, GLFW_KEY_Q, 0, 0, 0); + +CallbackBridge_nativeSendKey(GLFW_KEY_Q, 0, 0, 0); } } } } --(void)surfaceOnMouseScroll:(UIPanGestureRecognizer *)sender API_AVAILABLE(ios(13.4)) -{ - if (sender.state == UIGestureRecognizerStateBegan || - sender.state == UIGestureRecognizerStateChanged || - sender.state == UIGestureRecognizerStateEnded) { - CGPoint velocity = [sender velocityInView:self.view]; - - if (velocity.x > 0.0f) { - velocity.x = -1.0; - } else if (velocity.x < 0.0f) { - velocity.x = 1.0f; - } - if (velocity.y > 0.0f) { - velocity.y = -1.0; - } else if (velocity.y < 0.0f) { - velocity.y = 1.0f; - } - if (velocity.x != 0.0f || velocity.y != 0.0f) { - Java_org_lwjgl_glfw_CallbackBridge_nativeSendScroll(NULL, NULL, (jdouble) velocity.x * 4.0, (jdouble) velocity.y * 4.0); - } - } -} - - (void)surfaceOnTouchesScroll:(UIPanGestureRecognizer *)sender { if (isGrabbing) return; if (sender.state == UIGestureRecognizerStateBegan || @@ -502,106 +568,90 @@ const void * _CGDataProviderGetBytePointerCallbackOSMESA(void *info) { sender.state == UIGestureRecognizerStateEnded) { CGPoint velocity = [sender velocityInView:self.view]; if (velocity.x != 0.0f || velocity.y != 0.0f) { - Java_org_lwjgl_glfw_CallbackBridge_nativeSendScroll(NULL, NULL, (jdouble) (velocity.x/10.0), (jdouble) (velocity.y/10.0)); + CallbackBridge_nativeSendScroll((CGFloat) (velocity.x/10.0), (CGFloat) (velocity.y/10.0)); } } } +// FIXME: incomplete - (UIPointerRegion *)pointerInteraction:(UIPointerInteraction *)interaction regionForRequest:(UIPointerRegionRequest *)request defaultRegion:(UIPointerRegion *)defaultRegion API_AVAILABLE(ios(13.4)) API_AVAILABLE(ios(13.4)) API_AVAILABLE(ios(13.4)){ - if (request != nil) { - CGPoint origin = self.surfaceView.bounds.origin; - CGPoint point = request.location; - - point.x -= origin.x; - point.y -= origin.y; - - NSLog(@"UIPointerInteraction pos changed: x=%d, y=%d", (int) point.x, (int) point.y); - - // TODO FIXME - callback_SurfaceViewController_onTouch(ACTION_DOWN, (int)point.x, (int)point.y); - } - return [UIPointerRegion regionWithRect:self.surfaceView.bounds identifier:nil]; + NSLog(@"regionForRequest called"); + return nil; } - (UIPointerStyle *)pointerInteraction:(UIPointerInteraction *)interaction styleForRegion:(UIPointerRegion *)region API_AVAILABLE(ios(13.4)){ - if (isGrabbing == JNI_FALSE) { - return nil; - } else { - return [UIPointerStyle hiddenPointerStyle]; - } + NSLog(@"styleForRegion called"); + return [UIPointerStyle hiddenPointerStyle]; } #pragma mark - Input view stuff NSString* inputStringBefore; +int inputStringLength = INPUT_FULL_LENGTH; -(void)inputViewDidChange { - if ([inputView.text length] < INPUT_SPACE_LENGTH) { - Java_org_lwjgl_glfw_CallbackBridge_nativeSendKey(NULL, NULL, GLFW_KEY_BACKSPACE, 0, 1, 0); - Java_org_lwjgl_glfw_CallbackBridge_nativeSendKey(NULL, NULL, GLFW_KEY_BACKSPACE, 0, 0, 0); - inputView.text = [@" " stringByAppendingString:inputView.text]; - - if (inputTextLength > 0) { - --inputTextLength; + int typedLength = (int)self.inputView.text.length - inputStringLength; + if (typedLength < 0) { + for (int i = 0; i < -typedLength; i++) { + if (self.inputView.text.length < INPUT_FULL_LENGTH) { + self.inputView.text = [@" " stringByAppendingString:self.inputView.text]; + } + CallbackBridge_nativeSendKey(GLFW_KEY_BACKSPACE, 0, 1, 0); + CallbackBridge_nativeSendKey(GLFW_KEY_BACKSPACE, 0, 0, 0); + if (inputTextLength > 0) { + --inputTextLength; + } } #ifdef DEBUG_VISIBLE_TEXT_FIELD - inputLengthView.text = [@"length=" stringByAppendingFormat:@"%i", + inputLengthView.text = [@"length=" stringByAppendingFormat:@"%i", inputTextLength]; #endif - } else if ([inputView.text length] > INPUT_SPACE_LENGTH) { - NSString *newText = [inputView.text substringFromIndex:INPUT_SPACE_LENGTH]; + } else if (typedLength > 0) { + int index = [self.inputView offsetFromPosition:self.inputView.beginningOfDocument toPosition:self.inputView.selectedTextRange.start]; + NSString *newText = [self.inputView.text substringWithRange:NSMakeRange(index - typedLength, typedLength)]; int charLength = (int) [newText length]; for (int i = 0; i < charLength; i++) { // Directly convert unichar to jchar since both are in UTF-16 encoding. -/* - jchar theChar = (jchar) - (isUseStackQueueCall ? - [newText UTF8String][i] : [newText characterAtIndex:i]); -*/ - jchar theChar = (jchar) [newText characterAtIndex:i]; if (isUseStackQueueCall) { - Java_org_lwjgl_glfw_CallbackBridge_nativeSendCharMods(NULL, NULL, theChar, /* mods */ 0); + CallbackBridge_nativeSendCharMods(theChar, /* mods */ 0); } else { - Java_org_lwjgl_glfw_CallbackBridge_nativeSendChar(NULL, NULL, theChar); + CallbackBridge_nativeSendChar(theChar); } - inputView.text = [inputView.text substringFromIndex:1]; - if (inputTextLength < INPUT_SPACE_LENGTH) { - ++inputTextLength; - } + ++inputTextLength; #ifdef DEBUG_VISIBLE_TEXT_FIELD inputLengthView.text = [@"length=" stringByAppendingFormat:@"%i", inputTextLength]; #endif } - inputStringBefore = inputView.text; - // [inputView.text substringFromIndex:inputTextLength - 1]; + inputStringBefore = self.inputView.text; + // [self.inputView.text substringFromIndex:inputTextLength - 1]; } else { #ifdef DEBUG_VISIBLE_TEXT_FIELD - NSLog(@"Compare \"%@\" vs \"%@\"", inputView.text, inputStringBefore); + NSLog(@"Compare \"%@\" vs \"%@\"", self.inputView.text, inputStringBefore); #endif - for (int i = 0; i < INPUT_SPACE_LENGTH; i++) { - if ([inputView.text characterAtIndex:i] != [inputStringBefore characterAtIndex:i]) { - NSString *inputStringNow = [inputView.text substringFromIndex:i]; + for (int i = 0; i < INPUT_FULL_LENGTH; i++) { + if ([self.inputView.text characterAtIndex:i] != [inputStringBefore characterAtIndex:i]) { + NSString *inputStringNow = [self.inputView.text substringFromIndex:i]; /* - inputView.text = [inputView.text substringToIndex:i]; + self.inputView.text = [self.inputView.text substringToIndex:i]; // self notify [self inputViewDidChange]; - inputView.text = [inputView.text stringByAppendingString:inputStringNow]; + self.inputView.text = [self.inputView.text stringByAppendingString:inputStringNow]; // self notify [self inputViewDidChange]; */ for (int i2 = 0; i2 < [inputStringNow length]; i2++) { - Java_org_lwjgl_glfw_CallbackBridge_nativeSendKey(NULL, NULL, GLFW_KEY_BACKSPACE, 0, 1, 0); - Java_org_lwjgl_glfw_CallbackBridge_nativeSendKey(NULL, NULL, GLFW_KEY_BACKSPACE, 0, 0, 0); + CallbackBridge_nativeSendKey(GLFW_KEY_BACKSPACE, 0, 1, 0); + CallbackBridge_nativeSendKey(GLFW_KEY_BACKSPACE, 0, 0, 0); } for (int i2 = 0; i2 < [inputStringNow length]; i2++) { - Java_org_lwjgl_glfw_CallbackBridge_nativeSendCharMods(NULL, NULL, (jchar) [inputStringNow characterAtIndex:i2], /* mods */ 0); + CallbackBridge_nativeSendCharMods((jchar) [inputStringNow characterAtIndex:i2], /* mods */ 0); } break; @@ -611,26 +661,18 @@ NSString* inputStringBefore; #ifdef DEBUG_VISIBLE_TEXT_FIELD inputLengthView.text = @"length ="; #endif - inputStringBefore = inputView.text; - // [inputView.text substringFromIndex:inputTextLength - 1]; + inputStringBefore = self.inputView.text; } - // Reset to default value - // inputView.text = INPUT_SPACE_CHAR; -} + inputStringLength = (int)self.inputView.text.length; --(void)inputViewDidClick { - // Zero the input field so user will no longer able to select text inside. -#ifndef DEBUG_VISIBLE_TEXT_FIELD - inputView.alpha = 0.0f; -#endif - inputView.text = INPUT_SPACE_CHAR; - inputTextLength = 0; + // Reset to default value + // self.inputView.text = INPUT_SPACE_CHAR; } -(BOOL)textFieldShouldReturn:(UITextField *)textField { - Java_org_lwjgl_glfw_CallbackBridge_nativeSendKey(NULL, NULL, GLFW_KEY_ENTER, 0, 1, 0); - Java_org_lwjgl_glfw_CallbackBridge_nativeSendKey(NULL, NULL, GLFW_KEY_ENTER, 0, 0, 0); + CallbackBridge_nativeSendKey(GLFW_KEY_ENTER, 0, 1, 0); + CallbackBridge_nativeSendKey(GLFW_KEY_ENTER, 0, 0, 0); return YES; } @@ -640,29 +682,40 @@ int currentVisibility = 1; - (void)executebtn:(UIButton *)sender withAction:(int)action { ControlButton *button = (ControlButton *)sender; int held = action == ACTION_DOWN; - // TODO v2: mulitple keys support for (int i = 0; i < 4; i++) { int keycode = ((NSNumber *)button.properties[@"keycodes"][i]).intValue; if (keycode < 0) { switch (keycode) { case SPECIALBTN_KEYBOARD: if (held == 0) { - [inputView resignFirstResponder]; - inputView.alpha = 1.0f; - inputView.text = @""; + if (self.inputView.isFirstResponder) { + [self.inputView resignFirstResponder]; + self.inputView.alpha = 1.0f; + self.inputView.text = @""; + } else { + [self.inputView becomeFirstResponder]; + // Empty the input field so that user will no longer able to select text inside. + self.inputView.text = INPUT_SPACE_CHAR; + inputStringLength = INPUT_FULL_LENGTH; + +#ifndef DEBUG_VISIBLE_TEXT_FIELD + self.inputView.alpha = 0.0f; +#endif + inputTextLength = 0; + } } break; case SPECIALBTN_MOUSEPRI: - Java_org_lwjgl_glfw_CallbackBridge_nativeSendMouseButton(NULL, NULL, GLFW_MOUSE_BUTTON_LEFT, held, 0); + CallbackBridge_nativeSendMouseButton(GLFW_MOUSE_BUTTON_LEFT, held, 0); break; case SPECIALBTN_MOUSESEC: - Java_org_lwjgl_glfw_CallbackBridge_nativeSendMouseButton(NULL, NULL, GLFW_MOUSE_BUTTON_RIGHT, held, 0); + CallbackBridge_nativeSendMouseButton(GLFW_MOUSE_BUTTON_RIGHT, held, 0); break; case SPECIALBTN_MOUSEMID: - Java_org_lwjgl_glfw_CallbackBridge_nativeSendMouseButton(NULL, NULL, GLFW_MOUSE_BUTTON_MIDDLE, held, 0); + CallbackBridge_nativeSendMouseButton(GLFW_MOUSE_BUTTON_MIDDLE, held, 0); break; case SPECIALBTN_TOGGLECTRL: @@ -671,13 +724,13 @@ int currentVisibility = 1; case SPECIALBTN_SCROLLDOWN: if (!held) { - Java_org_lwjgl_glfw_CallbackBridge_nativeSendScroll(NULL, NULL, 0.0, 1.0); + CallbackBridge_nativeSendScroll(0.0, 1.0); } break; case SPECIALBTN_SCROLLUP: if (!held) { - Java_org_lwjgl_glfw_CallbackBridge_nativeSendScroll(NULL, NULL, 0.0, -1.0); + CallbackBridge_nativeSendScroll(0.0, -1.0); } case SPECIALBTN_VIRTUALMOUSE: @@ -695,7 +748,8 @@ int currentVisibility = 1; // there's no key id 0, but we accidentally used -1 as a special key id, so we had to do that // if (keycode == 0) { keycode = -1; } // at the moment, send unknown keycode does nothing, may even cause performance issue, so ignore it - Java_org_lwjgl_glfw_CallbackBridge_nativeSendKey(NULL, NULL, keycode, 0, held, 0); + +CallbackBridge_nativeSendKey(keycode, 0, held, 0); } } } @@ -712,7 +766,7 @@ int currentVisibility = 1; { CGPoint location = [sender locationInView:self.view]; if (sender.state == UIGestureRecognizerStateCancelled || sender.state == UIGestureRecognizerStateEnded) { - [self executebtn_up:nil]; + [self executebtn_up:self.swipingButton]; return; } for (ControlButton *button in self.swipeableButtons) { @@ -727,7 +781,7 @@ int currentVisibility = 1; - (void)executebtn_up:(ControlButton *)sender { - if (self.swipingButton) { + if (self.swipingButton == sender) { [self executebtn:self.swipingButton withAction:ACTION_UP]; self.swipingButton = nil; } else { @@ -750,7 +804,7 @@ int currentVisibility = 1; } #ifndef DEBUG_VISIBLE_TEXT_FIELD - inputView.hidden = currentVisibility; + self.inputView.hidden = currentVisibility; #endif } } @@ -762,27 +816,72 @@ int touchesMovedCount; - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event { [super touchesBegan:touches withEvent:event]; - [self sendTouchEvent:touches withUIEvent:event withEvent:ACTION_DOWN]; + int i = 0; + for (UITouch *touch in touches) { + if (@available(iOS 14.0, *)) { // 13.4 + if (touch.type == UITouchTypeIndirectPointer) { + continue; // handle this in a different place + } + } + CGPoint locationInView = [touch locationInView:self.view]; + CGFloat screenScale = [[UIScreen mainScreen] scale]; + currentHotbarSlot = callback_SurfaceViewController_touchHotbar(locationInView.x * screenScale, locationInView.y * screenScale); + if ([self isTouchInactive:self.hotbarTouch] && currentHotbarSlot != -1) { + self.hotbarTouch = touch; + } + if ([self isTouchInactive:self.primaryTouch] && currentHotbarSlot == -1) { + self.primaryTouch = touch; + } + [self sendTouchEvent:touch withUIEvent:event withEvent:ACTION_DOWN]; + break; + } } // Equals to Android ACTION_MOVE - (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event { [super touchesMoved:touches withEvent:event]; - [self sendTouchEvent:touches withUIEvent:event withEvent:ACTION_MOVE]; + + for (UITouch *touch in touches) { + if (@available(iOS 14.0, *)) { // 13.4 + if (touch.type == UITouchTypeIndirectPointer) { + continue; // handle this in a different place + } + } + if (self.hotbarTouch != touch && [self isTouchInactive:self.primaryTouch]) { + // Replace the inactive touch with the current active touch + self.primaryTouch = touch; + [self sendTouchEvent:touch withUIEvent:event withEvent:ACTION_DOWN]; + } + [self sendTouchEvent:touch withUIEvent:event withEvent:ACTION_MOVE]; + } +} + +// For ACTION_UP and ACTION_CANCEL +- (void)touchesEndedGlobal:(NSSet *)touches withEvent:(UIEvent *)event +{ + for (UITouch *touch in touches) { + if (@available(iOS 14.0, *)) { // 13.4 + if (touch.type == UITouchTypeIndirectPointer) { + continue; // handle this in a different place + } + } + [self sendTouchEvent:touch withUIEvent:event withEvent:ACTION_UP]; + } } // Equals to Android ACTION_UP - (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event { [super touchesEnded:touches withEvent:event]; - [self sendTouchEvent:touches withUIEvent:event withEvent:ACTION_UP]; + [self touchesEndedGlobal:touches withEvent:event]; } +// Equals to Android ACTION_CANCEL - (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event { [super touchesCancelled:touches withEvent:event]; - [self sendTouchEvent:touches withUIEvent:event withEvent:ACTION_UP]; + [self touchesEndedGlobal:touches withEvent:event]; } @end diff --git a/Natives/UpdateHistoryViewController.m b/Natives/UpdateHistoryViewController.m index 210deef2..d53dc5df 100644 --- a/Natives/UpdateHistoryViewController.m +++ b/Natives/UpdateHistoryViewController.m @@ -10,10 +10,11 @@ @interface UpdateHistoryViewController () { } +-(UILabel *)uhContent:(bool)isHeading size:(int)size text:(NSString *)text width:(int)width; @end @implementation UpdateHistoryViewController - +CGFloat uhcurrY = 4.0; - (void)viewDidLoad { [super viewDidLoad]; @@ -38,197 +39,104 @@ } else { self.view.backgroundColor = [UIColor whiteColor]; } - - UILabel *latestVerNote = [[UILabel alloc] initWithFrame:CGRectMake(4.0, 4.0, scrollView.frame.size.width - 4, 30.0)]; - latestVerNote.text = @"Current version"; - latestVerNote.lineBreakMode = NSLineBreakByWordWrapping; - latestVerNote.numberOfLines = 0; - [scrollView addSubview:latestVerNote]; - [latestVerNote setFont:[UIFont boldSystemFontOfSize:25]]; - - UILabel *latestVerView = [[UILabel alloc] initWithFrame:CGRectMake(4.0, latestVerNote.frame.origin.y + latestVerNote.frame.size.height, scrollView.frame.size.width - 4, 30.0)]; - latestVerView.text = [NSString stringWithFormat:@"2.1 (%s)", CONFIG_TYPE]; - latestVerView.lineBreakMode = NSLineBreakByWordWrapping; - latestVerView.numberOfLines = 0; - [scrollView addSubview:latestVerView]; - [latestVerView setFont:[UIFont boldSystemFontOfSize:20]]; - - UILabel *latestVerChanges = [[UILabel alloc] initWithFrame:CGRectMake(4.0, latestVerView.frame.origin.y + latestVerView.frame.size.height, scrollView.frame.size.width - 4, 30.00)]; - latestVerChanges.text = @"Changes"; - latestVerChanges.numberOfLines = 0; - [scrollView addSubview:latestVerChanges]; - [latestVerChanges setFont:[UIFont boldSystemFontOfSize:17]]; - - UILabel *latestVerChangesCont = [[UILabel alloc] initWithFrame:CGRectMake(4.0, latestVerChanges.frame.origin.y + latestVerChanges.frame.size.height, scrollView.frame.size.width - 4, 30.00)]; - latestVerChangesCont.text = @"- Various bug fixes"; - latestVerChangesCont.numberOfLines = 0; - [latestVerChangesCont sizeToFit]; - [scrollView addSubview:latestVerChangesCont]; - - UILabel *latestVerFixes = [[UILabel alloc] initWithFrame:CGRectMake(4.0, latestVerChangesCont.frame.origin.y + latestVerChangesCont.frame.size.height + 5.0, scrollView.frame.size.width - 4, 30.00)]; - latestVerFixes.text = @"Fixes"; - latestVerFixes.numberOfLines = 0; - [scrollView addSubview:latestVerFixes]; - [latestVerFixes setFont:[UIFont boldSystemFontOfSize:17]]; - - UILabel *latestVerFixesCont = [[UILabel alloc] initWithFrame:CGRectMake(4.0, latestVerFixes.frame.origin.y + latestVerFixes.frame.size.height, scrollView.frame.size.width - 4, 30.00)]; - latestVerFixesCont.text = @"- Custom controls page is now complete"; - latestVerFixesCont.numberOfLines = 0; - [latestVerFixesCont sizeToFit]; - [scrollView addSubview:latestVerFixesCont]; - - UILabel *latestVerIssues = [[UILabel alloc] initWithFrame:CGRectMake(4.0, latestVerFixesCont.frame.origin.y + latestVerFixesCont.frame.size.height + 5.0, scrollView.frame.size.width - 4, 30.00)]; - latestVerIssues.text = @"Issues"; - latestVerIssues.numberOfLines = 0; - [scrollView addSubview:latestVerIssues]; - [latestVerIssues setFont:[UIFont boldSystemFontOfSize:17]]; - - UILabel *latestVerIssuesCont = [[UILabel alloc] initWithFrame:CGRectMake(4.0, latestVerIssues.frame.origin.y + latestVerIssues.frame.size.height, scrollView.frame.size.width - 4, 30.00)]; - latestVerIssuesCont.text = @"- Crash if login to Microsoft fails\n" - "- Old custom control .json files no longer work, remove to fix\n" - "- An unknown issue might cause Taurine, 14.3, and A12+ to crash on launch."; - latestVerIssuesCont.numberOfLines = 0; - [latestVerIssuesCont sizeToFit]; - [scrollView addSubview:latestVerIssuesCont]; - - UILabel *prevVerNote = [[UILabel alloc] initWithFrame:CGRectMake(4.0, latestVerIssuesCont.frame.origin.y + latestVerIssuesCont.frame.size.height + 10.0, scrollView.frame.size.width - 4, 30.0)]; - prevVerNote.text = @"Previous versions"; - prevVerNote.lineBreakMode = NSLineBreakByWordWrapping; - prevVerNote.numberOfLines = 0; - [scrollView addSubview:prevVerNote]; - [prevVerNote setFont:[UIFont boldSystemFontOfSize:25]]; - - UILabel *backOneVerView = [[UILabel alloc] initWithFrame:CGRectMake(4.0, prevVerNote.frame.origin.y + prevVerNote.frame.size.height, scrollView.frame.size.width - 4, 30.0)]; - backOneVerView.text = @"2.0 - Raw Iron"; - backOneVerView.lineBreakMode = NSLineBreakByWordWrapping; - backOneVerView.numberOfLines = 0; - [scrollView addSubview:backOneVerView]; - [backOneVerView setFont:[UIFont boldSystemFontOfSize:20]]; - - UILabel *backOneVerChanges = [[UILabel alloc] initWithFrame:CGRectMake(4.0, backOneVerView.frame.origin.y + backOneVerView.frame.size.height, scrollView.frame.size.width - 4, 30.00)]; - backOneVerChanges.text = @"Changes"; - backOneVerChanges.numberOfLines = 0; - [scrollView addSubview:backOneVerChanges]; - [backOneVerChanges setFont:[UIFont boldSystemFontOfSize:17]]; + + uhcurrY = 4.0; + + [scrollView addSubview:[self uhContent:true size:25 text:@"Current version" width:width]]; + [scrollView addSubview:[self uhContent:true size:20 text:[NSString stringWithFormat:@"2.1 (%s)", CONFIG_TYPE] width:width]]; + [scrollView addSubview:[self uhContent:true size:17 text:@"Changes" width:width]]; + [scrollView addSubview:[self uhContent:false size:0 text:@"- Now shows when currently logging in\n" + "- Play button is greyed out when launching\n" + "- Back button is hidden when launching\n" + "- New toggle to allow restarting JVM before launching\n" + "- Added WIP Demo mode support!\n" + "- Patch log4shell exploit in client\n" + "- Keyboard and mouse support deepened\n" + "- New \"vgpu\" renderer, exports OpenGL 3.0\n" + "- Custom controls UI completed\n" + "- Arc custom capes integration!" width:width]]; + [scrollView addSubview:[self uhContent:true size:17 text:@"Fixes" width:width]]; + [scrollView addSubview:[self uhContent:false size:0 text:@"- Slight changes to error messages\n" + "- Fix Makefile errors in `deploy` and `ipa`\n" + "- Fix some instances of Mojang login failing\n" + "- Fix NullPointerException when launching ≤1.6.4\n" + "- Fix NullPointerException when setting inherited fields\n" + "- Fix \"Share your logs\" not working\n" + "- Fix Fabric 1.17+ not launching\n" + "- Fix postinst issue on Procursus" width:width]]; + [scrollView addSubview:[self uhContent:true size:17 text:@"Issues" width:width]]; + [scrollView addSubview:[self uhContent:false size:0 text:@"- Mouse support requires iOS 14.0 or later, keyboards require iOS 13.4 or later\n" + "- Old custom control .json files no longer work, remove to fix" width:width]]; + [scrollView addSubview:[self uhContent:true size:25 text:@"Previous versions" width:width]]; + [scrollView addSubview:[self uhContent:true size:20 text:@"2.0 - Raw Iron" width:width]]; + [scrollView addSubview:[self uhContent:true size:17 text:@"Changes" width:width]]; + [scrollView addSubview:[self uhContent:false size:0 text:@"- The Login view has been simplified to three easy buttons\n" + "- The Offline Account has been replaced with Local Account. Installing Minecraft now requires a Mojang or Microsoft account logged in.\n" + "- New FAQ page to show quick answers to questions\n" + "- New About view to show quick details, links, and update history\n" + "- Ability to send logs from within the launcher\n" + "- The Select Account screen is now a pop-up window\n" + "- New picker view to switch versions without typing them manually\n" + "- Support to show your locally installed clients\n" + "- New settings page to manage preferences\n" + "- OpenJDK 8 support, to allow older versions of modded Minecraft\n" + "- New mod installer, built into the launcher\n" + "- Unfinished in-launcher custom controls\n" + "- Move to /usr/share, for better rootFS compatibility\n" + "- New packaging format\n" + " - release, for iOS 14 and lower (full root access jailbreaks)\n" + " - release-rootless, for iOS 15 (Procursus rootless jailbreak)" width:width]]; + [scrollView addSubview:[self uhContent:true size:17 text:@"Fixes" width:width]]; + [scrollView addSubview:[self uhContent:false size:0 text:@"- WIP fix for typing on 1.12.2 and older\n" + "- The hotbar now works across GUI scales\n" + "- (With JDK 8) Forge 1.8.9 - 1.15.2 now work\n" + "- (With JDK 8) Vanilla 1.5.2 and under now work\n" + "- Buttons now scale correctly according to screen size" width:width]]; + [scrollView addSubview:[self uhContent:true size:17 text:@"Issues" width:width]]; + [scrollView addSubview:[self uhContent:false size:0 text:@"- Crash if login to Microsoft fails\n" + "- Old custom control .json files no longer work, remove to fix\n" + "- Custom controls settings page is not complete, there may be some issues!\n" + "- An unknown issue might cause Taurine, 14.3, and A12+ to crash on launch." width:width]]; + [scrollView addSubview:[self uhContent:true size:20 text:@"1.2" width:width]]; + [scrollView addSubview:[self uhContent:true size:17 text:@"Changes" width:width]]; + [scrollView addSubview:[self uhContent:false size:0 text:@"- Use new method for Microsoft login\n" + "- Added gl4es 1.1.5 as an option\n" + "- WIP custom controls (can be changed by placing at /var/mobile/Documents/.pojavlauncher/controlmap/default.json). Note that some functions may not work properly.\n" + "- WIP external mouse support\n" + "- Custom environment variables, in /var/mobile/Documents/.pojavlauncher/custom_env.txt\n" + "- Reduction of file size with removal of unused binaries\n" + "- Moved latestlog.txt and overrideargs.txt to /var/mobile/Documents/.pojavlauncher" width:width]]; + [scrollView addSubview:[self uhContent:true size:17 text:@"Fixes" width:width]]; + [scrollView addSubview:[self uhContent:false size:0 text:@"- Fix file permission issues during install of package\n" + "- Hide home bar like Bedrock Edition\n" + "- Properly hide iPad status bar" width:width]]; + [scrollView addSubview:[self uhContent:true size:17 text:@"Issues" width:width]]; + [scrollView addSubview:[self uhContent:false size:0 text:@"- Crash if login to Microsoft fails\n" + "- Several Forge versions won’t work due to removed deprecated classes (see #67 and #68)\n" + "- Control buttons notch offset seems doubled\n" + "- Text input will not work on 1.12.2 and below" width:width]]; + [scrollView addSubview:[self uhContent:true size:20 text:@"See the GitHub for even earlier releases" width:width]]; - UILabel *backOneVerChangesCont = [[UILabel alloc] initWithFrame:CGRectMake(4.0, backOneVerChanges.frame.origin.y + backOneVerChanges.frame.size.height, scrollView.frame.size.width - 4, 30.00)]; - backOneVerChangesCont.text = @"- The Login view has been simplified to three easy buttons\n" - "- The Offline Account has been replaced with Local Account. Installing Minecraft now requires a Mojang or Microsoft account logged in.\n" - "- New FAQ page to show quick answers to questions\n" - "- New About view to show quick details, links, and update history\n" - "- Ability to send logs from within the launcher\n" - "- The Select Account screen is now a pop-up window\n" - "- New picker view to switch versions without typing them manually\n" - "- Support to show your locally installed clients\n" - "- New settings page to manage preferences\n" - "- OpenJDK 8 support, to allow older versions of modded Minecraft\n" - "- New mod installer, built into the launcher\n" - "- Unfinished in-launcher custom controls\n" - "- Move to /usr/share, for better rootFS compatibility\n" - "- New packaging format\n" - " - release, for iOS 14 and lower (full root access jailbreaks)\n" - " - release-rootless, for iOS 15 (Procursus rootless jailbreak)"; - backOneVerChangesCont.numberOfLines = 0; - [backOneVerChangesCont sizeToFit]; - [scrollView addSubview:backOneVerChangesCont]; - - UILabel *backOneVerFixes = [[UILabel alloc] initWithFrame:CGRectMake(4.0, backOneVerChangesCont.frame.origin.y + backOneVerChangesCont.frame.size.height + 5.0, scrollView.frame.size.width - 4, 30.00)]; - backOneVerFixes.text = @"Fixes"; - backOneVerFixes.numberOfLines = 0; - [scrollView addSubview:backOneVerFixes]; - [backOneVerFixes setFont:[UIFont boldSystemFontOfSize:17]]; - - UILabel *backOneVerFixesCont = [[UILabel alloc] initWithFrame:CGRectMake(4.0, backOneVerFixes.frame.origin.y + backOneVerFixes.frame.size.height, scrollView.frame.size.width - 4, 30.00)]; - backOneVerFixesCont.text = @"- WIP fix for typing on 1.12.2 and older\n" - "- The hotbar now works across GUI scales\n" - "- (With JDK 8) Forge 1.8.9 - 1.15.2 now work\n" - "- (With JDK 8) Vanilla 1.5.2 and under now work\n" - "- Buttons now scale correctly according to screen size"; - backOneVerFixesCont.numberOfLines = 0; - [backOneVerFixesCont sizeToFit]; - [scrollView addSubview:backOneVerFixesCont]; - - UILabel *backOneVerIssues = [[UILabel alloc] initWithFrame:CGRectMake(4.0, backOneVerFixesCont.frame.origin.y + backOneVerFixesCont.frame.size.height + 5.0, scrollView.frame.size.width - 4, 30.00)]; - backOneVerIssues.text = @"Issues"; - backOneVerIssues.numberOfLines = 0; - [scrollView addSubview:backOneVerIssues]; - [backOneVerIssues setFont:[UIFont boldSystemFontOfSize:17]]; - - UILabel *backOneVerIssuesCont = [[UILabel alloc] initWithFrame:CGRectMake(4.0, backOneVerIssues.frame.origin.y + backOneVerIssues.frame.size.height, scrollView.frame.size.width - 4, 30.00)]; - backOneVerIssuesCont.text = @"- Crash if login to Microsoft fails\n" - "- Old custom control .json files no longer work, remove to fix\n" - "- Custom controls settings page is not complete, there may be some issues!\n" - "- An unknown issue might cause Taurine, 14.3, and A12+ to crash on launch."; - backOneVerIssuesCont.numberOfLines = 0; - [backOneVerIssuesCont sizeToFit]; - [scrollView addSubview:backOneVerIssuesCont]; - - UILabel *backTwoVerView = [[UILabel alloc] initWithFrame:CGRectMake(4.0, backOneVerIssuesCont.frame.origin.y + backOneVerIssuesCont.frame.size.height + 20.0, scrollView.frame.size.width - 4, 30.0)]; - backTwoVerView.text = @"1.2"; - backTwoVerView.lineBreakMode = NSLineBreakByWordWrapping; - backTwoVerView.numberOfLines = 0; - [scrollView addSubview:backTwoVerView]; - [backTwoVerView setFont:[UIFont boldSystemFontOfSize:20]]; - - UILabel *backTwoVerChanges = [[UILabel alloc] initWithFrame:CGRectMake(4.0, backTwoVerView.frame.origin.y + backTwoVerView.frame.size.height, scrollView.frame.size.width - 4, 30.00)]; - backTwoVerChanges.text = @"Changes"; - backTwoVerChanges.numberOfLines = 0; - [scrollView addSubview:backTwoVerChanges]; - [backTwoVerChanges setFont:[UIFont boldSystemFontOfSize:17]]; - - - UILabel *backTwoVerChangesCont = [[UILabel alloc] initWithFrame:CGRectMake(4.0, backTwoVerChanges.frame.origin.y + backTwoVerChanges.frame.size.height, scrollView.frame.size.width - 4, 30.00)]; - backTwoVerChangesCont.text = @"- Use new method for Microsoft login\n" - "- Added gl4es 1.1.5 as an option\n" - "- WIP custom controls (can be changed by placing at /var/mobile/Documents/.pojavlauncher/controlmap/default.json). Note that some functions may not work properly.\n" - "- WIP external mouse support\n" - "- Custom environment variables, in /var/mobile/Documents/.pojavlauncher/custom_env.txt\n" - "- Reduction of file size with removal of unused binaries\n" - "- Moved latestlog.txt and overrideargs.txt to /var/mobile/Documents/.pojavlauncher"; - backTwoVerChangesCont.numberOfLines = 0; - [backTwoVerChangesCont sizeToFit]; - [scrollView addSubview:backTwoVerChangesCont]; - - UILabel *backTwoVerFixes = [[UILabel alloc] initWithFrame:CGRectMake(4.0, backTwoVerChangesCont.frame.origin.y + backTwoVerChangesCont.frame.size.height + 5.0, scrollView.frame.size.width - 4, 30.00)]; - backTwoVerFixes.text = @"Fixes"; - backTwoVerFixes.numberOfLines = 0; - [scrollView addSubview:backTwoVerFixes]; - [backTwoVerFixes setFont:[UIFont boldSystemFontOfSize:17]]; - - UILabel *backTwoVerFixesCont = [[UILabel alloc] initWithFrame:CGRectMake(4.0, backTwoVerFixes.frame.origin.y + backTwoVerFixes.frame.size.height, scrollView.frame.size.width - 4, 30.00)]; - backTwoVerFixesCont.text = @"- Fix file permission issues during install of package\n" - "- Hide home bar like Bedrock Edition\n" - "- Properly hide iPad status bar"; - backTwoVerFixesCont.numberOfLines = 0; - [backTwoVerFixesCont sizeToFit]; - [scrollView addSubview:backTwoVerFixesCont]; - - UILabel *backTwoVerIssues = [[UILabel alloc] initWithFrame:CGRectMake(4.0, backTwoVerFixesCont.frame.origin.y + backTwoVerFixesCont.frame.size.height + 5.0, scrollView.frame.size.width - 4, 30.00)]; - backTwoVerIssues.text = @"Issues"; - backTwoVerIssues.numberOfLines = 0; - [scrollView addSubview:backTwoVerIssues]; - [backTwoVerIssues setFont:[UIFont boldSystemFontOfSize:17]]; - - UILabel *backTwoVerIssuesCont = [[UILabel alloc] initWithFrame:CGRectMake(4.0, backTwoVerIssues.frame.origin.y + backTwoVerIssues.frame.size.height, scrollView.frame.size.width - 4, 30.00)]; - backTwoVerIssuesCont.text = @"- Crash if login to Microsoft fails\n" - "- Several Forge versions won’t work due to removed deprecated classes (see #67 and #68)\n" - "- Control buttons notch offset seems doubled\n" - "- Text input will not work on 1.12.2 and below"; - backTwoVerIssuesCont.numberOfLines = 0; - [backTwoVerIssuesCont sizeToFit]; - [scrollView addSubview:backTwoVerIssuesCont]; - - UILabel *backMoreVerView = [[UILabel alloc] initWithFrame:CGRectMake(4.0, backTwoVerIssuesCont.frame.origin.y + backTwoVerIssuesCont.frame.size.height, scrollView.frame.size.width - 4, 30.00)]; - backMoreVerView.text = @"See the GitHub for even earlier releases"; - backMoreVerView.numberOfLines = 0; - [scrollView addSubview:backMoreVerView]; - [backMoreVerView setFont:[UIFont boldSystemFontOfSize:20]]; - - scrollView.contentSize = CGSizeMake(scrollView.frame.size.width, backMoreVerView.frame.origin.y + backMoreVerView.frame.size.height); + scrollView.contentSize = CGSizeMake(scrollView.frame.size.width, uhcurrY); } +-(UILabel *)uhContent:(bool)isHeading size:(int)size text:(NSString *)text width:(int)width { + UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(4.0, uhcurrY, width - 40, 30.0)]; + label.text = text; + label.lineBreakMode = NSLineBreakByWordWrapping; + label.numberOfLines = 0; + if(isHeading) { + [label setFont:[UIFont boldSystemFontOfSize:size]]; + } else { + [label sizeToFit]; + } + uhcurrY+=label.frame.size.height; + return label; +} + + -(void)traitCollectionDidChange:(UITraitCollection *)previousTraitCollection { if(@available(iOS 13.0, *)) { if (UITraitCollection.currentTraitCollection.userInterfaceStyle == UIUserInterfaceStyleDark) { diff --git a/Natives/egl_bridge.m b/Natives/egl_bridge.m index c40dc5e1..4feff38b 100644 --- a/Natives/egl_bridge.m +++ b/Natives/egl_bridge.m @@ -221,12 +221,12 @@ int pojavInit() { mainThreadID = gettid(); NSString *renderer = @(getenv("RENDERER")); - + BOOL isVGPU = [renderer hasPrefix:@"libvgpu"]; if ([renderer isEqualToString:@"libOSMesa.8.dylib"]) { config_renderer = RENDERER_VIRGL; setenv("GALLIUM_DRIVER", "virpipe", 1); loadSymbolsVirGL(); - } else if ([renderer hasPrefix:@"libgl4es"] || [renderer hasPrefix:@"libtinygl4angle"]) { + } else if ([renderer hasPrefix:@"libgl4es"] || [renderer hasPrefix:@"libtinygl4angle"] || isVGPU) { config_renderer = RENDERER_MTL_ANGLE; loadSymbols(); } else if ([renderer hasPrefix:@"libOSMesa"]) { @@ -282,13 +282,15 @@ int pojavInit() { //ANativeWindow_setBuffersGeometry(potatoBridge.androidWindow, 0, 0, vid); - if (!eglBindAPI_p(EGL_OPENGL_API)) { - NSLog(@"EGLBridge: Failed to bind EGL_OPENGL_API, fallbacking to EGL_OPENGL_ES_API, error=0x%x", eglGetError_p()); + if (/*!isVGPU &&*/ !eglBindAPI_p(EGL_OPENGL_API)) { + NSLog(@"EGLBridge: Failed to bind EGL_OPENGL_API, falling back to EGL_OPENGL_ES_API, error=0x%x", eglGetError_p()); + eglBindAPI_p(EGL_OPENGL_ES_API); + } else if (isVGPU) { eglBindAPI_p(EGL_OPENGL_ES_API); } potatoBridge.eglSurface = eglCreateWindowSurface_p(potatoBridge.eglDisplay, config, (__bridge EGLNativeWindowType) ((SurfaceViewController *)viewController).surfaceView.layer, NULL); - NSLog(@"Layer %@", ((SurfaceViewController *)viewController).surfaceView.layer); + //NSLog(@"Layer %@", ((SurfaceViewController *)viewController).surfaceView.layer); if (!potatoBridge.eglSurface) { NSLog(@"EGLBridge: Error eglCreateWindowSurface failed: 0x%x", eglGetError_p()); diff --git a/Natives/external_include/GL/gl.h b/Natives/external/zink/GL/gl.h similarity index 100% rename from Natives/external_include/GL/gl.h rename to Natives/external/zink/GL/gl.h diff --git a/Natives/external_include/GL/glcorearb.h b/Natives/external/zink/GL/glcorearb.h similarity index 100% rename from Natives/external_include/GL/glcorearb.h rename to Natives/external/zink/GL/glcorearb.h diff --git a/Natives/external_include/GL/glext.h b/Natives/external/zink/GL/glext.h similarity index 100% rename from Natives/external_include/GL/glext.h rename to Natives/external/zink/GL/glext.h diff --git a/Natives/external_include/GL/glx.h b/Natives/external/zink/GL/glx.h similarity index 100% rename from Natives/external_include/GL/glx.h rename to Natives/external/zink/GL/glx.h diff --git a/Natives/external_include/GL/glxext.h b/Natives/external/zink/GL/glxext.h similarity index 100% rename from Natives/external_include/GL/glxext.h rename to Natives/external/zink/GL/glxext.h diff --git a/Natives/external_include/GL/internal/dri_interface.h b/Natives/external/zink/GL/internal/dri_interface.h similarity index 100% rename from Natives/external_include/GL/internal/dri_interface.h rename to Natives/external/zink/GL/internal/dri_interface.h diff --git a/Natives/external_include/GL/mesa_glinterop.h b/Natives/external/zink/GL/mesa_glinterop.h similarity index 100% rename from Natives/external_include/GL/mesa_glinterop.h rename to Natives/external/zink/GL/mesa_glinterop.h diff --git a/Natives/external_include/GL/osmesa.h b/Natives/external/zink/GL/osmesa.h similarity index 100% rename from Natives/external_include/GL/osmesa.h rename to Natives/external/zink/GL/osmesa.h diff --git a/Natives/external_include/GL/wglext.h b/Natives/external/zink/GL/wglext.h similarity index 100% rename from Natives/external_include/GL/wglext.h rename to Natives/external/zink/GL/wglext.h diff --git a/Natives/external_include/MoltenVK/mvk_datatypes.h b/Natives/external/zink/MoltenVK/mvk_datatypes.h similarity index 100% rename from Natives/external_include/MoltenVK/mvk_datatypes.h rename to Natives/external/zink/MoltenVK/mvk_datatypes.h diff --git a/Natives/external_include/MoltenVK/mvk_vulkan.h b/Natives/external/zink/MoltenVK/mvk_vulkan.h similarity index 100% rename from Natives/external_include/MoltenVK/mvk_vulkan.h rename to Natives/external/zink/MoltenVK/mvk_vulkan.h diff --git a/Natives/external_include/MoltenVK/vk_mvk_moltenvk.h b/Natives/external/zink/MoltenVK/vk_mvk_moltenvk.h similarity index 100% rename from Natives/external_include/MoltenVK/vk_mvk_moltenvk.h rename to Natives/external/zink/MoltenVK/vk_mvk_moltenvk.h diff --git a/Natives/external_include/vulkan/.editorconfig b/Natives/external/zink/vulkan/.editorconfig similarity index 100% rename from Natives/external_include/vulkan/.editorconfig rename to Natives/external/zink/vulkan/.editorconfig diff --git a/Natives/external_include/vulkan/vk_android_native_buffer.h b/Natives/external/zink/vulkan/vk_android_native_buffer.h similarity index 100% rename from Natives/external_include/vulkan/vk_android_native_buffer.h rename to Natives/external/zink/vulkan/vk_android_native_buffer.h diff --git a/Natives/external_include/vulkan/vk_icd.h b/Natives/external/zink/vulkan/vk_icd.h similarity index 100% rename from Natives/external_include/vulkan/vk_icd.h rename to Natives/external/zink/vulkan/vk_icd.h diff --git a/Natives/external_include/vulkan/vk_layer.h b/Natives/external/zink/vulkan/vk_layer.h similarity index 100% rename from Natives/external_include/vulkan/vk_layer.h rename to Natives/external/zink/vulkan/vk_layer.h diff --git a/Natives/external_include/vulkan/vk_platform.h b/Natives/external/zink/vulkan/vk_platform.h similarity index 100% rename from Natives/external_include/vulkan/vk_platform.h rename to Natives/external/zink/vulkan/vk_platform.h diff --git a/Natives/external_include/vulkan/vulkan.h b/Natives/external/zink/vulkan/vulkan.h similarity index 100% rename from Natives/external_include/vulkan/vulkan.h rename to Natives/external/zink/vulkan/vulkan.h diff --git a/Natives/external_include/vulkan/vulkan_android.h b/Natives/external/zink/vulkan/vulkan_android.h similarity index 100% rename from Natives/external_include/vulkan/vulkan_android.h rename to Natives/external/zink/vulkan/vulkan_android.h diff --git a/Natives/external_include/vulkan/vulkan_beta.h b/Natives/external/zink/vulkan/vulkan_beta.h similarity index 100% rename from Natives/external_include/vulkan/vulkan_beta.h rename to Natives/external/zink/vulkan/vulkan_beta.h diff --git a/Natives/external_include/vulkan/vulkan_core.h b/Natives/external/zink/vulkan/vulkan_core.h similarity index 100% rename from Natives/external_include/vulkan/vulkan_core.h rename to Natives/external/zink/vulkan/vulkan_core.h diff --git a/Natives/external_include/vulkan/vulkan_directfb.h b/Natives/external/zink/vulkan/vulkan_directfb.h similarity index 100% rename from Natives/external_include/vulkan/vulkan_directfb.h rename to Natives/external/zink/vulkan/vulkan_directfb.h diff --git a/Natives/external_include/vulkan/vulkan_fuchsia.h b/Natives/external/zink/vulkan/vulkan_fuchsia.h similarity index 100% rename from Natives/external_include/vulkan/vulkan_fuchsia.h rename to Natives/external/zink/vulkan/vulkan_fuchsia.h diff --git a/Natives/external_include/vulkan/vulkan_ggp.h b/Natives/external/zink/vulkan/vulkan_ggp.h similarity index 100% rename from Natives/external_include/vulkan/vulkan_ggp.h rename to Natives/external/zink/vulkan/vulkan_ggp.h diff --git a/Natives/external_include/vulkan/vulkan_intel.h b/Natives/external/zink/vulkan/vulkan_intel.h similarity index 100% rename from Natives/external_include/vulkan/vulkan_intel.h rename to Natives/external/zink/vulkan/vulkan_intel.h diff --git a/Natives/external_include/vulkan/vulkan_ios.h b/Natives/external/zink/vulkan/vulkan_ios.h similarity index 100% rename from Natives/external_include/vulkan/vulkan_ios.h rename to Natives/external/zink/vulkan/vulkan_ios.h diff --git a/Natives/external_include/vulkan/vulkan_macos.h b/Natives/external/zink/vulkan/vulkan_macos.h similarity index 100% rename from Natives/external_include/vulkan/vulkan_macos.h rename to Natives/external/zink/vulkan/vulkan_macos.h diff --git a/Natives/external_include/vulkan/vulkan_metal.h b/Natives/external/zink/vulkan/vulkan_metal.h similarity index 100% rename from Natives/external_include/vulkan/vulkan_metal.h rename to Natives/external/zink/vulkan/vulkan_metal.h diff --git a/Natives/external_include/vulkan/vulkan_vi.h b/Natives/external/zink/vulkan/vulkan_vi.h similarity index 100% rename from Natives/external_include/vulkan/vulkan_vi.h rename to Natives/external/zink/vulkan/vulkan_vi.h diff --git a/Natives/external_include/vulkan/vulkan_wayland.h b/Natives/external/zink/vulkan/vulkan_wayland.h similarity index 100% rename from Natives/external_include/vulkan/vulkan_wayland.h rename to Natives/external/zink/vulkan/vulkan_wayland.h diff --git a/Natives/external_include/vulkan/vulkan_win32.h b/Natives/external/zink/vulkan/vulkan_win32.h similarity index 100% rename from Natives/external_include/vulkan/vulkan_win32.h rename to Natives/external/zink/vulkan/vulkan_win32.h diff --git a/Natives/external_include/vulkan/vulkan_xcb.h b/Natives/external/zink/vulkan/vulkan_xcb.h similarity index 100% rename from Natives/external_include/vulkan/vulkan_xcb.h rename to Natives/external/zink/vulkan/vulkan_xcb.h diff --git a/Natives/external_include/vulkan/vulkan_xlib.h b/Natives/external/zink/vulkan/vulkan_xlib.h similarity index 100% rename from Natives/external_include/vulkan/vulkan_xlib.h rename to Natives/external/zink/vulkan/vulkan_xlib.h diff --git a/Natives/external_include/vulkan/vulkan_xlib_xrandr.h b/Natives/external/zink/vulkan/vulkan_xlib_xrandr.h similarity index 100% rename from Natives/external_include/vulkan/vulkan_xlib_xrandr.h rename to Natives/external/zink/vulkan/vulkan_xlib_xrandr.h diff --git a/Natives/input_bridge_v3.m b/Natives/input_bridge_v3.m index 14fe5b4b..3638557f 100644 --- a/Natives/input_bridge_v3.m +++ b/Natives/input_bridge_v3.m @@ -36,7 +36,7 @@ typedef void GLFW_invoke_Scroll_func(void* window, double xoffset, double yoffse typedef void GLFW_invoke_WindowSize_func(void* window, int width, int height); typedef void GLFW_invoke_WindowPos_func(void* window, int x, int y); -int grabCursorX, grabCursorY, lastCursorX, lastCursorY; +CGFloat grabCursorX, grabCursorY, lastCursorX, lastCursorY; jclass inputBridgeClass_ANDROID, inputBridgeClass_JRE; jmethodID inputBridgeMethod_ANDROID, inputBridgeMethod_JRE; @@ -87,12 +87,12 @@ void getJavaInputBridge(jclass* clazz, jmethodID* method) { if (*method == NULL && runtimeJNIEnvPtr_ANDROID != NULL) { *clazz = (*runtimeJNIEnvPtr_ANDROID)->FindClass(runtimeJNIEnvPtr_ANDROID, "org/lwjgl/glfw/CallbackBridge"); assert(*clazz != NULL); - *method = (*runtimeJNIEnvPtr_ANDROID)->GetStaticMethodID(runtimeJNIEnvPtr_ANDROID, *clazz, "receiveCallback", "(IIIII)V"); + *method = (*runtimeJNIEnvPtr_ANDROID)->GetStaticMethodID(runtimeJNIEnvPtr_ANDROID, *clazz, "receiveCallback", "(IFFII)V"); assert(*method != NULL); } } -void sendData(int type, int i1, int i2, int i3, int i4) { +void sendData(int type, CGFloat i1, CGFloat i2, int i3, int i4) { if (runtimeJNIEnvPtr_ANDROID == NULL) { (*runtimeJavaVMPtr)->GetEnv(runtimeJavaVMPtr, (void**) &runtimeJNIEnvPtr_ANDROID, JNI_VERSION_1_4); getJavaInputBridge(&inputBridgeClass_ANDROID, &inputBridgeMethod_ANDROID); @@ -105,12 +105,13 @@ void sendData(int type, int i1, int i2, int i3, int i4) { debug("BUG: Input is ready but thread is not attached yet."); return; } + // FIXME: should we send double instead of float? (*runtimeJNIEnvPtr_ANDROID)->CallStaticVoidMethod( runtimeJNIEnvPtr_ANDROID, inputBridgeClass_ANDROID, inputBridgeMethod_ANDROID, type, - i1, i2, i3, i4 + (jfloat)i1, (jfloat)i2, i3, i4 ); } @@ -176,21 +177,21 @@ void callback_SurfaceViewController_launchMinecraft(int width, int height) { ); } -void callback_SurfaceViewController_onTouch(int event, int x, int y) { +void callback_SurfaceViewController_onTouch(int event, CGFloat x, CGFloat y) { if (!uikitBridgeClass) { uikitBridgeClass = (*runtimeJNIEnvPtr_JRE)->FindClass(runtimeJNIEnvPtr_JRE, "net/kdt/pojavlaunch/uikit/UIKit"); assert(uikitBridgeClass != NULL); } if (!uikitBridgeTouchMethod) { - uikitBridgeTouchMethod = (*runtimeJNIEnvPtr_JRE)->GetStaticMethodID(runtimeJNIEnvPtr_JRE, uikitBridgeClass, "callback_SurfaceViewController_onTouch", "(III)V"); + uikitBridgeTouchMethod = (*runtimeJNIEnvPtr_JRE)->GetStaticMethodID(runtimeJNIEnvPtr_JRE, uikitBridgeClass, "callback_SurfaceViewController_onTouch", "(IFF)V"); assert(uikitBridgeTouchMethod != NULL); } (*runtimeJNIEnvPtr_JRE)->CallStaticVoidMethod( runtimeJNIEnvPtr_JRE, uikitBridgeClass, uikitBridgeTouchMethod, - event, x, y + event, (jfloat)x, (jfloat)y ); } @@ -200,22 +201,22 @@ const int hotbarKeys[9] = { GLFW_KEY_7, GLFW_KEY_8, GLFW_KEY_9 }; int guiScale = 1; -int mcscale(int input) { +int mcscale(CGFloat input) { return (int)((guiScale * input)/resolutionScale); } -int callback_SurfaceViewController_touchHotbar(int x, int y) { +int callback_SurfaceViewController_touchHotbar(CGFloat x, CGFloat y) { if (isGrabbing == JNI_FALSE) { return -1; } - int barHeight = mcscale(20); - int barWidth = mcscale(180); + int barHeight = mcscale(40); // 20 + int barWidth = mcscale(360); // 180 int barX = (savedWidth / 2) - (barWidth / 2); int barY = savedHeight - barHeight; if (x < barX || x >= barX + barWidth || y < barY || y >= barY + barHeight) { return -1; } - return hotbarKeys[((x - barX) / mcscale(180 / 9)) % 9]; + return hotbarKeys[(int) MathUtils_map(x, barX, barX + barWidth, 0, 9)]; } JNIEXPORT void JNICALL Java_net_kdt_pojavlaunch_uikit_UIKit_updateMCGuiScale(JNIEnv* env, jclass clazz, jint scale) { @@ -256,7 +257,7 @@ JNIEXPORT jboolean JNICALL Java_org_lwjgl_glfw_CallbackBridge_nativeSetInputRead return isUseStackQueueCall; } -JNIEXPORT void JNICALL Java_org_lwjgl_glfw_CallbackBridge_nativeSetGrabbing(JNIEnv* env, jclass clazz, jboolean grabbing, jint xset, jint yset) { +JNIEXPORT void JNICALL Java_org_lwjgl_glfw_CallbackBridge_nativeSetGrabbing(JNIEnv* env, jclass clazz, jboolean grabbing, jfloat xset, jfloat yset) { isGrabbing = grabbing; if (isGrabbing == JNI_TRUE) { grabCursorX = xset; // savedWidth / 2; @@ -269,10 +270,14 @@ JNIEXPORT void JNICALL Java_org_lwjgl_glfw_CallbackBridge_nativeSetGrabbing(JNIE } dispatch_async(dispatch_get_main_queue(), ^{ + UIView *surfaceView = ((SurfaceViewController *)viewController).surfaceView; if (isGrabbing == JNI_TRUE) { CGFloat screenScale = [[UIScreen mainScreen] scale] * resolutionScale; callback_SurfaceViewController_onTouch(ACTION_DOWN, lastVirtualMousePoint.x * screenScale, lastVirtualMousePoint.y * screenScale); ((SurfaceViewController *)viewController).mousePointerView.frame = virtualMouseFrame; + [surfaceView removeGestureRecognizer:((SurfaceViewController *)viewController).scrollPanGesture]; + } else { + [surfaceView addGestureRecognizer:((SurfaceViewController *)viewController).scrollPanGesture]; } ((SurfaceViewController *)viewController).mousePointerView.hidden = isGrabbing || !virtualMouseEnabled; }); @@ -282,7 +287,7 @@ JNIEXPORT jboolean JNICALL Java_org_lwjgl_glfw_CallbackBridge_nativeIsGrabbing(J return isGrabbing; } -JNIEXPORT jboolean JNICALL Java_org_lwjgl_glfw_CallbackBridge_nativeSendChar(JNIEnv* env, jclass clazz, jchar codepoint /* jint codepoint */) { +BOOL CallbackBridge_nativeSendChar(jchar codepoint /* jint codepoint */) { if (GLFW_invoke_Char && isInputReady) { if (isUseStackQueueCall) { sendData(EVENT_TYPE_CHAR, codepoint, 0, 0, 0); @@ -290,21 +295,21 @@ JNIEXPORT jboolean JNICALL Java_org_lwjgl_glfw_CallbackBridge_nativeSendChar(JNI GLFW_invoke_Char((void*) showingWindow, (unsigned int) codepoint); // return lwjgl2_triggerCharEvent(codepoint); } - return JNI_TRUE; + return YES; } - return JNI_FALSE; + return NO; } -JNIEXPORT jboolean JNICALL Java_org_lwjgl_glfw_CallbackBridge_nativeSendCharMods(JNIEnv* env, jclass clazz, jchar codepoint, jint mods) { +BOOL CallbackBridge_nativeSendCharMods(jchar codepoint, int mods) { if (GLFW_invoke_CharMods && isInputReady) { if (isUseStackQueueCall) { sendData(EVENT_TYPE_CHAR_MODS, (unsigned int) codepoint, mods, 0, 0); } else { GLFW_invoke_CharMods((void*) showingWindow, codepoint, mods); } - return JNI_TRUE; + return YES; } - return JNI_FALSE; + return NO; } /* JNIEXPORT void JNICALL Java_org_lwjgl_glfw_CallbackBridge_nativeSendCursorEnter(JNIEnv* env, jclass clazz, jint entered) { @@ -313,7 +318,7 @@ JNIEXPORT void JNICALL Java_org_lwjgl_glfw_CallbackBridge_nativeSendCursorEnter( } } */ -JNIEXPORT void JNICALL Java_org_lwjgl_glfw_CallbackBridge_nativeSendCursorPos(JNIEnv* env, jclass clazz, jint x, jint y) { +void CallbackBridge_nativeSendCursorPos(CGFloat x, CGFloat y) { if (GLFW_invoke_CursorPos && isInputReady) { if (!isCursorEntered) { if (GLFW_invoke_CursorEnter) { @@ -356,7 +361,7 @@ JNIEXPORT void JNICALL Java_org_lwjgl_glfw_CallbackBridge_nativeSendCursorPos(JN } } -JNIEXPORT void JNICALL Java_org_lwjgl_glfw_CallbackBridge_nativeSendKey(JNIEnv* env, jclass clazz, jint key, jint scancode, jint action, jint mods) { +void CallbackBridge_nativeSendKey(int key, int scancode, int action, int mods) { if (GLFW_invoke_Key && isInputReady) { if (isUseStackQueueCall) { sendData(EVENT_TYPE_KEY, key, scancode, action, mods); @@ -366,16 +371,16 @@ JNIEXPORT void JNICALL Java_org_lwjgl_glfw_CallbackBridge_nativeSendKey(JNIEnv* } } -JNIEXPORT void JNICALL Java_org_lwjgl_glfw_CallbackBridge_nativeSendKeycode(JNIEnv* env, jclass clazz, jint keycode, jchar keychar, jint scancode, jint action, jint mods) { +void CallbackBridge_nativeSendKeycode(int keycode, char keychar, int scancode, int action, int mods) { if (isInputReady) { - Java_org_lwjgl_glfw_CallbackBridge_nativeSendKey(env, clazz, keycode, scancode, action, mods); - if (!Java_org_lwjgl_glfw_CallbackBridge_nativeSendCharMods(env, clazz, keychar, mods)) { - Java_org_lwjgl_glfw_CallbackBridge_nativeSendChar(env, clazz, keychar); + CallbackBridge_nativeSendKey(keycode, scancode, action, mods); + if (!CallbackBridge_nativeSendCharMods(keychar, mods)) { + CallbackBridge_nativeSendChar(keychar); } } } -JNIEXPORT void JNICALL Java_org_lwjgl_glfw_CallbackBridge_nativeSendMouseButton(JNIEnv* env, jclass clazz, jint button, jint action, jint mods) { +void CallbackBridge_nativeSendMouseButton(int button, int action, int mods) { if (isInputReady) { if (button == -1) { // Notify to prepare set new grab pos @@ -390,7 +395,7 @@ JNIEXPORT void JNICALL Java_org_lwjgl_glfw_CallbackBridge_nativeSendMouseButton( } } -JNIEXPORT void JNICALL Java_org_lwjgl_glfw_CallbackBridge_nativeSendScreenSize(JNIEnv* env, jclass clazz, jint width, jint height) { +void CallbackBridge_nativeSendScreenSize(int width, int height) { savedWidth = width; savedHeight = height; @@ -415,7 +420,7 @@ JNIEXPORT void JNICALL Java_org_lwjgl_glfw_CallbackBridge_nativeSendScreenSize(J // return (isInputReady && (GLFW_invoke_FramebufferSize || GLFW_invoke_WindowSize)); } -JNIEXPORT void JNICALL Java_org_lwjgl_glfw_CallbackBridge_nativeSendScroll(JNIEnv* env, jclass clazz, jdouble xoffset, jdouble yoffset) { +void CallbackBridge_nativeSendScroll(CGFloat xoffset, CGFloat yoffset) { if (GLFW_invoke_Scroll && isInputReady) { if (isUseStackQueueCall) { sendData(EVENT_TYPE_SCROLL, xoffset, yoffset, 0, 0); @@ -425,7 +430,7 @@ JNIEXPORT void JNICALL Java_org_lwjgl_glfw_CallbackBridge_nativeSendScroll(JNIEn } } -JNIEXPORT void JNICALL Java_org_lwjgl_glfw_CallbackBridge_nativeSendWindowPos(JNIEnv* env, jclass clazz, jint x, jint y) { +void CallbackBridge_nativeSendWindowPos(int x, int y) { if (GLFW_invoke_WindowPos && isInputReady) { if (isUseStackQueueCall) { sendData(EVENT_TYPE_WINDOW_POS, x, y, 0, 0); @@ -439,3 +444,10 @@ JNIEXPORT void JNICALL Java_org_lwjgl_glfw_GLFW_nglfwSetShowingWindow(JNIEnv* en showingWindow = (long) window; } +void CallbackBridge_sendKeycode(int keycode, jchar keychar, int scancode, int modifiers, BOOL isDown) { + if(keycode != 0) CallbackBridge_nativeSendKey(keycode,scancode,isDown ? 1 : 0, modifiers); + if(isDown && keychar != '\0') { + CallbackBridge_nativeSendCharMods(keychar, modifiers); + CallbackBridge_nativeSendChar(keychar); + } +} diff --git a/Natives/ios_uikit_bridge.h b/Natives/ios_uikit_bridge.h index 953dc7d0..7d890b29 100644 --- a/Natives/ios_uikit_bridge.h +++ b/Natives/ios_uikit_bridge.h @@ -3,7 +3,9 @@ #include "jni.h" void showDialog(UIViewController *viewController, NSString* title, NSString* message); +UIAlertController* createLoadingAlert(NSString* message); jstring UIKit_accessClipboard(JNIEnv* env, jint action, jstring copySrc); void UIKit_updateProgress(float progress, const char* message); void UIKit_launchJarFile(const char* filepath); void UIKit_launchMinecraftSurfaceVC(); +void launchInitialViewController(); diff --git a/Natives/ios_uikit_bridge.m b/Natives/ios_uikit_bridge.m index be016b47..02dcd206 100644 --- a/Natives/ios_uikit_bridge.m +++ b/Natives/ios_uikit_bridge.m @@ -1,6 +1,9 @@ #import "AppDelegate.h" +#import "BKSSystemService.h" #import "SceneDelegate.h" +#import "LoginViewController.h" +#import "LauncherPreferences.h" #import "LauncherViewController.h" #import "SurfaceViewController.h" @@ -127,27 +130,34 @@ void UIKit_launchJarFile(const char* filepath) { } void UIKit_launchMinecraftSurfaceVC() { -#if 1 // debug - NSLog(@"DBG: are we on main thread = %d", [NSThread isMainThread]); + setPreference(@"internal_selected_account", @(getenv("POJAV_INTERNAL_SELECTED_ACCOUNT"))); dispatch_async(dispatch_get_main_queue(), ^{ - NSLog(@"DBG: INSIDE main queue: are we on main thread = %d", [NSThread isMainThread]); - UIViewController *rootController = UIApplication.sharedApplication.windows.lastObject.rootViewController; - NSLog(@"DBG: Got rootController = %p", rootController); - SurfaceViewController *vc = [[SurfaceViewController alloc] init]; - NSLog(@"DBG: Got Surface VC = %p", vc); - vc.modalPresentationStyle = UIModalPresentationFullScreen; - NSLog(@"DBG: set present style"); - [rootController presentViewController:vc animated:YES completion:nil]; - NSLog(@"DBG: presented vc"); - // rootController.childForScreenEdgesDeferringSystemGestures = vc; + if ([getPreference(@"restart_before_launch") boolValue]) { + NSURL *url = [NSURL URLWithString:@"pojavlauncher://"]; + BKSSystemService *service = [[NSClassFromString(@"BKSSystemService") alloc] init]; + unsigned int port = [service createClientPort]; + [service openURL:url application:@"net.kdt.pojavlauncher" options:nil clientPort:port withResult:nil]; + + // exiting too fast will cause it to fail (race condition?) + // [FBSystemService][0xbb88] Caller "PojavLauncher:pid" has a sandbox that does not allow opening URL's. + // The request was denied by service delegate (SBMainWorkspace) for reason: Security ("Sandbox check failed for process (PojavLauncher:pid) openURL not allowed"). + // therefore, sleep for 1ms before exit + usleep(1000); + exit(0); + } else { + SurfaceViewController *vc = [[SurfaceViewController alloc] init]; + vc.modalPresentationStyle = UIModalPresentationFullScreen; + [viewController.navigationController pushViewController:vc animated:YES]; + } }); -#else - dispatch_async(dispatch_get_main_queue(), ^{ - UIViewController *rootController = UIApplication.sharedApplication.windows.lastObject.rootViewController; - SurfaceViewController *vc = [[SurfaceViewController alloc] init]; - vc.modalPresentationStyle = UIModalPresentationFullScreen; - [rootController presentViewController:vc animated:YES completion:nil]; - // rootController.childForScreenEdgesDeferringSystemGestures = vc; - }); -#endif +} + +void launchInitialViewController(UIWindow *window) { + NSString *selectedAccount = getPreference(@"internal_selected_account"); + if (selectedAccount == nil) { + LoginViewController *vc = [[LoginViewController alloc] init]; + window.rootViewController = [[UINavigationController alloc] initWithRootViewController:vc]; + } else { + window.rootViewController = [[SurfaceViewController alloc] init]; + } } diff --git a/Natives/resources/Assets.car b/Natives/resources/Assets.car index bc1f6311..f95262c0 100644 Binary files a/Natives/resources/Assets.car and b/Natives/resources/Assets.car differ diff --git a/Natives/resources/Frameworks/Alderis.framework/Alderis b/Natives/resources/Frameworks/Alderis.framework/Alderis new file mode 100755 index 00000000..0ebc02ee Binary files /dev/null and b/Natives/resources/Frameworks/Alderis.framework/Alderis differ diff --git a/Natives/resources/Frameworks/Alderis.framework/Assets.car b/Natives/resources/Frameworks/Alderis.framework/Assets.car new file mode 100644 index 00000000..97196c46 Binary files /dev/null and b/Natives/resources/Frameworks/Alderis.framework/Assets.car differ diff --git a/Natives/resources/Frameworks/Alderis.framework/Headers/Alderis-Swift.h b/Natives/resources/Frameworks/Alderis.framework/Headers/Alderis-Swift.h new file mode 100644 index 00000000..e6ddf3f0 --- /dev/null +++ b/Natives/resources/Frameworks/Alderis.framework/Headers/Alderis-Swift.h @@ -0,0 +1,1300 @@ +#if 0 +#elif defined(__arm64e__) && __arm64e__ +// Generated by Apple Swift version 5.2.4 (swiftlang-1103.0.32.9 clang-1103.0.32.53) +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wgcc-compat" + +#if !defined(__has_include) +# define __has_include(x) 0 +#endif +#if !defined(__has_attribute) +# define __has_attribute(x) 0 +#endif +#if !defined(__has_feature) +# define __has_feature(x) 0 +#endif +#if !defined(__has_warning) +# define __has_warning(x) 0 +#endif + +#if __has_include() +# include +#endif + +#pragma clang diagnostic ignored "-Wauto-import" +#include +#include +#include +#include + +#if !defined(SWIFT_TYPEDEFS) +# define SWIFT_TYPEDEFS 1 +# if __has_include() +# include +# elif !defined(__cplusplus) +typedef uint_least16_t char16_t; +typedef uint_least32_t char32_t; +# endif +typedef float swift_float2 __attribute__((__ext_vector_type__(2))); +typedef float swift_float3 __attribute__((__ext_vector_type__(3))); +typedef float swift_float4 __attribute__((__ext_vector_type__(4))); +typedef double swift_double2 __attribute__((__ext_vector_type__(2))); +typedef double swift_double3 __attribute__((__ext_vector_type__(3))); +typedef double swift_double4 __attribute__((__ext_vector_type__(4))); +typedef int swift_int2 __attribute__((__ext_vector_type__(2))); +typedef int swift_int3 __attribute__((__ext_vector_type__(3))); +typedef int swift_int4 __attribute__((__ext_vector_type__(4))); +typedef unsigned int swift_uint2 __attribute__((__ext_vector_type__(2))); +typedef unsigned int swift_uint3 __attribute__((__ext_vector_type__(3))); +typedef unsigned int swift_uint4 __attribute__((__ext_vector_type__(4))); +#endif + +#if !defined(SWIFT_PASTE) +# define SWIFT_PASTE_HELPER(x, y) x##y +# define SWIFT_PASTE(x, y) SWIFT_PASTE_HELPER(x, y) +#endif +#if !defined(SWIFT_METATYPE) +# define SWIFT_METATYPE(X) Class +#endif +#if !defined(SWIFT_CLASS_PROPERTY) +# if __has_feature(objc_class_property) +# define SWIFT_CLASS_PROPERTY(...) __VA_ARGS__ +# else +# define SWIFT_CLASS_PROPERTY(...) +# endif +#endif + +#if __has_attribute(objc_runtime_name) +# define SWIFT_RUNTIME_NAME(X) __attribute__((objc_runtime_name(X))) +#else +# define SWIFT_RUNTIME_NAME(X) +#endif +#if __has_attribute(swift_name) +# define SWIFT_COMPILE_NAME(X) __attribute__((swift_name(X))) +#else +# define SWIFT_COMPILE_NAME(X) +#endif +#if __has_attribute(objc_method_family) +# define SWIFT_METHOD_FAMILY(X) __attribute__((objc_method_family(X))) +#else +# define SWIFT_METHOD_FAMILY(X) +#endif +#if __has_attribute(noescape) +# define SWIFT_NOESCAPE __attribute__((noescape)) +#else +# define SWIFT_NOESCAPE +#endif +#if __has_attribute(ns_consumed) +# define SWIFT_RELEASES_ARGUMENT __attribute__((ns_consumed)) +#else +# define SWIFT_RELEASES_ARGUMENT +#endif +#if __has_attribute(warn_unused_result) +# define SWIFT_WARN_UNUSED_RESULT __attribute__((warn_unused_result)) +#else +# define SWIFT_WARN_UNUSED_RESULT +#endif +#if __has_attribute(noreturn) +# define SWIFT_NORETURN __attribute__((noreturn)) +#else +# define SWIFT_NORETURN +#endif +#if !defined(SWIFT_CLASS_EXTRA) +# define SWIFT_CLASS_EXTRA +#endif +#if !defined(SWIFT_PROTOCOL_EXTRA) +# define SWIFT_PROTOCOL_EXTRA +#endif +#if !defined(SWIFT_ENUM_EXTRA) +# define SWIFT_ENUM_EXTRA +#endif +#if !defined(SWIFT_CLASS) +# if __has_attribute(objc_subclassing_restricted) +# define SWIFT_CLASS(SWIFT_NAME) SWIFT_RUNTIME_NAME(SWIFT_NAME) __attribute__((objc_subclassing_restricted)) SWIFT_CLASS_EXTRA +# define SWIFT_CLASS_NAMED(SWIFT_NAME) __attribute__((objc_subclassing_restricted)) SWIFT_COMPILE_NAME(SWIFT_NAME) SWIFT_CLASS_EXTRA +# else +# define SWIFT_CLASS(SWIFT_NAME) SWIFT_RUNTIME_NAME(SWIFT_NAME) SWIFT_CLASS_EXTRA +# define SWIFT_CLASS_NAMED(SWIFT_NAME) SWIFT_COMPILE_NAME(SWIFT_NAME) SWIFT_CLASS_EXTRA +# endif +#endif +#if !defined(SWIFT_RESILIENT_CLASS) +# if __has_attribute(objc_class_stub) +# define SWIFT_RESILIENT_CLASS(SWIFT_NAME) SWIFT_CLASS(SWIFT_NAME) __attribute__((objc_class_stub)) +# define SWIFT_RESILIENT_CLASS_NAMED(SWIFT_NAME) __attribute__((objc_class_stub)) SWIFT_CLASS_NAMED(SWIFT_NAME) +# else +# define SWIFT_RESILIENT_CLASS(SWIFT_NAME) SWIFT_CLASS(SWIFT_NAME) +# define SWIFT_RESILIENT_CLASS_NAMED(SWIFT_NAME) SWIFT_CLASS_NAMED(SWIFT_NAME) +# endif +#endif + +#if !defined(SWIFT_PROTOCOL) +# define SWIFT_PROTOCOL(SWIFT_NAME) SWIFT_RUNTIME_NAME(SWIFT_NAME) SWIFT_PROTOCOL_EXTRA +# define SWIFT_PROTOCOL_NAMED(SWIFT_NAME) SWIFT_COMPILE_NAME(SWIFT_NAME) SWIFT_PROTOCOL_EXTRA +#endif + +#if !defined(SWIFT_EXTENSION) +# define SWIFT_EXTENSION(M) SWIFT_PASTE(M##_Swift_, __LINE__) +#endif + +#if !defined(OBJC_DESIGNATED_INITIALIZER) +# if __has_attribute(objc_designated_initializer) +# define OBJC_DESIGNATED_INITIALIZER __attribute__((objc_designated_initializer)) +# else +# define OBJC_DESIGNATED_INITIALIZER +# endif +#endif +#if !defined(SWIFT_ENUM_ATTR) +# if defined(__has_attribute) && __has_attribute(enum_extensibility) +# define SWIFT_ENUM_ATTR(_extensibility) __attribute__((enum_extensibility(_extensibility))) +# else +# define SWIFT_ENUM_ATTR(_extensibility) +# endif +#endif +#if !defined(SWIFT_ENUM) +# define SWIFT_ENUM(_type, _name, _extensibility) enum _name : _type _name; enum SWIFT_ENUM_ATTR(_extensibility) SWIFT_ENUM_EXTRA _name : _type +# if __has_feature(generalized_swift_name) +# define SWIFT_ENUM_NAMED(_type, _name, SWIFT_NAME, _extensibility) enum _name : _type _name SWIFT_COMPILE_NAME(SWIFT_NAME); enum SWIFT_COMPILE_NAME(SWIFT_NAME) SWIFT_ENUM_ATTR(_extensibility) SWIFT_ENUM_EXTRA _name : _type +# else +# define SWIFT_ENUM_NAMED(_type, _name, SWIFT_NAME, _extensibility) SWIFT_ENUM(_type, _name, _extensibility) +# endif +#endif +#if !defined(SWIFT_UNAVAILABLE) +# define SWIFT_UNAVAILABLE __attribute__((unavailable)) +#endif +#if !defined(SWIFT_UNAVAILABLE_MSG) +# define SWIFT_UNAVAILABLE_MSG(msg) __attribute__((unavailable(msg))) +#endif +#if !defined(SWIFT_AVAILABILITY) +# define SWIFT_AVAILABILITY(plat, ...) __attribute__((availability(plat, __VA_ARGS__))) +#endif +#if !defined(SWIFT_WEAK_IMPORT) +# define SWIFT_WEAK_IMPORT __attribute__((weak_import)) +#endif +#if !defined(SWIFT_DEPRECATED) +# define SWIFT_DEPRECATED __attribute__((deprecated)) +#endif +#if !defined(SWIFT_DEPRECATED_MSG) +# define SWIFT_DEPRECATED_MSG(...) __attribute__((deprecated(__VA_ARGS__))) +#endif +#if __has_feature(attribute_diagnose_if_objc) +# define SWIFT_DEPRECATED_OBJC(Msg) __attribute__((diagnose_if(1, Msg, "warning"))) +#else +# define SWIFT_DEPRECATED_OBJC(Msg) SWIFT_DEPRECATED_MSG(Msg) +#endif +#if !defined(IBSegueAction) +# define IBSegueAction +#endif +#if __has_feature(modules) +#if __has_warning("-Watimport-in-framework-header") +#pragma clang diagnostic ignored "-Watimport-in-framework-header" +#endif +@import CoreGraphics; +@import Foundation; +@import ObjectiveC; +@import UIKit; +#endif + +#pragma clang diagnostic ignored "-Wproperty-attribute-mismatch" +#pragma clang diagnostic ignored "-Wduplicate-method-arg" +#if __has_warning("-Wpragma-clang-attribute") +# pragma clang diagnostic ignored "-Wpragma-clang-attribute" +#endif +#pragma clang diagnostic ignored "-Wunknown-pragmas" +#pragma clang diagnostic ignored "-Wnullability" + +#if __has_attribute(external_source_symbol) +# pragma push_macro("any") +# undef any +# pragma clang attribute push(__attribute__((external_source_symbol(language="Swift", defined_in="Alderis",generated_declaration))), apply_to=any(function,enum,objc_interface,objc_category,objc_protocol)) +# pragma pop_macro("any") +#endif + +@protocol UIViewControllerContextTransitioning; + +SWIFT_CLASS("_TtC7Alderis21BottomSheetTransition") +@interface BottomSheetTransition : NSObject +- (NSTimeInterval)transitionDuration:(id _Nullable)transitionContext SWIFT_WARN_UNUSED_RESULT; +- (void)animateTransition:(id _Nonnull)transitionContext; +- (nonnull instancetype)init SWIFT_UNAVAILABLE; ++ (nonnull instancetype)new SWIFT_UNAVAILABLE_MSG("-init is unavailable"); +@end + +@class UIViewController; + +SWIFT_CLASS("_TtC7Alderis32BottomSheetTransitioningDelegate") +@interface BottomSheetTransitioningDelegate : NSObject +- (id _Nullable)animationControllerForPresentedController:(UIViewController * _Nonnull)presented presentingController:(UIViewController * _Nonnull)presenting sourceController:(UIViewController * _Nonnull)source SWIFT_WARN_UNUSED_RESULT; +- (id _Nullable)animationControllerForDismissedController:(UIViewController * _Nonnull)dismissed SWIFT_WARN_UNUSED_RESULT; +- (nonnull instancetype)init OBJC_DESIGNATED_INITIALIZER; +@end + +@class UIColor; +@class NSCoder; +@class UITraitCollection; +@class UIAction; + +/// ColorWell can be used to present the user’s color selection in your user interface. It +/// optionally also supports drag-and-drop operations. +/// By default, drop interactions are supported, which causes a UIControl.Event.valueChanged event +/// to be emitted. Optionally, drag operations can be enabled, allowing the color to be dropped +/// elsewhere. +/// You can also use UIControl.Event.touchUpInside to perform an action, such as to initialise +/// and present an instance of ColorPickerViewController. +SWIFT_CLASS_NAMED("ColorWell") +@interface HBColorWell : UIControl +/// Set the color to be displayed by the view. +@property (nonatomic, strong) UIColor * _Nullable color; +/// Override the default border color if desired. +@property (nonatomic, strong) UIColor * _Nullable borderColor; +/// Whether the user can begin a drag interaction from this view, allowing them to drop the color +/// into a supporting app. The default is false. +@property (nonatomic) BOOL isDragInteractionEnabled; +/// Whether the user can end a drag interaction by dropping on this view, allowing them to drag a +/// color from a supporting app onto this view. The default is true. +/// To handle a color being dropped on this view, add an action for the .valueChanged event. For +/// example: +/// \code +/// circleView.addTarget(self, action: #selector(self.handleColorDropEvent(_:)), for: .valueChanged) +/// +/// \endcode +@property (nonatomic) BOOL isDropInteractionEnabled; +/// :nodoc: +- (nonnull instancetype)initWithFrame:(CGRect)frame OBJC_DESIGNATED_INITIALIZER; +/// :nodoc: +- (nullable instancetype)initWithCoder:(NSCoder * _Nonnull)coder OBJC_DESIGNATED_INITIALIZER; +/// :nodoc: +- (void)layoutSubviews; +/// :nodoc: +- (void)didMoveToWindow; +/// :nodoc: +- (void)traitCollectionDidChange:(UITraitCollection * _Nullable)previousTraitCollection; +/// :nodoc: +- (void)addTarget:(id _Nullable)target action:(SEL _Nonnull)action forControlEvents:(UIControlEvents)controlEvents; +/// :nodoc: +- (void)addAction:(UIAction * _Nonnull)action forControlEvents:(UIControlEvents)controlEvents /*SWIFT_AVAILABILITY(maccatalyst,introduced=14)*/ SWIFT_AVAILABILITY(ios,introduced=14); +/// :nodoc: +- (void)removeTarget:(id _Nullable)target action:(SEL _Nullable)action forControlEvents:(UIControlEvents)controlEvents; +/// :nodoc: +- (void)removeAction:(UIAction * _Nonnull)action forControlEvents:(UIControlEvents)controlEvents /*SWIFT_AVAILABILITY(maccatalyst,introduced=14)*/ SWIFT_AVAILABILITY(ios,introduced=14); +/// :nodoc: +- (void)removeActionForIdentifier:(UIActionIdentifier _Nonnull)actionIdentifier forControlEvents:(UIControlEvents)controlEvents /*SWIFT_AVAILABILITY(maccatalyst,introduced=14)*/ SWIFT_AVAILABILITY(ios,introduced=14); +@end + + +/// Deprecated. Use ColorWell instead. +SWIFT_CLASS_NAMED("ColorPickerCircleView") SWIFT_DEPRECATED_MSG("", "HBColorWell") +@interface HBColorPickerCircleView : HBColorWell +- (nonnull instancetype)initWithFrame:(CGRect)frame OBJC_DESIGNATED_INITIALIZER; +- (nullable instancetype)initWithCoder:(NSCoder * _Nonnull)coder OBJC_DESIGNATED_INITIALIZER; +@end + + +SWIFT_CLASS("_TtC7Alderis21ColorPickerSliderBase") +@interface ColorPickerSliderBase : UIControl +- (nullable instancetype)initWithCoder:(NSCoder * _Nonnull)coder OBJC_DESIGNATED_INITIALIZER; +- (void)sliderChanged; +- (nonnull instancetype)initWithFrame:(CGRect)frame SWIFT_UNAVAILABLE; +@end + + +SWIFT_CLASS("_TtC7Alderis26ColorPickerComponentSlider") +@interface ColorPickerComponentSlider : ColorPickerSliderBase +- (nullable instancetype)initWithCoder:(NSCoder * _Nonnull)coder OBJC_DESIGNATED_INITIALIZER; +@end + +enum HBColorPickerTab : NSInteger; + +/// ColorPickerConfiguration is used to configure an instance of ColorPickerViewController. +SWIFT_CLASS_NAMED("ColorPickerConfiguration") +@interface HBColorPickerConfiguration : NSObject +/// Initialise a configuration object with the required color property configured. +- (nonnull instancetype)initWithColor:(UIColor * _Nonnull)color OBJC_DESIGNATED_INITIALIZER; +/// The initial color to use when launching the color picker. Required. If you don’t have a value +/// set yet, provide a sensible default. +@property (nonatomic, strong) UIColor * _Nonnull color; +/// Whether to allow the user to set an alpha transparency value on the color. This controls the +/// visibility of an Alpha slider on the Sliders tab. When set to false, alpha values provided via +/// the color property, or by the user when entering a hexadecimal value on the Sliders tab, +/// will be discarded. +@property (nonatomic) BOOL supportsAlpha; +/// The title to display at the top of the popup. If set to nil, no title will be displayed. The +/// default is nil. +@property (nonatomic, copy) NSString * _Nullable title; +/// The initial tab to select when the color picker is presented. The default is +/// ColorPickerTab.swatch. +/// This value must be found in visibleTabs. +///
    +///
  • +/// see: visibleTabs +///
  • +///
+@property (nonatomic) enum HBColorPickerTab initialTab; +/// Maps visibleTabs to Objective-C due to Swift limitations. This is an implementation detail. +/// Ignore this and use visibleTabs per usual. +@property (nonatomic, copy) NSArray * _Nonnull visibleTabs; +/// Whether to display the tab selection at the top of the popup. The default is true. When set to +/// false, the user will only be able to access the tab specified in initialTab. +@property (nonatomic) BOOL showTabs; +/// When the Smart Invert accessibility feature is enabled, Alderis instructs the system to not +/// invert most of its user interface. This ensures the user can make a more accurate color +/// selection. If this behavior is not desired, you can disable it here. +@property (nonatomic) BOOL overrideSmartInvert; +/// Whether the user can end a drag interaction by dropping on the color picker window, allowing +/// them to drag a color from a supporting app. The default is true. +@property (nonatomic) BOOL isDropInteractionEnabled; +- (nonnull instancetype)init SWIFT_UNAVAILABLE; ++ (nonnull instancetype)new SWIFT_UNAVAILABLE_MSG("-init is unavailable"); +@end + +@class HBColorPickerViewController; + +/// Use ColorPickerDelegate to handle the user’s response to ColorPickerViewController. +SWIFT_PROTOCOL_NAMED("ColorPickerDelegate") +@protocol HBColorPickerDelegate +@optional +/// Informs the delegate that the user has selected a color in the color picker. Optional. +/// Use this to update your user interface with the new color value, if suitable to your use case. +/// You should, at minimum, implement either this method or colorPicker(_:didAccept:). If you +/// don’t intend to implement this method, it is expected that you implement +/// colorPicker(_:didAccept:). If you implement this method and the user selects Cancel, this +/// method will be called with the initial color passed in via ColorPickerConfiguration.color to +/// undo the selection. +///
    +///
  • +/// see: colorPicker(_:didAccept:) +///
  • +///
+/// \param colorPicker The ColorPickerViewController instance that triggered the action. +/// +/// \param color The UIColor selection the user made. +/// +- (void)colorPicker:(HBColorPickerViewController * _Nonnull)colorPicker didSelectColor:(UIColor * _Nonnull)color; +/// Informs the delegate that the user has dismissed the color picker with a positive response, +/// having selected the selected color. Optional. +/// You should, at minimum, implement either this method or colorPicker(_:didSelect:). +///
    +///
  • +/// see: colorPicker(_:didSelect:) +///
  • +///
+/// \param colorPicker The ColorPickerViewController instance that triggered the action. +/// +/// \param color The UIColor selection the user made. +/// +- (void)colorPicker:(HBColorPickerViewController * _Nonnull)colorPicker didAcceptColor:(UIColor * _Nonnull)color; +/// Informs the delegate that the user has dismissed the color picker with a negative response. +/// Optional. +/// You usually do not need to handle this condition. +/// \param colorPicker The ColorPickerViewController instance that triggered the action. +/// +- (void)colorPickerDidCancel:(HBColorPickerViewController * _Nonnull)colorPicker; +@end + +@protocol UIContentContainer; +@class NSBundle; + +SWIFT_CLASS("_TtC7Alderis30ColorPickerInnerViewController") +@interface ColorPickerInnerViewController : UIViewController +- (nullable instancetype)initWithCoder:(NSCoder * _Nonnull)coder OBJC_DESIGNATED_INITIALIZER; +- (void)viewDidLoad; +- (void)viewWillLayoutSubviews; +- (void)viewDidLayoutSubviews; +- (void)preferredContentSizeDidChangeForChildContentContainer:(id _Nonnull)container; +- (void)saveTapped; +- (nonnull instancetype)initWithNibName:(NSString * _Nullable)nibNameOrNil bundle:(NSBundle * _Nullable)nibBundleOrNil SWIFT_UNAVAILABLE; +@end + + + +@class UIPresentationController; + +@interface ColorPickerInnerViewController (SWIFT_EXTENSION(Alderis)) +- (void)presentationControllerWillDismiss:(UIPresentationController * _Nonnull)presentationController; +@end + +@class UIDropInteraction; +@protocol UIDropSession; +@class UIDropProposal; + +@interface ColorPickerInnerViewController (SWIFT_EXTENSION(Alderis)) +- (BOOL)dropInteraction:(UIDropInteraction * _Nonnull)interaction canHandleSession:(id _Nonnull)session SWIFT_WARN_UNUSED_RESULT; +- (UIDropProposal * _Nonnull)dropInteraction:(UIDropInteraction * _Nonnull)interaction sessionDidUpdate:(id _Nonnull)session SWIFT_WARN_UNUSED_RESULT; +- (void)dropInteraction:(UIDropInteraction * _Nonnull)interaction performDrop:(id _Nonnull)session; +@end + + +SWIFT_CLASS("_TtC7Alderis20ColorPickerMapSlider") +@interface ColorPickerMapSlider : ColorPickerComponentSlider +- (nullable instancetype)initWithCoder:(NSCoder * _Nonnull)coder OBJC_DESIGNATED_INITIALIZER; +@end + + +SWIFT_CLASS("_TtC7Alderis32ColorPickerTabViewControllerBase") +@interface ColorPickerTabViewControllerBase : UIViewController +- (nullable instancetype)initWithCoder:(NSCoder * _Nonnull)coder OBJC_DESIGNATED_INITIALIZER; +- (nonnull instancetype)initWithNibName:(NSString * _Nullable)nibNameOrNil bundle:(NSBundle * _Nullable)nibBundleOrNil SWIFT_UNAVAILABLE; +@end + + +SWIFT_CLASS("_TtC7Alderis28ColorPickerMapViewController") +@interface ColorPickerMapViewController : ColorPickerTabViewControllerBase +- (void)viewDidLoad; +- (void)viewDidLayoutSubviews; +- (nullable instancetype)initWithCoder:(NSCoder * _Nonnull)coder OBJC_DESIGNATED_INITIALIZER; +@end + + + + +SWIFT_CLASS("_TtC7Alderis24ColorPickerNumericSlider") +@interface ColorPickerNumericSlider : ColorPickerComponentSlider +- (nullable instancetype)initWithCoder:(NSCoder * _Nonnull)coder OBJC_DESIGNATED_INITIALIZER; +@end + +@class UITextField; + +@interface ColorPickerNumericSlider (SWIFT_EXTENSION(Alderis)) +- (BOOL)textField:(UITextField * _Nonnull)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString * _Nonnull)string SWIFT_WARN_UNUSED_RESULT; +@end + + +@class UISegmentedControl; +@class UITouch; +@class UIEvent; + +SWIFT_CLASS("_TtC7Alderis32ColorPickerSlidersViewController") +@interface ColorPickerSlidersViewController : ColorPickerTabViewControllerBase +- (void)viewDidLoad; +- (void)segmentControlChanged:(UISegmentedControl * _Nonnull)sender; +- (void)touchesBegan:(NSSet * _Nonnull)touches withEvent:(UIEvent * _Nullable)event; +- (void)sliderChanged:(ColorPickerNumericSlider * _Nonnull)slider; +- (nullable instancetype)initWithCoder:(NSCoder * _Nonnull)coder OBJC_DESIGNATED_INITIALIZER; +@end + + +@interface ColorPickerSlidersViewController (SWIFT_EXTENSION(Alderis)) +- (BOOL)textFieldShouldReturn:(UITextField * _Nonnull)textField SWIFT_WARN_UNUSED_RESULT; +- (BOOL)textField:(UITextField * _Nonnull)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString * _Nonnull)string SWIFT_WARN_UNUSED_RESULT; +@end + + +SWIFT_CLASS("_TtC7Alderis31ColorPickerSwatchViewController") +@interface ColorPickerSwatchViewController : ColorPickerTabViewControllerBase +- (void)viewDidLoad; +- (void)viewDidLayoutSubviews; +- (nullable instancetype)initWithCoder:(NSCoder * _Nonnull)coder OBJC_DESIGNATED_INITIALIZER; +@end + +/// An enumeration of the tabs ColorPickerViewController features. Use these enumeration values to +/// set tab-related settings on ColorPickerConfiguration. +typedef SWIFT_ENUM_NAMED(NSInteger, HBColorPickerTab, "ColorPickerTab", open) { +/// Tab 1: A grid of 9 variations of 11 colours, and a grayscale ramp. The first and default tab. + HBColorPickerTabSwatch = 0, +/// Tab 2: A color wheel displaying every possible hue and saturation combination. The user can +/// additionally adjust the brightness of the colour using a slider. + HBColorPickerTabMap = 1, +/// Tab 3: A set of sliders for red, green, and blue color values, which can be switched to hue, +/// saturation, and brightness. The user can additionally copy or enter a color value expressed +/// using a CSS-style hexadecimal string, and adjust alpha transparency. + HBColorPickerTabSliders = 2, +}; + + + +/// Provides the Color Picker user interface. +/// Present this view controller to display the color picker. Do not push it onto a navigation +/// controller stack. In horizontally and vertically regular size class environments, for instance +/// on iPad and Mac, the picker will be presented as a popover. This means that you must set +/// sourceView or other similar properties on the view controller’s popoverPresentationController +/// before presentation. +/// To review examples of ColorPickerViewController in use, run pod try Alderis. +SWIFT_CLASS_NAMED("ColorPickerViewController") +@interface HBColorPickerViewController : UIViewController +/// Initialise an instance of ColorPickerViewController with a configuration object. +/// Remember to set the delegate before presenting the view controller. +- (nonnull instancetype)initWithConfiguration:(HBColorPickerConfiguration * _Nonnull)configuration OBJC_DESIGNATED_INITIALIZER; +/// The delegate that will receive the user’s selection upon tapping the Done button, or a +/// cancellation upon tapping the Cancel button. +@property (nonatomic, weak) id _Nullable delegate; +/// The configuration of the color picker. Use this to set the initially selected color, as well +/// as other behavioral options. +/// Making changes to this value or its properties after the color picker interface has been +/// presented may result in undefined behavior. +///
    +///
  • +/// see: ColorPickerConfiguration +///
  • +///
+@property (nonatomic, strong) HBColorPickerConfiguration * _Null_unspecified configuration; +/// Deprecated. Set overrideSmartInvert on the ColorPickerConfiguration instead. +///
    +///
  • +/// see: ColorPickerConfiguration.overrideSmartInvert +///
  • +///
+@property (nonatomic) BOOL overrideSmartInvert SWIFT_DEPRECATED_MSG("Use ColorPickerConfiguration instead"); +/// Deprecated. Set color on the ColorPickerConfiguration instead. +///
    +///
  • +/// see: ColorPickerConfiguration.color +///
  • +///
+@property (nonatomic, strong) UIColor * _Nonnull color SWIFT_DEPRECATED_MSG("Use ColorPickerConfiguration instead"); +/// :nodoc: +- (nonnull instancetype)initWithNibName:(NSString * _Nullable)nibNameOrNil bundle:(NSBundle * _Nullable)nibBundleOrNil OBJC_DESIGNATED_INITIALIZER; +/// :nodoc: +- (nullable instancetype)initWithCoder:(NSCoder * _Nonnull)coder OBJC_DESIGNATED_INITIALIZER; +/// :nodoc: +- (void)viewDidLoad; +/// :nodoc: +- (void)viewWillLayoutSubviews; +/// :nodoc: +- (void)viewSafeAreaInsetsDidChange; +/// :nodoc: +- (void)preferredContentSizeDidChangeForChildContentContainer:(id _Nonnull)container; +/// :nodoc: +- (void)viewWillAppear:(BOOL)animated; +/// :nodoc: +- (void)viewDidAppear:(BOOL)animated; +/// :nodoc: +- (void)viewWillDisappear:(BOOL)animated; +/// :nodoc: +- (void)traitCollectionDidChange:(UITraitCollection * _Nullable)previousTraitCollection; +@end + + +SWIFT_CLASS("_TtC7Alderis20ColorPickerWheelView") +@interface ColorPickerWheelView : UIView +- (nullable instancetype)initWithCoder:(NSCoder * _Nonnull)coder OBJC_DESIGNATED_INITIALIZER; +- (void)layoutSubviews; +- (nonnull instancetype)initWithFrame:(CGRect)frame SWIFT_UNAVAILABLE; +@end + + +@class UIDragInteraction; +@protocol UIDragSession; +@class UIDragItem; + +@interface HBColorWell (SWIFT_EXTENSION(Alderis)) +/// :nodoc: +- (NSArray * _Nonnull)dragInteraction:(UIDragInteraction * _Nonnull)interaction itemsForBeginningSession:(id _Nonnull)session SWIFT_WARN_UNUSED_RESULT; +@end + + +@interface HBColorWell (SWIFT_EXTENSION(Alderis)) +/// :nodoc: +- (BOOL)dropInteraction:(UIDropInteraction * _Nonnull)interaction canHandleSession:(id _Nonnull)session SWIFT_WARN_UNUSED_RESULT; +/// :nodoc: +- (UIDropProposal * _Nonnull)dropInteraction:(UIDropInteraction * _Nonnull)interaction sessionDidUpdate:(id _Nonnull)session SWIFT_WARN_UNUSED_RESULT; +/// :nodoc: +- (void)dropInteraction:(UIDropInteraction * _Nonnull)interaction performDrop:(id _Nonnull)session; +@end + + +SWIFT_CLASS("_TtC7Alderis12DialogButton") +@interface DialogButton : UIButton +- (nonnull instancetype)init OBJC_DESIGNATED_INITIALIZER; +- (nullable instancetype)initWithCoder:(NSCoder * _Nonnull)coder OBJC_DESIGNATED_INITIALIZER; +- (nonnull instancetype)initWithFrame:(CGRect)frame SWIFT_UNAVAILABLE; +@end + + +SWIFT_CLASS("_TtC7Alderis13SeparatorView") +@interface SeparatorView : UIView +- (nullable instancetype)initWithCoder:(NSCoder * _Nonnull)coder OBJC_DESIGNATED_INITIALIZER; +- (void)updateConstraints; +- (void)didMoveToWindow; +- (nonnull instancetype)initWithFrame:(CGRect)frame SWIFT_UNAVAILABLE; +@end + + +@interface UIColor (SWIFT_EXTENSION(Alderis)) +/// Maps init(propertyListValue:) to Objective-C due to Swift limitations. This is an +/// implementation detail. Ignore this and use UIColor(propertyListValue:) or +/// -[UIColor initWithHbcp_propertyListValue:] as per usual. +///
    +///
  • +/// see: init(propertyListValue:) +///
  • +///
+/// \param value The object to retrieve data from. See the discussion for the supported +/// object types. +/// +/// +/// returns: +/// An initialized color object, or nil if the value does not conform to the expected +/// type. The color information represented by this object is in the device RGB colorspace. +/// device RGB colorspace. +- (nullable instancetype)initWithHbcp_propertyListValue:(id _Nullable)propertyListValue; +/// Returns a string that represents the color. +/// The output is a string in the format #AABBCC:0.5, where the initial #AABBCC portion is a +/// 6-character CSS-style hex string, and the final :0.5 portion represents the alpha value. If +/// the color’s alpha value is 1, the alpha portion is excluded. +/// If the color is dynamic, for instance if it is a UIKit system color, or initialised via +/// UIColor(dynamicProvider:), the color that matches the current trait collection is used. +///
    +///
  • +/// see: init(propertyListValue:) +///
  • +///
+/// +/// returns: +/// A string representing the color, in the format discussed above. +@property (nonatomic, readonly, copy) NSString * _Nonnull hbcp_propertyListValue; +@end + +#if __has_attribute(external_source_symbol) +# pragma clang attribute pop +#endif +#pragma clang diagnostic pop + +#elif defined(__arm64__) && __arm64__ +// Generated by Apple Swift version 5.2.4 (swiftlang-1103.0.32.9 clang-1103.0.32.53) +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wgcc-compat" + +#if !defined(__has_include) +# define __has_include(x) 0 +#endif +#if !defined(__has_attribute) +# define __has_attribute(x) 0 +#endif +#if !defined(__has_feature) +# define __has_feature(x) 0 +#endif +#if !defined(__has_warning) +# define __has_warning(x) 0 +#endif + +#if __has_include() +# include +#endif + +#pragma clang diagnostic ignored "-Wauto-import" +#include +#include +#include +#include + +#if !defined(SWIFT_TYPEDEFS) +# define SWIFT_TYPEDEFS 1 +# if __has_include() +# include +# elif !defined(__cplusplus) +typedef uint_least16_t char16_t; +typedef uint_least32_t char32_t; +# endif +typedef float swift_float2 __attribute__((__ext_vector_type__(2))); +typedef float swift_float3 __attribute__((__ext_vector_type__(3))); +typedef float swift_float4 __attribute__((__ext_vector_type__(4))); +typedef double swift_double2 __attribute__((__ext_vector_type__(2))); +typedef double swift_double3 __attribute__((__ext_vector_type__(3))); +typedef double swift_double4 __attribute__((__ext_vector_type__(4))); +typedef int swift_int2 __attribute__((__ext_vector_type__(2))); +typedef int swift_int3 __attribute__((__ext_vector_type__(3))); +typedef int swift_int4 __attribute__((__ext_vector_type__(4))); +typedef unsigned int swift_uint2 __attribute__((__ext_vector_type__(2))); +typedef unsigned int swift_uint3 __attribute__((__ext_vector_type__(3))); +typedef unsigned int swift_uint4 __attribute__((__ext_vector_type__(4))); +#endif + +#if !defined(SWIFT_PASTE) +# define SWIFT_PASTE_HELPER(x, y) x##y +# define SWIFT_PASTE(x, y) SWIFT_PASTE_HELPER(x, y) +#endif +#if !defined(SWIFT_METATYPE) +# define SWIFT_METATYPE(X) Class +#endif +#if !defined(SWIFT_CLASS_PROPERTY) +# if __has_feature(objc_class_property) +# define SWIFT_CLASS_PROPERTY(...) __VA_ARGS__ +# else +# define SWIFT_CLASS_PROPERTY(...) +# endif +#endif + +#if __has_attribute(objc_runtime_name) +# define SWIFT_RUNTIME_NAME(X) __attribute__((objc_runtime_name(X))) +#else +# define SWIFT_RUNTIME_NAME(X) +#endif +#if __has_attribute(swift_name) +# define SWIFT_COMPILE_NAME(X) __attribute__((swift_name(X))) +#else +# define SWIFT_COMPILE_NAME(X) +#endif +#if __has_attribute(objc_method_family) +# define SWIFT_METHOD_FAMILY(X) __attribute__((objc_method_family(X))) +#else +# define SWIFT_METHOD_FAMILY(X) +#endif +#if __has_attribute(noescape) +# define SWIFT_NOESCAPE __attribute__((noescape)) +#else +# define SWIFT_NOESCAPE +#endif +#if __has_attribute(ns_consumed) +# define SWIFT_RELEASES_ARGUMENT __attribute__((ns_consumed)) +#else +# define SWIFT_RELEASES_ARGUMENT +#endif +#if __has_attribute(warn_unused_result) +# define SWIFT_WARN_UNUSED_RESULT __attribute__((warn_unused_result)) +#else +# define SWIFT_WARN_UNUSED_RESULT +#endif +#if __has_attribute(noreturn) +# define SWIFT_NORETURN __attribute__((noreturn)) +#else +# define SWIFT_NORETURN +#endif +#if !defined(SWIFT_CLASS_EXTRA) +# define SWIFT_CLASS_EXTRA +#endif +#if !defined(SWIFT_PROTOCOL_EXTRA) +# define SWIFT_PROTOCOL_EXTRA +#endif +#if !defined(SWIFT_ENUM_EXTRA) +# define SWIFT_ENUM_EXTRA +#endif +#if !defined(SWIFT_CLASS) +# if __has_attribute(objc_subclassing_restricted) +# define SWIFT_CLASS(SWIFT_NAME) SWIFT_RUNTIME_NAME(SWIFT_NAME) __attribute__((objc_subclassing_restricted)) SWIFT_CLASS_EXTRA +# define SWIFT_CLASS_NAMED(SWIFT_NAME) __attribute__((objc_subclassing_restricted)) SWIFT_COMPILE_NAME(SWIFT_NAME) SWIFT_CLASS_EXTRA +# else +# define SWIFT_CLASS(SWIFT_NAME) SWIFT_RUNTIME_NAME(SWIFT_NAME) SWIFT_CLASS_EXTRA +# define SWIFT_CLASS_NAMED(SWIFT_NAME) SWIFT_COMPILE_NAME(SWIFT_NAME) SWIFT_CLASS_EXTRA +# endif +#endif +#if !defined(SWIFT_RESILIENT_CLASS) +# if __has_attribute(objc_class_stub) +# define SWIFT_RESILIENT_CLASS(SWIFT_NAME) SWIFT_CLASS(SWIFT_NAME) __attribute__((objc_class_stub)) +# define SWIFT_RESILIENT_CLASS_NAMED(SWIFT_NAME) __attribute__((objc_class_stub)) SWIFT_CLASS_NAMED(SWIFT_NAME) +# else +# define SWIFT_RESILIENT_CLASS(SWIFT_NAME) SWIFT_CLASS(SWIFT_NAME) +# define SWIFT_RESILIENT_CLASS_NAMED(SWIFT_NAME) SWIFT_CLASS_NAMED(SWIFT_NAME) +# endif +#endif + +#if !defined(SWIFT_PROTOCOL) +# define SWIFT_PROTOCOL(SWIFT_NAME) SWIFT_RUNTIME_NAME(SWIFT_NAME) SWIFT_PROTOCOL_EXTRA +# define SWIFT_PROTOCOL_NAMED(SWIFT_NAME) SWIFT_COMPILE_NAME(SWIFT_NAME) SWIFT_PROTOCOL_EXTRA +#endif + +#if !defined(SWIFT_EXTENSION) +# define SWIFT_EXTENSION(M) SWIFT_PASTE(M##_Swift_, __LINE__) +#endif + +#if !defined(OBJC_DESIGNATED_INITIALIZER) +# if __has_attribute(objc_designated_initializer) +# define OBJC_DESIGNATED_INITIALIZER __attribute__((objc_designated_initializer)) +# else +# define OBJC_DESIGNATED_INITIALIZER +# endif +#endif +#if !defined(SWIFT_ENUM_ATTR) +# if defined(__has_attribute) && __has_attribute(enum_extensibility) +# define SWIFT_ENUM_ATTR(_extensibility) __attribute__((enum_extensibility(_extensibility))) +# else +# define SWIFT_ENUM_ATTR(_extensibility) +# endif +#endif +#if !defined(SWIFT_ENUM) +# define SWIFT_ENUM(_type, _name, _extensibility) enum _name : _type _name; enum SWIFT_ENUM_ATTR(_extensibility) SWIFT_ENUM_EXTRA _name : _type +# if __has_feature(generalized_swift_name) +# define SWIFT_ENUM_NAMED(_type, _name, SWIFT_NAME, _extensibility) enum _name : _type _name SWIFT_COMPILE_NAME(SWIFT_NAME); enum SWIFT_COMPILE_NAME(SWIFT_NAME) SWIFT_ENUM_ATTR(_extensibility) SWIFT_ENUM_EXTRA _name : _type +# else +# define SWIFT_ENUM_NAMED(_type, _name, SWIFT_NAME, _extensibility) SWIFT_ENUM(_type, _name, _extensibility) +# endif +#endif +#if !defined(SWIFT_UNAVAILABLE) +# define SWIFT_UNAVAILABLE __attribute__((unavailable)) +#endif +#if !defined(SWIFT_UNAVAILABLE_MSG) +# define SWIFT_UNAVAILABLE_MSG(msg) __attribute__((unavailable(msg))) +#endif +#if !defined(SWIFT_AVAILABILITY) +# define SWIFT_AVAILABILITY(plat, ...) __attribute__((availability(plat, __VA_ARGS__))) +#endif +#if !defined(SWIFT_WEAK_IMPORT) +# define SWIFT_WEAK_IMPORT __attribute__((weak_import)) +#endif +#if !defined(SWIFT_DEPRECATED) +# define SWIFT_DEPRECATED __attribute__((deprecated)) +#endif +#if !defined(SWIFT_DEPRECATED_MSG) +# define SWIFT_DEPRECATED_MSG(...) __attribute__((deprecated(__VA_ARGS__))) +#endif +#if __has_feature(attribute_diagnose_if_objc) +# define SWIFT_DEPRECATED_OBJC(Msg) __attribute__((diagnose_if(1, Msg, "warning"))) +#else +# define SWIFT_DEPRECATED_OBJC(Msg) SWIFT_DEPRECATED_MSG(Msg) +#endif +#if !defined(IBSegueAction) +# define IBSegueAction +#endif +#if __has_feature(modules) +#if __has_warning("-Watimport-in-framework-header") +#pragma clang diagnostic ignored "-Watimport-in-framework-header" +#endif +@import CoreGraphics; +@import Foundation; +@import ObjectiveC; +@import UIKit; +#endif + +#pragma clang diagnostic ignored "-Wproperty-attribute-mismatch" +#pragma clang diagnostic ignored "-Wduplicate-method-arg" +#if __has_warning("-Wpragma-clang-attribute") +# pragma clang diagnostic ignored "-Wpragma-clang-attribute" +#endif +#pragma clang diagnostic ignored "-Wunknown-pragmas" +#pragma clang diagnostic ignored "-Wnullability" + +#if __has_attribute(external_source_symbol) +# pragma push_macro("any") +# undef any +# pragma clang attribute push(__attribute__((external_source_symbol(language="Swift", defined_in="Alderis",generated_declaration))), apply_to=any(function,enum,objc_interface,objc_category,objc_protocol)) +# pragma pop_macro("any") +#endif + +@protocol UIViewControllerContextTransitioning; + +SWIFT_CLASS("_TtC7Alderis21BottomSheetTransition") +@interface BottomSheetTransition : NSObject +- (NSTimeInterval)transitionDuration:(id _Nullable)transitionContext SWIFT_WARN_UNUSED_RESULT; +- (void)animateTransition:(id _Nonnull)transitionContext; +- (nonnull instancetype)init SWIFT_UNAVAILABLE; ++ (nonnull instancetype)new SWIFT_UNAVAILABLE_MSG("-init is unavailable"); +@end + +@class UIViewController; + +SWIFT_CLASS("_TtC7Alderis32BottomSheetTransitioningDelegate") +@interface BottomSheetTransitioningDelegate : NSObject +- (id _Nullable)animationControllerForPresentedController:(UIViewController * _Nonnull)presented presentingController:(UIViewController * _Nonnull)presenting sourceController:(UIViewController * _Nonnull)source SWIFT_WARN_UNUSED_RESULT; +- (id _Nullable)animationControllerForDismissedController:(UIViewController * _Nonnull)dismissed SWIFT_WARN_UNUSED_RESULT; +- (nonnull instancetype)init OBJC_DESIGNATED_INITIALIZER; +@end + +@class UIColor; +@class NSCoder; +@class UITraitCollection; +@class UIAction; + +/// ColorWell can be used to present the user’s color selection in your user interface. It +/// optionally also supports drag-and-drop operations. +/// By default, drop interactions are supported, which causes a UIControl.Event.valueChanged event +/// to be emitted. Optionally, drag operations can be enabled, allowing the color to be dropped +/// elsewhere. +/// You can also use UIControl.Event.touchUpInside to perform an action, such as to initialise +/// and present an instance of ColorPickerViewController. +SWIFT_CLASS_NAMED("ColorWell") +@interface HBColorWell : UIControl +/// Set the color to be displayed by the view. +@property (nonatomic, strong) UIColor * _Nullable color; +/// Override the default border color if desired. +@property (nonatomic, strong) UIColor * _Nullable borderColor; +/// Whether the user can begin a drag interaction from this view, allowing them to drop the color +/// into a supporting app. The default is false. +@property (nonatomic) BOOL isDragInteractionEnabled; +/// Whether the user can end a drag interaction by dropping on this view, allowing them to drag a +/// color from a supporting app onto this view. The default is true. +/// To handle a color being dropped on this view, add an action for the .valueChanged event. For +/// example: +/// \code +/// circleView.addTarget(self, action: #selector(self.handleColorDropEvent(_:)), for: .valueChanged) +/// +/// \endcode +@property (nonatomic) BOOL isDropInteractionEnabled; +/// :nodoc: +- (nonnull instancetype)initWithFrame:(CGRect)frame OBJC_DESIGNATED_INITIALIZER; +/// :nodoc: +- (nullable instancetype)initWithCoder:(NSCoder * _Nonnull)coder OBJC_DESIGNATED_INITIALIZER; +/// :nodoc: +- (void)layoutSubviews; +/// :nodoc: +- (void)didMoveToWindow; +/// :nodoc: +- (void)traitCollectionDidChange:(UITraitCollection * _Nullable)previousTraitCollection; +/// :nodoc: +- (void)addTarget:(id _Nullable)target action:(SEL _Nonnull)action forControlEvents:(UIControlEvents)controlEvents; +/// :nodoc: +- (void)addAction:(UIAction * _Nonnull)action forControlEvents:(UIControlEvents)controlEvents /*SWIFT_AVAILABILITY(maccatalyst,introduced=14)*/ SWIFT_AVAILABILITY(ios,introduced=14); +/// :nodoc: +- (void)removeTarget:(id _Nullable)target action:(SEL _Nullable)action forControlEvents:(UIControlEvents)controlEvents; +/// :nodoc: +- (void)removeAction:(UIAction * _Nonnull)action forControlEvents:(UIControlEvents)controlEvents /*SWIFT_AVAILABILITY(maccatalyst,introduced=14)*/ SWIFT_AVAILABILITY(ios,introduced=14); +/// :nodoc: +- (void)removeActionForIdentifier:(UIActionIdentifier _Nonnull)actionIdentifier forControlEvents:(UIControlEvents)controlEvents /*SWIFT_AVAILABILITY(maccatalyst,introduced=14)*/ SWIFT_AVAILABILITY(ios,introduced=14); +@end + + +/// Deprecated. Use ColorWell instead. +SWIFT_CLASS_NAMED("ColorPickerCircleView") SWIFT_DEPRECATED_MSG("", "HBColorWell") +@interface HBColorPickerCircleView : HBColorWell +- (nonnull instancetype)initWithFrame:(CGRect)frame OBJC_DESIGNATED_INITIALIZER; +- (nullable instancetype)initWithCoder:(NSCoder * _Nonnull)coder OBJC_DESIGNATED_INITIALIZER; +@end + + +SWIFT_CLASS("_TtC7Alderis21ColorPickerSliderBase") +@interface ColorPickerSliderBase : UIControl +- (nullable instancetype)initWithCoder:(NSCoder * _Nonnull)coder OBJC_DESIGNATED_INITIALIZER; +- (void)sliderChanged; +- (nonnull instancetype)initWithFrame:(CGRect)frame SWIFT_UNAVAILABLE; +@end + + +SWIFT_CLASS("_TtC7Alderis26ColorPickerComponentSlider") +@interface ColorPickerComponentSlider : ColorPickerSliderBase +- (nullable instancetype)initWithCoder:(NSCoder * _Nonnull)coder OBJC_DESIGNATED_INITIALIZER; +@end + +enum HBColorPickerTab : NSInteger; + +/// ColorPickerConfiguration is used to configure an instance of ColorPickerViewController. +SWIFT_CLASS_NAMED("ColorPickerConfiguration") +@interface HBColorPickerConfiguration : NSObject +/// Initialise a configuration object with the required color property configured. +- (nonnull instancetype)initWithColor:(UIColor * _Nonnull)color OBJC_DESIGNATED_INITIALIZER; +/// The initial color to use when launching the color picker. Required. If you don’t have a value +/// set yet, provide a sensible default. +@property (nonatomic, strong) UIColor * _Nonnull color; +/// Whether to allow the user to set an alpha transparency value on the color. This controls the +/// visibility of an Alpha slider on the Sliders tab. When set to false, alpha values provided via +/// the color property, or by the user when entering a hexadecimal value on the Sliders tab, +/// will be discarded. +@property (nonatomic) BOOL supportsAlpha; +/// The title to display at the top of the popup. If set to nil, no title will be displayed. The +/// default is nil. +@property (nonatomic, copy) NSString * _Nullable title; +/// The initial tab to select when the color picker is presented. The default is +/// ColorPickerTab.swatch. +/// This value must be found in visibleTabs. +///
    +///
  • +/// see: visibleTabs +///
  • +///
+@property (nonatomic) enum HBColorPickerTab initialTab; +/// Maps visibleTabs to Objective-C due to Swift limitations. This is an implementation detail. +/// Ignore this and use visibleTabs per usual. +@property (nonatomic, copy) NSArray * _Nonnull visibleTabs; +/// Whether to display the tab selection at the top of the popup. The default is true. When set to +/// false, the user will only be able to access the tab specified in initialTab. +@property (nonatomic) BOOL showTabs; +/// When the Smart Invert accessibility feature is enabled, Alderis instructs the system to not +/// invert most of its user interface. This ensures the user can make a more accurate color +/// selection. If this behavior is not desired, you can disable it here. +@property (nonatomic) BOOL overrideSmartInvert; +/// Whether the user can end a drag interaction by dropping on the color picker window, allowing +/// them to drag a color from a supporting app. The default is true. +@property (nonatomic) BOOL isDropInteractionEnabled; +- (nonnull instancetype)init SWIFT_UNAVAILABLE; ++ (nonnull instancetype)new SWIFT_UNAVAILABLE_MSG("-init is unavailable"); +@end + +@class HBColorPickerViewController; + +/// Use ColorPickerDelegate to handle the user’s response to ColorPickerViewController. +SWIFT_PROTOCOL_NAMED("ColorPickerDelegate") +@protocol HBColorPickerDelegate +@optional +/// Informs the delegate that the user has selected a color in the color picker. Optional. +/// Use this to update your user interface with the new color value, if suitable to your use case. +/// You should, at minimum, implement either this method or colorPicker(_:didAccept:). If you +/// don’t intend to implement this method, it is expected that you implement +/// colorPicker(_:didAccept:). If you implement this method and the user selects Cancel, this +/// method will be called with the initial color passed in via ColorPickerConfiguration.color to +/// undo the selection. +///
    +///
  • +/// see: colorPicker(_:didAccept:) +///
  • +///
+/// \param colorPicker The ColorPickerViewController instance that triggered the action. +/// +/// \param color The UIColor selection the user made. +/// +- (void)colorPicker:(HBColorPickerViewController * _Nonnull)colorPicker didSelectColor:(UIColor * _Nonnull)color; +/// Informs the delegate that the user has dismissed the color picker with a positive response, +/// having selected the selected color. Optional. +/// You should, at minimum, implement either this method or colorPicker(_:didSelect:). +///
    +///
  • +/// see: colorPicker(_:didSelect:) +///
  • +///
+/// \param colorPicker The ColorPickerViewController instance that triggered the action. +/// +/// \param color The UIColor selection the user made. +/// +- (void)colorPicker:(HBColorPickerViewController * _Nonnull)colorPicker didAcceptColor:(UIColor * _Nonnull)color; +/// Informs the delegate that the user has dismissed the color picker with a negative response. +/// Optional. +/// You usually do not need to handle this condition. +/// \param colorPicker The ColorPickerViewController instance that triggered the action. +/// +- (void)colorPickerDidCancel:(HBColorPickerViewController * _Nonnull)colorPicker; +@end + +@protocol UIContentContainer; +@class NSBundle; + +SWIFT_CLASS("_TtC7Alderis30ColorPickerInnerViewController") +@interface ColorPickerInnerViewController : UIViewController +- (nullable instancetype)initWithCoder:(NSCoder * _Nonnull)coder OBJC_DESIGNATED_INITIALIZER; +- (void)viewDidLoad; +- (void)viewWillLayoutSubviews; +- (void)viewDidLayoutSubviews; +- (void)preferredContentSizeDidChangeForChildContentContainer:(id _Nonnull)container; +- (void)saveTapped; +- (nonnull instancetype)initWithNibName:(NSString * _Nullable)nibNameOrNil bundle:(NSBundle * _Nullable)nibBundleOrNil SWIFT_UNAVAILABLE; +@end + + + +@class UIPresentationController; + +@interface ColorPickerInnerViewController (SWIFT_EXTENSION(Alderis)) +- (void)presentationControllerWillDismiss:(UIPresentationController * _Nonnull)presentationController; +@end + +@class UIDropInteraction; +@protocol UIDropSession; +@class UIDropProposal; + +@interface ColorPickerInnerViewController (SWIFT_EXTENSION(Alderis)) +- (BOOL)dropInteraction:(UIDropInteraction * _Nonnull)interaction canHandleSession:(id _Nonnull)session SWIFT_WARN_UNUSED_RESULT; +- (UIDropProposal * _Nonnull)dropInteraction:(UIDropInteraction * _Nonnull)interaction sessionDidUpdate:(id _Nonnull)session SWIFT_WARN_UNUSED_RESULT; +- (void)dropInteraction:(UIDropInteraction * _Nonnull)interaction performDrop:(id _Nonnull)session; +@end + + +SWIFT_CLASS("_TtC7Alderis20ColorPickerMapSlider") +@interface ColorPickerMapSlider : ColorPickerComponentSlider +- (nullable instancetype)initWithCoder:(NSCoder * _Nonnull)coder OBJC_DESIGNATED_INITIALIZER; +@end + + +SWIFT_CLASS("_TtC7Alderis32ColorPickerTabViewControllerBase") +@interface ColorPickerTabViewControllerBase : UIViewController +- (nullable instancetype)initWithCoder:(NSCoder * _Nonnull)coder OBJC_DESIGNATED_INITIALIZER; +- (nonnull instancetype)initWithNibName:(NSString * _Nullable)nibNameOrNil bundle:(NSBundle * _Nullable)nibBundleOrNil SWIFT_UNAVAILABLE; +@end + + +SWIFT_CLASS("_TtC7Alderis28ColorPickerMapViewController") +@interface ColorPickerMapViewController : ColorPickerTabViewControllerBase +- (void)viewDidLoad; +- (void)viewDidLayoutSubviews; +- (nullable instancetype)initWithCoder:(NSCoder * _Nonnull)coder OBJC_DESIGNATED_INITIALIZER; +@end + + + + +SWIFT_CLASS("_TtC7Alderis24ColorPickerNumericSlider") +@interface ColorPickerNumericSlider : ColorPickerComponentSlider +- (nullable instancetype)initWithCoder:(NSCoder * _Nonnull)coder OBJC_DESIGNATED_INITIALIZER; +@end + +@class UITextField; + +@interface ColorPickerNumericSlider (SWIFT_EXTENSION(Alderis)) +- (BOOL)textField:(UITextField * _Nonnull)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString * _Nonnull)string SWIFT_WARN_UNUSED_RESULT; +@end + + +@class UISegmentedControl; +@class UITouch; +@class UIEvent; + +SWIFT_CLASS("_TtC7Alderis32ColorPickerSlidersViewController") +@interface ColorPickerSlidersViewController : ColorPickerTabViewControllerBase +- (void)viewDidLoad; +- (void)segmentControlChanged:(UISegmentedControl * _Nonnull)sender; +- (void)touchesBegan:(NSSet * _Nonnull)touches withEvent:(UIEvent * _Nullable)event; +- (void)sliderChanged:(ColorPickerNumericSlider * _Nonnull)slider; +- (nullable instancetype)initWithCoder:(NSCoder * _Nonnull)coder OBJC_DESIGNATED_INITIALIZER; +@end + + +@interface ColorPickerSlidersViewController (SWIFT_EXTENSION(Alderis)) +- (BOOL)textFieldShouldReturn:(UITextField * _Nonnull)textField SWIFT_WARN_UNUSED_RESULT; +- (BOOL)textField:(UITextField * _Nonnull)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString * _Nonnull)string SWIFT_WARN_UNUSED_RESULT; +@end + + +SWIFT_CLASS("_TtC7Alderis31ColorPickerSwatchViewController") +@interface ColorPickerSwatchViewController : ColorPickerTabViewControllerBase +- (void)viewDidLoad; +- (void)viewDidLayoutSubviews; +- (nullable instancetype)initWithCoder:(NSCoder * _Nonnull)coder OBJC_DESIGNATED_INITIALIZER; +@end + +/// An enumeration of the tabs ColorPickerViewController features. Use these enumeration values to +/// set tab-related settings on ColorPickerConfiguration. +typedef SWIFT_ENUM_NAMED(NSInteger, HBColorPickerTab, "ColorPickerTab", open) { +/// Tab 1: A grid of 9 variations of 11 colours, and a grayscale ramp. The first and default tab. + HBColorPickerTabSwatch = 0, +/// Tab 2: A color wheel displaying every possible hue and saturation combination. The user can +/// additionally adjust the brightness of the colour using a slider. + HBColorPickerTabMap = 1, +/// Tab 3: A set of sliders for red, green, and blue color values, which can be switched to hue, +/// saturation, and brightness. The user can additionally copy or enter a color value expressed +/// using a CSS-style hexadecimal string, and adjust alpha transparency. + HBColorPickerTabSliders = 2, +}; + + + +/// Provides the Color Picker user interface. +/// Present this view controller to display the color picker. Do not push it onto a navigation +/// controller stack. In horizontally and vertically regular size class environments, for instance +/// on iPad and Mac, the picker will be presented as a popover. This means that you must set +/// sourceView or other similar properties on the view controller’s popoverPresentationController +/// before presentation. +/// To review examples of ColorPickerViewController in use, run pod try Alderis. +SWIFT_CLASS_NAMED("ColorPickerViewController") +@interface HBColorPickerViewController : UIViewController +/// Initialise an instance of ColorPickerViewController with a configuration object. +/// Remember to set the delegate before presenting the view controller. +- (nonnull instancetype)initWithConfiguration:(HBColorPickerConfiguration * _Nonnull)configuration OBJC_DESIGNATED_INITIALIZER; +/// The delegate that will receive the user’s selection upon tapping the Done button, or a +/// cancellation upon tapping the Cancel button. +@property (nonatomic, weak) id _Nullable delegate; +/// The configuration of the color picker. Use this to set the initially selected color, as well +/// as other behavioral options. +/// Making changes to this value or its properties after the color picker interface has been +/// presented may result in undefined behavior. +///
    +///
  • +/// see: ColorPickerConfiguration +///
  • +///
+@property (nonatomic, strong) HBColorPickerConfiguration * _Null_unspecified configuration; +/// Deprecated. Set overrideSmartInvert on the ColorPickerConfiguration instead. +///
    +///
  • +/// see: ColorPickerConfiguration.overrideSmartInvert +///
  • +///
+@property (nonatomic) BOOL overrideSmartInvert SWIFT_DEPRECATED_MSG("Use ColorPickerConfiguration instead"); +/// Deprecated. Set color on the ColorPickerConfiguration instead. +///
    +///
  • +/// see: ColorPickerConfiguration.color +///
  • +///
+@property (nonatomic, strong) UIColor * _Nonnull color SWIFT_DEPRECATED_MSG("Use ColorPickerConfiguration instead"); +/// :nodoc: +- (nonnull instancetype)initWithNibName:(NSString * _Nullable)nibNameOrNil bundle:(NSBundle * _Nullable)nibBundleOrNil OBJC_DESIGNATED_INITIALIZER; +/// :nodoc: +- (nullable instancetype)initWithCoder:(NSCoder * _Nonnull)coder OBJC_DESIGNATED_INITIALIZER; +/// :nodoc: +- (void)viewDidLoad; +/// :nodoc: +- (void)viewWillLayoutSubviews; +/// :nodoc: +- (void)viewSafeAreaInsetsDidChange; +/// :nodoc: +- (void)preferredContentSizeDidChangeForChildContentContainer:(id _Nonnull)container; +/// :nodoc: +- (void)viewWillAppear:(BOOL)animated; +/// :nodoc: +- (void)viewDidAppear:(BOOL)animated; +/// :nodoc: +- (void)viewWillDisappear:(BOOL)animated; +/// :nodoc: +- (void)traitCollectionDidChange:(UITraitCollection * _Nullable)previousTraitCollection; +@end + + +SWIFT_CLASS("_TtC7Alderis20ColorPickerWheelView") +@interface ColorPickerWheelView : UIView +- (nullable instancetype)initWithCoder:(NSCoder * _Nonnull)coder OBJC_DESIGNATED_INITIALIZER; +- (void)layoutSubviews; +- (nonnull instancetype)initWithFrame:(CGRect)frame SWIFT_UNAVAILABLE; +@end + + +@class UIDragInteraction; +@protocol UIDragSession; +@class UIDragItem; + +@interface HBColorWell (SWIFT_EXTENSION(Alderis)) +/// :nodoc: +- (NSArray * _Nonnull)dragInteraction:(UIDragInteraction * _Nonnull)interaction itemsForBeginningSession:(id _Nonnull)session SWIFT_WARN_UNUSED_RESULT; +@end + + +@interface HBColorWell (SWIFT_EXTENSION(Alderis)) +/// :nodoc: +- (BOOL)dropInteraction:(UIDropInteraction * _Nonnull)interaction canHandleSession:(id _Nonnull)session SWIFT_WARN_UNUSED_RESULT; +/// :nodoc: +- (UIDropProposal * _Nonnull)dropInteraction:(UIDropInteraction * _Nonnull)interaction sessionDidUpdate:(id _Nonnull)session SWIFT_WARN_UNUSED_RESULT; +/// :nodoc: +- (void)dropInteraction:(UIDropInteraction * _Nonnull)interaction performDrop:(id _Nonnull)session; +@end + + +SWIFT_CLASS("_TtC7Alderis12DialogButton") +@interface DialogButton : UIButton +- (nonnull instancetype)init OBJC_DESIGNATED_INITIALIZER; +- (nullable instancetype)initWithCoder:(NSCoder * _Nonnull)coder OBJC_DESIGNATED_INITIALIZER; +- (nonnull instancetype)initWithFrame:(CGRect)frame SWIFT_UNAVAILABLE; +@end + + +SWIFT_CLASS("_TtC7Alderis13SeparatorView") +@interface SeparatorView : UIView +- (nullable instancetype)initWithCoder:(NSCoder * _Nonnull)coder OBJC_DESIGNATED_INITIALIZER; +- (void)updateConstraints; +- (void)didMoveToWindow; +- (nonnull instancetype)initWithFrame:(CGRect)frame SWIFT_UNAVAILABLE; +@end + + +@interface UIColor (SWIFT_EXTENSION(Alderis)) +/// Maps init(propertyListValue:) to Objective-C due to Swift limitations. This is an +/// implementation detail. Ignore this and use UIColor(propertyListValue:) or +/// -[UIColor initWithHbcp_propertyListValue:] as per usual. +///
    +///
  • +/// see: init(propertyListValue:) +///
  • +///
+/// \param value The object to retrieve data from. See the discussion for the supported +/// object types. +/// +/// +/// returns: +/// An initialized color object, or nil if the value does not conform to the expected +/// type. The color information represented by this object is in the device RGB colorspace. +/// device RGB colorspace. +- (nullable instancetype)initWithHbcp_propertyListValue:(id _Nullable)propertyListValue; +/// Returns a string that represents the color. +/// The output is a string in the format #AABBCC:0.5, where the initial #AABBCC portion is a +/// 6-character CSS-style hex string, and the final :0.5 portion represents the alpha value. If +/// the color’s alpha value is 1, the alpha portion is excluded. +/// If the color is dynamic, for instance if it is a UIKit system color, or initialised via +/// UIColor(dynamicProvider:), the color that matches the current trait collection is used. +///
    +///
  • +/// see: init(propertyListValue:) +///
  • +///
+/// +/// returns: +/// A string representing the color, in the format discussed above. +@property (nonatomic, readonly, copy) NSString * _Nonnull hbcp_propertyListValue; +@end + +#if __has_attribute(external_source_symbol) +# pragma clang attribute pop +#endif +#pragma clang diagnostic pop + +#endif diff --git a/Natives/resources/Frameworks/Alderis.framework/Headers/Alderis.h b/Natives/resources/Frameworks/Alderis.framework/Headers/Alderis.h new file mode 100644 index 00000000..4836fe1a --- /dev/null +++ b/Natives/resources/Frameworks/Alderis.framework/Headers/Alderis.h @@ -0,0 +1,11 @@ +// +// Alderis.h +// Alderis +// +// Created by Adam Demasi on 16/3/20. +// Copyright © 2020 HASHBANG Productions. All rights reserved. +// + +#import + +#import "AlderisSDKCompatibility.h" diff --git a/Natives/resources/Frameworks/Alderis.framework/Headers/AlderisSDKCompatibility.h b/Natives/resources/Frameworks/Alderis.framework/Headers/AlderisSDKCompatibility.h new file mode 100644 index 00000000..3f2bfd71 --- /dev/null +++ b/Natives/resources/Frameworks/Alderis.framework/Headers/AlderisSDKCompatibility.h @@ -0,0 +1,21 @@ +// +// AlderisSDKCompatibility.h +// Alderis +// +// Created by Adam Demasi on 3/10/20. +// Copyright © 2020 HASHBANG Productions. All rights reserved. +// + +#import + +#ifndef __IPHONE_14_0 +// Allows building with the iOS 13 SDK while retaining iOS 14 compatibility. + +@interface UIControl () + +- (void)addAction:(UIAction *)action forControlEvents:(UIControlEvents)controlEvents NS_SWIFT_NAME(addAction(_:for:)) API_AVAILABLE(ios(14.0)); +- (void)removeAction:(UIAction *)action forControlEvents:(UIControlEvents)controlEvents NS_SWIFT_NAME(removeAction(_:for:)) API_AVAILABLE(ios(14.0)); +- (void)removeActionForIdentifier:(UIActionIdentifier)actionIdentifier forControlEvents:(UIControlEvents)controlEvents NS_SWIFT_NAME(removeAction(identifiedBy:for:)) API_AVAILABLE(ios(14.0)); + +@end +#endif diff --git a/Natives/resources/Frameworks/Alderis.framework/Info.plist b/Natives/resources/Frameworks/Alderis.framework/Info.plist new file mode 100644 index 00000000..bf60b1b3 Binary files /dev/null and b/Natives/resources/Frameworks/Alderis.framework/Info.plist differ diff --git a/Natives/resources/Frameworks/libvgpu.dylib b/Natives/resources/Frameworks/libvgpu.dylib new file mode 100644 index 00000000..b923fe36 Binary files /dev/null and b/Natives/resources/Frameworks/libvgpu.dylib differ diff --git a/Natives/resources/log4j-rce-patch-1.12.xml b/Natives/resources/log4j-rce-patch-1.12.xml new file mode 100644 index 00000000..1cf0fd92 --- /dev/null +++ b/Natives/resources/log4j-rce-patch-1.12.xml @@ -0,0 +1,28 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Natives/resources/log4j-rce-patch-1.7.xml b/Natives/resources/log4j-rce-patch-1.7.xml new file mode 100755 index 00000000..784eca3d --- /dev/null +++ b/Natives/resources/log4j-rce-patch-1.7.xml @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Natives/utils.h b/Natives/utils.h index 31125583..5d4db85d 100644 --- a/Natives/utils.h +++ b/Natives/utils.h @@ -7,6 +7,7 @@ #define ACTION_DOWN 0 #define ACTION_UP 1 #define ACTION_MOVE 2 +#define ACTION_MOVE_MOTION 3 #define BUTTON1_DOWN_MASK 1 << 10 // left btn #define BUTTON2_DOWN_MASK 1 << 11 // mid btn @@ -56,7 +57,11 @@ int savedWidth, savedHeight; BOOL virtualMouseEnabled; +static inline CGFloat clamp(CGFloat x, CGFloat lower, CGFloat upper) { + return fmin(upper, fmax(x, lower)); +} CGFloat MathUtils_dist(CGFloat x1, CGFloat y1, CGFloat x2, CGFloat y2); +CGFloat MathUtils_map(CGFloat x, CGFloat in_min, CGFloat in_max, CGFloat out_min, CGFloat out_max); CGFloat dpToPx(CGFloat dp); CGFloat pxToDp(CGFloat px); void _CGDataProviderReleaseBytePointerCallback(void *info,const void *pointer); @@ -67,22 +72,21 @@ jobjectArray convert_from_char_array(JNIEnv *env, char **charArray, int num_rows void free_char_array(JNIEnv *env, jobjectArray jstringArray, char **charArray); jstring convertStringJVM(JNIEnv* srcEnv, JNIEnv* dstEnv, jstring srcStr); -void sendData(int type, int i1, int i2, int i3, int i4); +void sendData(int type, CGFloat i1, CGFloat i2, int i3, int i4); void closeGLFWWindow(); void callback_LauncherViewController_installMinecraft(); void callback_SurfaceViewController_launchMinecraft(int width, int height); -void callback_SurfaceViewController_onTouch(int event, int x, int y); -int callback_SurfaceViewController_touchHotbar(int x, int y); - -JNIEXPORT jboolean JNICALL Java_org_lwjgl_glfw_CallbackBridge_nativeSendChar(JNIEnv* env, jclass clazz, jchar codepoint /* jint codepoint */); -JNIEXPORT jboolean JNICALL Java_org_lwjgl_glfw_CallbackBridge_nativeSendCharMods(JNIEnv* env, jclass clazz, jchar codepoint, jint mods); -JNIEXPORT void JNICALL Java_org_lwjgl_glfw_CallbackBridge_nativeSendCursorPos(JNIEnv* env, jclass clazz, jint x, jint y); -JNIEXPORT void JNICALL Java_org_lwjgl_glfw_CallbackBridge_nativeSendKey(JNIEnv* env, jclass clazz, jint key, jint scancode, jint action, jint mods); -JNIEXPORT void JNICALL Java_org_lwjgl_glfw_CallbackBridge_nativeSendKeycode(JNIEnv* env, jclass clazz, jint keycode, jchar keychar, jint scancode, jint action, jint mods); -JNIEXPORT void JNICALL Java_org_lwjgl_glfw_CallbackBridge_nativeSendMouseButton(JNIEnv* env, jclass clazz, jint button, jint action, jint mods); -JNIEXPORT void JNICALL Java_org_lwjgl_glfw_CallbackBridge_nativeSendScreenSize(JNIEnv* env, jclass clazz, jint width, jint height); -JNIEXPORT void JNICALL Java_org_lwjgl_glfw_CallbackBridge_nativeSendScroll(JNIEnv* env, jclass clazz, jdouble xoffset, jdouble yoffset); -JNIEXPORT void JNICALL Java_org_lwjgl_glfw_CallbackBridge_nativeSendWindowPos(JNIEnv* env, jclass clazz, jint x, jint y); - +void callback_SurfaceViewController_onTouch(int event, CGFloat x, CGFloat y); +int callback_SurfaceViewController_touchHotbar(CGFloat x, CGFloat y); +BOOL CallbackBridge_nativeSendChar(jchar codepoint /* jint codepoint */); +BOOL CallbackBridge_nativeSendCharMods(jchar codepoint, int mods); +void CallbackBridge_nativeSendCursorPos(CGFloat x, CGFloat y); +void CallbackBridge_nativeSendKey(int key, int scancode, int action, int mods); +void CallbackBridge_nativeSendKeycode(int keycode, char keychar, int scancode, int action, int mods); +void CallbackBridge_nativeSendMouseButton(int button, int action, int mods); +void CallbackBridge_nativeSendScreenSize(int width, int height); +void CallbackBridge_nativeSendScroll(CGFloat xoffset, CGFloat yoffset); +void CallbackBridge_nativeSendWindowPos(jint x, jint y); +void CallbackBridge_sendKeycode(int keycode, jchar keychar, int scancode, int modifiers, BOOL isDown); diff --git a/Natives/utils.m b/Natives/utils.m index 24e45c0b..2500982a 100644 --- a/Natives/utils.m +++ b/Natives/utils.m @@ -12,7 +12,13 @@ CGFloat MathUtils_dist(CGFloat x1, CGFloat y1, CGFloat x2, CGFloat y2) { const CGFloat x = (x2 - x1); const CGFloat y = (y2 - y1); return (CGFloat) hypot(x, y); - } +} + +//Ported from https://www.arduino.cc/reference/en/language/functions/math/map/ +CGFloat MathUtils_map(CGFloat x, CGFloat in_min, CGFloat in_max, CGFloat out_min, CGFloat out_max) { + return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min; +} + void _CGDataProviderReleaseBytePointerCallback(void *info,const void *pointer) { } diff --git a/README.md b/README.md index 8162a54e..c7cb31cd 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,7 @@ - The official Twitter for PojavLauncher is [@PLaunchTeam](https://twitter.com/PLaunchTeam). Any others (most notably @PojavLauncher) are fake, please report them to Twitter's moderation team. ## Introduction -PojavLauncher is a Minecraft: Java Edition launcher for Android and iOS based on [Boardwalk](https://github.com/zhuowei/Boardwalk). This launcher can launch most of available Minecraft versions (from 1.6.1 to 21w08b (1.17) snapshot, including Combat Test versions). 1.17 support is available with our current workaround described [here](https://pojavlauncherteam.github.io/updates/117). Modding via Forge (1.16.x only) and Fabric are also supported. Older versions of Forge and Fabric can be used with OpenJDK 8. This repository contains source code for iOS/iPadOS platform. For Android platform, check out [PojavLauncher repository](https://github.com/PojavLauncherTeam/PojavLauncher). +PojavLauncher is a Minecraft: Java Edition launcher for Android and iOS based on [Boardwalk](https://github.com/zhuowei/Boardwalk). This launcher can launch most of available Minecraft versions (from 1.6.1 to 1.18, including Combat Test versions). 1.17+ support is available as of v2.0, or with the workarounds described on our [website](https://pojavlauncherteam.github.io). Modding via Forge (1.16.x only) and Fabric are also supported. Older versions of Forge and Fabric can be used with OpenJDK 8. This repository contains source code for iOS/iPadOS platform. For Android platform, check out [PojavLauncher repository](https://github.com/PojavLauncherTeam/PojavLauncher). This launcher is available on the Procursus repo, thanks to [@Diatrus](https://twitter.com/Diatrus), and Doregon's Repository, thanks to [@Doregon](https://twitter.com/AdamTunnic) @@ -16,6 +16,7 @@ This launcher is available on the Procursus repo, thanks to [@Diatrus](https://t The [PojavLauncher Website](https://pojavlauncherteam.github.io) has extensive documentation on how to install, set up, and play! For those who wish to install quickly, here's the basics (on iOS 12 or later): ### Procursus-bootstraps +*Note: This is currently unavailable. Will be fixed soon!* If you have Chimera, Taurine, Odyssey, or another jailbreak that comes with **libhooker**, this one's for you. 1. Search for `pojavlauncher` with your favorite package manager. @@ -27,8 +28,9 @@ If you have unc0ver, checkra1n, or another jailbreak that comes with **Cydia Sub 1. Add `https://apt.doregon.gq` to your sources list. 2. Search for `pojavlauncher` with your favorite package manager. 3. Install the package you wish to have, according to your preference: - * `pojavlauncher` is the stable build. This one gets updated with new releases or tags on this repository, or when Procursus updated their copy. - * `pojavlauncher-dev` is the latest commit on the `main` branch of this repository. It may have application breaking bugs, but also has more features. + * `pojavlauncher.release` is the stable build. This one gets updated with new releases or tags on this repository, or when Procursus updated their copy. + * `pojavlauncher.development` is the latest commit on the `main` branch of this repository. It may have application breaking bugs, but also has more features. + * The rootless variants serve the same purpose, but only work with Procursus jailbreaks and iOS 15 (see our website for more information). ## Known issues * Minecraft 1.12.2 and below are very buggy: you can't type text, random crashes, etc... @@ -43,10 +45,10 @@ If you have unc0ver, checkra1n, or another jailbreak that comes with **Cydia Sub PojavLauncher is amazing, and surprisingly stable, and it wouldn't be this way without the following people that helped and contribute to the project! @khanhduytran0 - Lead iOS port developer +@Doregon - PojavLauncher hosting on Doregon's Repository, iOS port developer @artdeell - Lead developer @LegacyGamerHD - Lead developer @zhouwei - Original Boardwalk code -@Doregon - PojavLauncher hosting on Doregon's Repository, iOS port developer @Mathius-Boulay - Developer @Diatrus - PojavLauncher hosting on Procursus @Syjalo @@ -70,9 +72,10 @@ PojavLauncher is amazing, and surprisingly stable, and it wouldn't be this way w - [OpenJDK 16](https://www.ios-repo-updates.com/repository/procursus/package/openjdk-16-jre) ported to iOS by @Diatrus: [GNU GPLv2 License](https://openjdk.java.net/legal/gplv2+ce.html). - [LWJGL3](https://github.com/PojavLauncherTeam/lwjgl3): [BSD-3 License](https://github.com/LWJGL/lwjgl3/blob/master/LICENSE.md). - [LWJGLX](https://github.com/PojavLauncherTeam/lwjglx) (LWJGL2 API compatibility layer for LWJGL3): unknown license. +- [Alderis](https://github.com/hbang/Alderis) (color picker for iOS < 14): [Apache 2.0 License](https://github.com/hbang/Alderis/blob/master/LICENSE.md). - [DBNumberedSlider](https://github.com/immago/DBNumberedSlider): [Apache 2.0 License](https://github.com/immago/DBNumberedSlider/blob/master/LICENSE) - [fishhook](https://github.com/facebook/fishhook) (jailed environment usage only): [BSD-3 License](https://github.com/facebook/fishhook/blob/main/LICENSE). - [Java Native Access](https://github.com/java-native-access/jna): [Apache 2.0 License](https://github.com/java-native-access/jna/blob/master/LICENSE). - + diff --git a/depends/Info.plist b/depends/Info.plist new file mode 100644 index 00000000..4b433dc0 --- /dev/null +++ b/depends/Info.plist @@ -0,0 +1,51 @@ + + + + + BuildMachineOSBuild + 18G3020 + CFBundleDevelopmentRegion + en + CFBundleExecutable + DYLIB_NAME + CFBundleIdentifier + com.oracle.DYLIB_NAME + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + DYLIB_NAME + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.0 + CFBundleSupportedPlatforms + + iPhoneOS + + CFBundleVersion + 1 + DTCompiler + com.apple.compilers.llvm.clang.1_0 + DTPlatformBuild + 17B102 + DTPlatformName + iphoneos + DTPlatformVersion + 13.2 + DTSDKBuild + 17B102 + DTSDKName + iphoneos13.2 + DTXcode + 1120 + DTXcodeBuild + 11B500 + MinimumOSVersion + 12.0 + UIDeviceFamily + + 1 + 2 + + +