[Scummvm-git-logs] scummvm master -> 92b22e4ba644c0c54fd95337931dfa3a4abcf9b3

criezy noreply at scummvm.org
Sun Jan 29 21:16:10 UTC 2023


This automated email contains information about 16 new commits which have been
pushed to the 'scummvm' repo located at https://github.com/scummvm/scummvm .

Summary:
505c2499c9 TVOS: Add Apple TV OS as a separate dist
29efa1922e CREATE_PROJECT: Add Apple TV OS XCode target
5f54aedbb9 IOS7: Put iOS specific code within platform specific macros
c24ee0d61e IOS7: Add missing break to kInputJoystickButtonUp
5aeef796bc IOS7: Implement support for Apple TV remote
d731c9c290 IOS7: Implement keyboard support for Apple TV OS
14ee8b07d3 IOS7: Forward backward key presses when textField is empty
3dae4b033e IOS7: Replace UIAlertView with UIAlertAction
8a2a6aa197 IOS7: Show inputAccessoryView when hardware keyboad is connected
b2b2d2cf9f IOS7: Trigger joystick presses only once for buttons A and B
4c0cd6f2eb IOS7: Check keyboard visible if inputView being first responder
770ab0ca50 IOS7: Suspend application if menu key pressed and no game is running
fde0aa965d IOS7: Add general handling of the menu button on game controllers
235ebcbfb8 IOS7: Fix compiler warnings
dec343730e IOS7: Add AppleTV support to configure
92b22e4ba6 DOCS: Add draft documentation of Apple TV platform


Commit: 505c2499c9107062b6f6917fdd0557c05f9a06af
    https://github.com/scummvm/scummvm/commit/505c2499c9107062b6f6917fdd0557c05f9a06af
Author: Lars Sundström (l.sundstrom at gmail.com)
Date: 2023-01-29T21:13:51Z

Commit Message:
TVOS: Add Apple TV OS as a separate dist

The Apple TV OS requires a different type of storyboard than iOS. Also,
the Info.plist file differ since the tvOS platform doesn't handle
different orientations.

The Apple TV OS also need a different set of icons with different
resolutions more suitable for TV screens.

The application icons are required to be of layered type, which means
that a single PNG file is not accepted as an icon file. The icons must
have at least two layers, hence the ScummVM icon is defined by a back
image with just the background color and a front image with the ScummVM
logo.

The icons are then put together when archiving the application in Xcode
to an Assets.car file. However the linux builds are not building the
application using Xcode. Therefore a pre-compiled Assets.car file
containing the image assets (icons, splash screen etc) is added to the
tvos folder. This file is copied to the application bundle. If the icons
are changed in the future a new Assets.car file has to be compiled. This
can only be done on a computer with Xcode installed. To compile run the
following command in the tvos folder:
xcrun actool ./Images.xcassets --compile build --platform appletvos \
--minimum-deployment-target 9.0 --app-icon AppIcon \
--output-partial-info-plist build/partial.plist \
--launch-image LaunchImage

The partial.plist file generated will show what to add to the Info.plist
and if something must be changed in the ports.mk section for the
tvosbundle.

Changed paths:
  A dists/tvos/Assets.car
  A dists/tvos/Images.xcassets/AppIcon.brandassets/App Icon - App Store.imagestack/Back.imagestacklayer/Content.imageset/Contents.json
  A dists/tvos/Images.xcassets/AppIcon.brandassets/App Icon - App Store.imagestack/Back.imagestacklayer/Content.imageset/ScummVMAppStoreBack at 1x.png
  A dists/tvos/Images.xcassets/AppIcon.brandassets/App Icon - App Store.imagestack/Back.imagestacklayer/Contents.json
  A dists/tvos/Images.xcassets/AppIcon.brandassets/App Icon - App Store.imagestack/Contents.json
  A dists/tvos/Images.xcassets/AppIcon.brandassets/App Icon - App Store.imagestack/Front.imagestacklayer/Content.imageset/Contents.json
  A dists/tvos/Images.xcassets/AppIcon.brandassets/App Icon - App Store.imagestack/Front.imagestacklayer/Content.imageset/ScummVMAppStoreFront at 1x.png
  A dists/tvos/Images.xcassets/AppIcon.brandassets/App Icon - App Store.imagestack/Front.imagestacklayer/Contents.json
  A dists/tvos/Images.xcassets/AppIcon.brandassets/App Icon - App Store.imagestack/Middle.imagestacklayer/Content.imageset/Contents.json
  A dists/tvos/Images.xcassets/AppIcon.brandassets/App Icon - App Store.imagestack/Middle.imagestacklayer/Contents.json
  A dists/tvos/Images.xcassets/AppIcon.brandassets/App Icon.imagestack/Back.imagestacklayer/Content.imageset/Contents.json
  A dists/tvos/Images.xcassets/AppIcon.brandassets/App Icon.imagestack/Back.imagestacklayer/Content.imageset/ScummVMBack at 1x.png
  A dists/tvos/Images.xcassets/AppIcon.brandassets/App Icon.imagestack/Back.imagestacklayer/Contents.json
  A dists/tvos/Images.xcassets/AppIcon.brandassets/App Icon.imagestack/Contents.json
  A dists/tvos/Images.xcassets/AppIcon.brandassets/App Icon.imagestack/Front.imagestacklayer/Content.imageset/Contents.json
  A dists/tvos/Images.xcassets/AppIcon.brandassets/App Icon.imagestack/Front.imagestacklayer/Content.imageset/ScummVMFront at 1x.png
  A dists/tvos/Images.xcassets/AppIcon.brandassets/App Icon.imagestack/Front.imagestacklayer/Contents.json
  A dists/tvos/Images.xcassets/AppIcon.brandassets/App Icon.imagestack/Middle.imagestacklayer/Content.imageset/Contents.json
  A dists/tvos/Images.xcassets/AppIcon.brandassets/App Icon.imagestack/Middle.imagestacklayer/Contents.json
  A dists/tvos/Images.xcassets/AppIcon.brandassets/Contents.json
  A dists/tvos/Images.xcassets/AppIcon.brandassets/Top Shelf Image Wide.imageset/Contents.json
  A dists/tvos/Images.xcassets/AppIcon.brandassets/Top Shelf Image Wide.imageset/ScummVMTopShelfWide at 1x.png
  A dists/tvos/Images.xcassets/AppIcon.brandassets/Top Shelf Image.imageset/Contents.json
  A dists/tvos/Images.xcassets/AppIcon.brandassets/Top Shelf Image.imageset/ScummVMTopShelf at 1x.png
  A dists/tvos/Images.xcassets/Contents.json
  A dists/tvos/Images.xcassets/LaunchImage.launchimage/Contents.json
  A dists/tvos/Images.xcassets/LaunchImage.launchimage/ScummVMLaunchImage at 1x.png
  A dists/tvos/Info.plist
  A dists/tvos/Info.plist.in
  A dists/tvos/LaunchScreen_tvos.storyboard
    devtools/update-version.pl


diff --git a/devtools/update-version.pl b/devtools/update-version.pl
index 29f89ce766f..0a4c9e9ff1c 100755
--- a/devtools/update-version.pl
+++ b/devtools/update-version.pl
@@ -39,6 +39,7 @@ my @subs_files = qw(
 	dists/macosx/dockplugin/Info.plist
 	dists/iphone/Info.plist
 	dists/ios7/Info.plist
+	dists/tvos/Info.plist
 	dists/irix/scummvm.spec
 	dists/wii/meta.xml
 	dists/openpandora/PXML.xml
diff --git a/dists/tvos/Assets.car b/dists/tvos/Assets.car
new file mode 100644
index 00000000000..3fd882b153e
Binary files /dev/null and b/dists/tvos/Assets.car differ
diff --git a/dists/tvos/Images.xcassets/AppIcon.brandassets/App Icon - App Store.imagestack/Back.imagestacklayer/Content.imageset/Contents.json b/dists/tvos/Images.xcassets/AppIcon.brandassets/App Icon - App Store.imagestack/Back.imagestacklayer/Content.imageset/Contents.json
new file mode 100644
index 00000000000..2f76df8af96
--- /dev/null
+++ b/dists/tvos/Images.xcassets/AppIcon.brandassets/App Icon - App Store.imagestack/Back.imagestacklayer/Content.imageset/Contents.json	
@@ -0,0 +1,17 @@
+{
+  "images" : [
+    {
+      "filename" : "ScummVMAppStoreBack at 1x.png",
+      "idiom" : "tv",
+      "scale" : "1x"
+    },
+    {
+      "idiom" : "tv",
+      "scale" : "2x"
+    }
+  ],
+  "info" : {
+    "author" : "xcode",
+    "version" : 1
+  }
+}
diff --git a/dists/tvos/Images.xcassets/AppIcon.brandassets/App Icon - App Store.imagestack/Back.imagestacklayer/Content.imageset/ScummVMAppStoreBack at 1x.png b/dists/tvos/Images.xcassets/AppIcon.brandassets/App Icon - App Store.imagestack/Back.imagestacklayer/Content.imageset/ScummVMAppStoreBack at 1x.png
new file mode 100644
index 00000000000..405e1d2bfc3
Binary files /dev/null and b/dists/tvos/Images.xcassets/AppIcon.brandassets/App Icon - App Store.imagestack/Back.imagestacklayer/Content.imageset/ScummVMAppStoreBack at 1x.png differ
diff --git a/dists/tvos/Images.xcassets/AppIcon.brandassets/App Icon - App Store.imagestack/Back.imagestacklayer/Contents.json b/dists/tvos/Images.xcassets/AppIcon.brandassets/App Icon - App Store.imagestack/Back.imagestacklayer/Contents.json
new file mode 100644
index 00000000000..73c00596a7f
--- /dev/null
+++ b/dists/tvos/Images.xcassets/AppIcon.brandassets/App Icon - App Store.imagestack/Back.imagestacklayer/Contents.json	
@@ -0,0 +1,6 @@
+{
+  "info" : {
+    "author" : "xcode",
+    "version" : 1
+  }
+}
diff --git a/dists/tvos/Images.xcassets/AppIcon.brandassets/App Icon - App Store.imagestack/Contents.json b/dists/tvos/Images.xcassets/AppIcon.brandassets/App Icon - App Store.imagestack/Contents.json
new file mode 100644
index 00000000000..de59d885ae8
--- /dev/null
+++ b/dists/tvos/Images.xcassets/AppIcon.brandassets/App Icon - App Store.imagestack/Contents.json	
@@ -0,0 +1,17 @@
+{
+  "info" : {
+    "author" : "xcode",
+    "version" : 1
+  },
+  "layers" : [
+    {
+      "filename" : "Front.imagestacklayer"
+    },
+    {
+      "filename" : "Middle.imagestacklayer"
+    },
+    {
+      "filename" : "Back.imagestacklayer"
+    }
+  ]
+}
diff --git a/dists/tvos/Images.xcassets/AppIcon.brandassets/App Icon - App Store.imagestack/Front.imagestacklayer/Content.imageset/Contents.json b/dists/tvos/Images.xcassets/AppIcon.brandassets/App Icon - App Store.imagestack/Front.imagestacklayer/Content.imageset/Contents.json
new file mode 100644
index 00000000000..a67e7022813
--- /dev/null
+++ b/dists/tvos/Images.xcassets/AppIcon.brandassets/App Icon - App Store.imagestack/Front.imagestacklayer/Content.imageset/Contents.json	
@@ -0,0 +1,17 @@
+{
+  "images" : [
+    {
+      "filename" : "ScummVMAppStoreFront at 1x.png",
+      "idiom" : "tv",
+      "scale" : "1x"
+    },
+    {
+      "idiom" : "tv",
+      "scale" : "2x"
+    }
+  ],
+  "info" : {
+    "author" : "xcode",
+    "version" : 1
+  }
+}
diff --git a/dists/tvos/Images.xcassets/AppIcon.brandassets/App Icon - App Store.imagestack/Front.imagestacklayer/Content.imageset/ScummVMAppStoreFront at 1x.png b/dists/tvos/Images.xcassets/AppIcon.brandassets/App Icon - App Store.imagestack/Front.imagestacklayer/Content.imageset/ScummVMAppStoreFront at 1x.png
new file mode 100644
index 00000000000..4ba46552303
Binary files /dev/null and b/dists/tvos/Images.xcassets/AppIcon.brandassets/App Icon - App Store.imagestack/Front.imagestacklayer/Content.imageset/ScummVMAppStoreFront at 1x.png differ
diff --git a/dists/tvos/Images.xcassets/AppIcon.brandassets/App Icon - App Store.imagestack/Front.imagestacklayer/Contents.json b/dists/tvos/Images.xcassets/AppIcon.brandassets/App Icon - App Store.imagestack/Front.imagestacklayer/Contents.json
new file mode 100644
index 00000000000..73c00596a7f
--- /dev/null
+++ b/dists/tvos/Images.xcassets/AppIcon.brandassets/App Icon - App Store.imagestack/Front.imagestacklayer/Contents.json	
@@ -0,0 +1,6 @@
+{
+  "info" : {
+    "author" : "xcode",
+    "version" : 1
+  }
+}
diff --git a/dists/tvos/Images.xcassets/AppIcon.brandassets/App Icon - App Store.imagestack/Middle.imagestacklayer/Content.imageset/Contents.json b/dists/tvos/Images.xcassets/AppIcon.brandassets/App Icon - App Store.imagestack/Middle.imagestacklayer/Content.imageset/Contents.json
new file mode 100644
index 00000000000..795cce17243
--- /dev/null
+++ b/dists/tvos/Images.xcassets/AppIcon.brandassets/App Icon - App Store.imagestack/Middle.imagestacklayer/Content.imageset/Contents.json	
@@ -0,0 +1,16 @@
+{
+  "images" : [
+    {
+      "idiom" : "tv",
+      "scale" : "1x"
+    },
+    {
+      "idiom" : "tv",
+      "scale" : "2x"
+    }
+  ],
+  "info" : {
+    "author" : "xcode",
+    "version" : 1
+  }
+}
diff --git a/dists/tvos/Images.xcassets/AppIcon.brandassets/App Icon - App Store.imagestack/Middle.imagestacklayer/Contents.json b/dists/tvos/Images.xcassets/AppIcon.brandassets/App Icon - App Store.imagestack/Middle.imagestacklayer/Contents.json
new file mode 100644
index 00000000000..73c00596a7f
--- /dev/null
+++ b/dists/tvos/Images.xcassets/AppIcon.brandassets/App Icon - App Store.imagestack/Middle.imagestacklayer/Contents.json	
@@ -0,0 +1,6 @@
+{
+  "info" : {
+    "author" : "xcode",
+    "version" : 1
+  }
+}
diff --git a/dists/tvos/Images.xcassets/AppIcon.brandassets/App Icon.imagestack/Back.imagestacklayer/Content.imageset/Contents.json b/dists/tvos/Images.xcassets/AppIcon.brandassets/App Icon.imagestack/Back.imagestacklayer/Content.imageset/Contents.json
new file mode 100644
index 00000000000..177e692a508
--- /dev/null
+++ b/dists/tvos/Images.xcassets/AppIcon.brandassets/App Icon.imagestack/Back.imagestacklayer/Content.imageset/Contents.json	
@@ -0,0 +1,17 @@
+{
+  "images" : [
+    {
+      "filename" : "ScummVMBack at 1x.png",
+      "idiom" : "tv",
+      "scale" : "1x"
+    },
+    {
+      "idiom" : "tv",
+      "scale" : "2x"
+    }
+  ],
+  "info" : {
+    "author" : "xcode",
+    "version" : 1
+  }
+}
diff --git a/dists/tvos/Images.xcassets/AppIcon.brandassets/App Icon.imagestack/Back.imagestacklayer/Content.imageset/ScummVMBack at 1x.png b/dists/tvos/Images.xcassets/AppIcon.brandassets/App Icon.imagestack/Back.imagestacklayer/Content.imageset/ScummVMBack at 1x.png
new file mode 100644
index 00000000000..c6b9f064607
Binary files /dev/null and b/dists/tvos/Images.xcassets/AppIcon.brandassets/App Icon.imagestack/Back.imagestacklayer/Content.imageset/ScummVMBack at 1x.png differ
diff --git a/dists/tvos/Images.xcassets/AppIcon.brandassets/App Icon.imagestack/Back.imagestacklayer/Contents.json b/dists/tvos/Images.xcassets/AppIcon.brandassets/App Icon.imagestack/Back.imagestacklayer/Contents.json
new file mode 100644
index 00000000000..73c00596a7f
--- /dev/null
+++ b/dists/tvos/Images.xcassets/AppIcon.brandassets/App Icon.imagestack/Back.imagestacklayer/Contents.json	
@@ -0,0 +1,6 @@
+{
+  "info" : {
+    "author" : "xcode",
+    "version" : 1
+  }
+}
diff --git a/dists/tvos/Images.xcassets/AppIcon.brandassets/App Icon.imagestack/Contents.json b/dists/tvos/Images.xcassets/AppIcon.brandassets/App Icon.imagestack/Contents.json
new file mode 100644
index 00000000000..de59d885ae8
--- /dev/null
+++ b/dists/tvos/Images.xcassets/AppIcon.brandassets/App Icon.imagestack/Contents.json	
@@ -0,0 +1,17 @@
+{
+  "info" : {
+    "author" : "xcode",
+    "version" : 1
+  },
+  "layers" : [
+    {
+      "filename" : "Front.imagestacklayer"
+    },
+    {
+      "filename" : "Middle.imagestacklayer"
+    },
+    {
+      "filename" : "Back.imagestacklayer"
+    }
+  ]
+}
diff --git a/dists/tvos/Images.xcassets/AppIcon.brandassets/App Icon.imagestack/Front.imagestacklayer/Content.imageset/Contents.json b/dists/tvos/Images.xcassets/AppIcon.brandassets/App Icon.imagestack/Front.imagestacklayer/Content.imageset/Contents.json
new file mode 100644
index 00000000000..7e049ff60cd
--- /dev/null
+++ b/dists/tvos/Images.xcassets/AppIcon.brandassets/App Icon.imagestack/Front.imagestacklayer/Content.imageset/Contents.json	
@@ -0,0 +1,17 @@
+{
+  "images" : [
+    {
+      "filename" : "ScummVMFront at 1x.png",
+      "idiom" : "tv",
+      "scale" : "1x"
+    },
+    {
+      "idiom" : "tv",
+      "scale" : "2x"
+    }
+  ],
+  "info" : {
+    "author" : "xcode",
+    "version" : 1
+  }
+}
diff --git a/dists/tvos/Images.xcassets/AppIcon.brandassets/App Icon.imagestack/Front.imagestacklayer/Content.imageset/ScummVMFront at 1x.png b/dists/tvos/Images.xcassets/AppIcon.brandassets/App Icon.imagestack/Front.imagestacklayer/Content.imageset/ScummVMFront at 1x.png
new file mode 100644
index 00000000000..25cd718935a
Binary files /dev/null and b/dists/tvos/Images.xcassets/AppIcon.brandassets/App Icon.imagestack/Front.imagestacklayer/Content.imageset/ScummVMFront at 1x.png differ
diff --git a/dists/tvos/Images.xcassets/AppIcon.brandassets/App Icon.imagestack/Front.imagestacklayer/Contents.json b/dists/tvos/Images.xcassets/AppIcon.brandassets/App Icon.imagestack/Front.imagestacklayer/Contents.json
new file mode 100644
index 00000000000..73c00596a7f
--- /dev/null
+++ b/dists/tvos/Images.xcassets/AppIcon.brandassets/App Icon.imagestack/Front.imagestacklayer/Contents.json	
@@ -0,0 +1,6 @@
+{
+  "info" : {
+    "author" : "xcode",
+    "version" : 1
+  }
+}
diff --git a/dists/tvos/Images.xcassets/AppIcon.brandassets/App Icon.imagestack/Middle.imagestacklayer/Content.imageset/Contents.json b/dists/tvos/Images.xcassets/AppIcon.brandassets/App Icon.imagestack/Middle.imagestacklayer/Content.imageset/Contents.json
new file mode 100644
index 00000000000..795cce17243
--- /dev/null
+++ b/dists/tvos/Images.xcassets/AppIcon.brandassets/App Icon.imagestack/Middle.imagestacklayer/Content.imageset/Contents.json	
@@ -0,0 +1,16 @@
+{
+  "images" : [
+    {
+      "idiom" : "tv",
+      "scale" : "1x"
+    },
+    {
+      "idiom" : "tv",
+      "scale" : "2x"
+    }
+  ],
+  "info" : {
+    "author" : "xcode",
+    "version" : 1
+  }
+}
diff --git a/dists/tvos/Images.xcassets/AppIcon.brandassets/App Icon.imagestack/Middle.imagestacklayer/Contents.json b/dists/tvos/Images.xcassets/AppIcon.brandassets/App Icon.imagestack/Middle.imagestacklayer/Contents.json
new file mode 100644
index 00000000000..73c00596a7f
--- /dev/null
+++ b/dists/tvos/Images.xcassets/AppIcon.brandassets/App Icon.imagestack/Middle.imagestacklayer/Contents.json	
@@ -0,0 +1,6 @@
+{
+  "info" : {
+    "author" : "xcode",
+    "version" : 1
+  }
+}
diff --git a/dists/tvos/Images.xcassets/AppIcon.brandassets/Contents.json b/dists/tvos/Images.xcassets/AppIcon.brandassets/Contents.json
new file mode 100644
index 00000000000..f47ba43daac
--- /dev/null
+++ b/dists/tvos/Images.xcassets/AppIcon.brandassets/Contents.json
@@ -0,0 +1,32 @@
+{
+  "assets" : [
+    {
+      "filename" : "App Icon - App Store.imagestack",
+      "idiom" : "tv",
+      "role" : "primary-app-icon",
+      "size" : "1280x768"
+    },
+    {
+      "filename" : "App Icon.imagestack",
+      "idiom" : "tv",
+      "role" : "primary-app-icon",
+      "size" : "400x240"
+    },
+    {
+      "filename" : "Top Shelf Image Wide.imageset",
+      "idiom" : "tv",
+      "role" : "top-shelf-image-wide",
+      "size" : "2320x720"
+    },
+    {
+      "filename" : "Top Shelf Image.imageset",
+      "idiom" : "tv",
+      "role" : "top-shelf-image",
+      "size" : "1920x720"
+    }
+  ],
+  "info" : {
+    "author" : "xcode",
+    "version" : 1
+  }
+}
diff --git a/dists/tvos/Images.xcassets/AppIcon.brandassets/Top Shelf Image Wide.imageset/Contents.json b/dists/tvos/Images.xcassets/AppIcon.brandassets/Top Shelf Image Wide.imageset/Contents.json
new file mode 100644
index 00000000000..0c885bb8003
--- /dev/null
+++ b/dists/tvos/Images.xcassets/AppIcon.brandassets/Top Shelf Image Wide.imageset/Contents.json	
@@ -0,0 +1,17 @@
+{
+  "images" : [
+    {
+      "filename" : "ScummVMTopShelfWide at 1x.png",
+      "idiom" : "tv",
+      "scale" : "1x"
+    },
+    {
+      "idiom" : "tv",
+      "scale" : "2x"
+    }
+  ],
+  "info" : {
+    "author" : "xcode",
+    "version" : 1
+  }
+}
diff --git a/dists/tvos/Images.xcassets/AppIcon.brandassets/Top Shelf Image Wide.imageset/ScummVMTopShelfWide at 1x.png b/dists/tvos/Images.xcassets/AppIcon.brandassets/Top Shelf Image Wide.imageset/ScummVMTopShelfWide at 1x.png
new file mode 100644
index 00000000000..410928e124d
Binary files /dev/null and b/dists/tvos/Images.xcassets/AppIcon.brandassets/Top Shelf Image Wide.imageset/ScummVMTopShelfWide at 1x.png differ
diff --git a/dists/tvos/Images.xcassets/AppIcon.brandassets/Top Shelf Image.imageset/Contents.json b/dists/tvos/Images.xcassets/AppIcon.brandassets/Top Shelf Image.imageset/Contents.json
new file mode 100644
index 00000000000..dca2306b264
--- /dev/null
+++ b/dists/tvos/Images.xcassets/AppIcon.brandassets/Top Shelf Image.imageset/Contents.json	
@@ -0,0 +1,17 @@
+{
+  "images" : [
+    {
+      "filename" : "ScummVMTopShelf at 1x.png",
+      "idiom" : "tv",
+      "scale" : "1x"
+    },
+    {
+      "idiom" : "tv",
+      "scale" : "2x"
+    }
+  ],
+  "info" : {
+    "author" : "xcode",
+    "version" : 1
+  }
+}
diff --git a/dists/tvos/Images.xcassets/AppIcon.brandassets/Top Shelf Image.imageset/ScummVMTopShelf at 1x.png b/dists/tvos/Images.xcassets/AppIcon.brandassets/Top Shelf Image.imageset/ScummVMTopShelf at 1x.png
new file mode 100644
index 00000000000..8ba5899f5a9
Binary files /dev/null and b/dists/tvos/Images.xcassets/AppIcon.brandassets/Top Shelf Image.imageset/ScummVMTopShelf at 1x.png differ
diff --git a/dists/tvos/Images.xcassets/Contents.json b/dists/tvos/Images.xcassets/Contents.json
new file mode 100644
index 00000000000..73c00596a7f
--- /dev/null
+++ b/dists/tvos/Images.xcassets/Contents.json
@@ -0,0 +1,6 @@
+{
+  "info" : {
+    "author" : "xcode",
+    "version" : 1
+  }
+}
diff --git a/dists/tvos/Images.xcassets/LaunchImage.launchimage/Contents.json b/dists/tvos/Images.xcassets/LaunchImage.launchimage/Contents.json
new file mode 100644
index 00000000000..a813397ef82
--- /dev/null
+++ b/dists/tvos/Images.xcassets/LaunchImage.launchimage/Contents.json
@@ -0,0 +1,23 @@
+{
+  "images" : [
+    {
+      "extent" : "full-screen",
+      "idiom" : "tv",
+      "minimum-system-version" : "11.0",
+      "orientation" : "landscape",
+      "scale" : "2x"
+    },
+    {
+      "extent" : "full-screen",
+      "filename" : "ScummVMLaunchImage at 1x.png",
+      "idiom" : "tv",
+      "minimum-system-version" : "9.0",
+      "orientation" : "landscape",
+      "scale" : "1x"
+    }
+  ],
+  "info" : {
+    "author" : "xcode",
+    "version" : 1
+  }
+}
diff --git a/dists/tvos/Images.xcassets/LaunchImage.launchimage/ScummVMLaunchImage at 1x.png b/dists/tvos/Images.xcassets/LaunchImage.launchimage/ScummVMLaunchImage at 1x.png
new file mode 100644
index 00000000000..b45bd1b37d1
Binary files /dev/null and b/dists/tvos/Images.xcassets/LaunchImage.launchimage/ScummVMLaunchImage at 1x.png differ
diff --git a/dists/tvos/Info.plist b/dists/tvos/Info.plist
new file mode 100644
index 00000000000..bf93f76be75
--- /dev/null
+++ b/dists/tvos/Info.plist
@@ -0,0 +1,53 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+	<key>CFBundleDevelopmentRegion</key>
+	<string>en</string>
+	<key>CFBundleExecutable</key>
+	<string>$(EXECUTABLE_NAME)</string>
+	<key>CFBundleIcons</key>
+	<dict/>
+	<key>CFBundleIdentifier</key>
+	<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
+	<key>CFBundleInfoDictionaryVersion</key>
+	<string>6.0</string>
+	<key>CFBundleName</key>
+	<string>ScummVM</string>
+	<key>CFBundlePackageType</key>
+	<string>APPL</string>
+	<key>CFBundleShortVersionString</key>
+	<string>2.7.0git</string>
+	<key>CFBundleSignature</key>
+	<string>????</string>
+	<key>CFBundleVersion</key>
+	<string>2.7.0git</string>
+	<key>GCSupportedGameControllers</key>
+	<array>
+		<dict>
+			<key>ProfileName</key>
+			<string>ExtendedGamepad</string>
+		</dict>
+	</array>
+	<key>GCSupportsControllerUserInteraction</key>
+	<true/>
+	<key>LSSupportsOpeningDocumentsInPlace</key>
+	<true/>
+	<key>UIApplicationExitsOnSuspend</key>
+	<false/>
+	<key>UIApplicationSupportsIndirectInputEvents</key>
+	<true/>
+	<key>UIFileSharingEnabled</key>
+	<true/>
+	<key>UILaunchImages</key>
+	<array/>
+	<key>UILaunchStoryboardName</key>
+	<string></string>
+	<key>UIPrerenderedIcon</key>
+	<true/>
+	<key>UIRequiresFullScreen</key>
+	<true/>
+	<key>UIStatusBarHidden</key>
+	<true/>
+</dict>
+</plist>
diff --git a/dists/tvos/Info.plist.in b/dists/tvos/Info.plist.in
new file mode 100644
index 00000000000..5603246fcd8
--- /dev/null
+++ b/dists/tvos/Info.plist.in
@@ -0,0 +1,53 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+	<key>CFBundleDevelopmentRegion</key>
+	<string>en</string>
+	<key>CFBundleExecutable</key>
+	<string>$(EXECUTABLE_NAME)</string>
+	<key>CFBundleIcons</key>
+	<dict/>
+	<key>CFBundleIdentifier</key>
+	<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
+	<key>CFBundleInfoDictionaryVersion</key>
+	<string>6.0</string>
+	<key>CFBundleName</key>
+	<string>ScummVM</string>
+	<key>CFBundlePackageType</key>
+	<string>APPL</string>
+	<key>CFBundleShortVersionString</key>
+	<string>2.7.0git</string>
+	<key>CFBundleSignature</key>
+	<string>????</string>
+	<key>CFBundleVersion</key>
+	<string>2.7.0git</string>
+	<key>GCSupportedGameControllers</key>
+	<array>
+		<dict>
+			<key>ProfileName</key>
+			<string>ExtendedGamepad</string>
+		</dict>
+	</array>
+	<key>GCSupportsControllerUserInteraction</key>
+	<true/>
+	<key>LSSupportsOpeningDocumentsInPlace</key>
+	<true/>
+	<key>UIApplicationExitsOnSuspend</key>
+	<false/>
+	<key>UIApplicationSupportsIndirectInputEvents</key>
+	<true/>
+	<key>UIFileSharingEnabled</key>
+	<true/>
+	<key>UILaunchImages</key>
+	<array/>
+	<key>UILaunchStoryboardName</key>
+	<string>LaunchScreen_tvos</string>
+	<key>UIPrerenderedIcon</key>
+	<true/>
+	<key>UIRequiresFullScreen</key>
+	<true/>
+	<key>UIStatusBarHidden</key>
+	<true/>
+</dict>
+</plist>
diff --git a/dists/tvos/LaunchScreen_tvos.storyboard b/dists/tvos/LaunchScreen_tvos.storyboard
new file mode 100644
index 00000000000..de7eeef3ea4
--- /dev/null
+++ b/dists/tvos/LaunchScreen_tvos.storyboard
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<document type="com.apple.InterfaceBuilder.AppleTV.Storyboard" version="3.0" toolsVersion="21507" targetRuntime="AppleTV" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="BYZ-38-t0r">
+    <device id="appleTV" appearance="light"/>
+    <dependencies>
+        <deployment identifier="tvOS"/>
+        <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="21505"/>
+        <capability name="Safe area layout guides" minToolsVersion="9.0"/>
+        <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
+    </dependencies>
+    <scenes>
+        <!--View Controller-->
+        <scene sceneID="tne-QT-ifu">
+            <objects>
+                <viewController id="BYZ-38-t0r" sceneMemberID="viewController">
+                    <layoutGuides>
+                        <viewControllerLayoutGuide type="top" id="MKS-xh-tX1"/>
+                        <viewControllerLayoutGuide type="bottom" id="fWP-k2-16V"/>
+                    </layoutGuides>
+                    <view key="view" contentMode="scaleToFill" id="8bC-Xf-vdC">
+                        <rect key="frame" x="0.0" y="0.0" width="1920" height="1080"/>
+                        <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
+                        <viewLayoutGuide key="safeArea" id="wu6-TO-1qx"/>
+                        <color key="backgroundColor" red="0.93520456549999997" green="0.48712334977416927" blue="0.12821434333899484" alpha="1" colorSpace="custom" customColorSpace="displayP3"/>
+                    </view>
+                </viewController>
+                <placeholder placeholderIdentifier="IBFirstResponder" id="dkx-z0-nzr" sceneMemberID="firstResponder"/>
+            </objects>
+            <point key="canvasLocation" x="24" y="-62"/>
+        </scene>
+    </scenes>
+</document>


Commit: 29efa1922e6b0f56ebc6c0fef00d767d2e6699b2
    https://github.com/scummvm/scummvm/commit/29efa1922e6b0f56ebc6c0fef00d767d2e6699b2
Author: Lars Sundström (l.sundstrom at gmail.com)
Date: 2023-01-29T21:13:51Z

Commit Message:
CREATE_PROJECT: Add Apple TV OS XCode target

Add Apple TV OS as a new target to the xcode project creator utility.
Make sure that TV OS specific files are not part of the iOS and macOS
targets and the other way around.
The TV OS project will utilize the same source code files as the iOS
project but will instead use the tvos dist files.

Changed paths:
    devtools/create_project/xcode.cpp


diff --git a/devtools/create_project/xcode.cpp b/devtools/create_project/xcode.cpp
index f6c52fb8f25..048f2d4ecd6 100644
--- a/devtools/create_project/xcode.cpp
+++ b/devtools/create_project/xcode.cpp
@@ -42,6 +42,7 @@ namespace CreateProjectTool {
 
 #define IOS_TARGET 0
 #define OSX_TARGET 1
+#define TVOS_TARGET 2
 
 #define ADD_DEFINE(defines, name) \
 	defines.push_back(name);
@@ -107,6 +108,10 @@ bool targetIsIOS(const std::string &targetName) {
 	return targetName.length() > 4 && targetName.substr(targetName.length() - 4) == "-iOS";
 }
 
+bool targetIsTVOS(const std::string &targetName) {
+	return targetName.length() > 5 && targetName.substr(targetName.length() - 5) == "-tvOS";
+}
+
 bool shouldSkipFileForTarget(const std::string &fileID, const std::string &targetName, const std::string &fileName) {
 	// Rules:
 	// - if the parent directory is "backends/platform/ios7", the file belongs to the iOS target.
@@ -116,11 +121,20 @@ bool shouldSkipFileForTarget(const std::string &fileID, const std::string &targe
 	std::string name, ext;
 	splitFilename(fileName, name, ext);
 
-	if (targetIsIOS(targetName)) {
-		// iOS target: we skip all files with the "_osx" suffix
+	if (targetIsIOS(targetName) || targetIsTVOS(targetName)) {
+		// iOS & tvOS target: we skip all files with the "_osx" suffix
 		if (name.length() > 4 && name.substr(name.length() - 4) == "_osx") {
 			return true;
 		}
+		if (targetIsIOS(targetName)) {
+			// skip tvos dist files
+			if (fileID.find("dists/tvos/") != std::string::npos)
+				return true;
+		} else {
+			// skip ios dist files
+			if (fileID.find("dists/ios7/") != std::string::npos)
+				return true;
+		}
 		// We don't need SDL for the iOS target
 		static const std::string sdl_directory = "/sdl/";
 		static const std::string surfacesdl_directory = "/surfacesdl/";
@@ -141,6 +155,10 @@ bool shouldSkipFileForTarget(const std::string &fileID, const std::string &targe
 		if (name.length() > 4 && name.substr(name.length() - 4) == "_ios") {
 			return true;
 		}
+		// macOS target: we skip all files with the "_tvos" suffix
+		if (name.length() > 5 && name.substr(name.length() - 5) == "_tvos") {
+			return true;
+		}
 		// macOS target: we skip all files with the "ios7_" prefix
 		if (name.length() > 5 && name.substr(0, 5) == "ios7_") {
 			return true;
@@ -278,6 +296,7 @@ XcodeProvider::XcodeProvider(StringList &global_warnings, std::map<std::string,
 
 void XcodeProvider::addResourceFiles(const BuildSetup &setup, StringList &includeList, StringList &excludeList) {
 	includeList.push_back(setup.srcDir + "/dists/ios7/Info.plist");
+	includeList.push_back(setup.srcDir + "/dists/tvos/Info.plist");
 
 	ValueList &resources = getResourceFiles(setup);
 	for (ValueList::iterator it = resources.begin(); it != resources.end(); ++it) {
@@ -299,6 +318,7 @@ void XcodeProvider::createWorkspace(const BuildSetup &setup) {
 	setupDefines(setup);
 	_targets.push_back(PROJECT_DESCRIPTION "-iOS");
 	_targets.push_back(PROJECT_DESCRIPTION "-macOS");
+	_targets.push_back(PROJECT_DESCRIPTION "-tvOS");
 	setupCopyFilesBuildPhase();
 	setupFrameworksBuildPhase(setup);
 	setupNativeTarget();
@@ -748,6 +768,107 @@ void XcodeProvider::setupFrameworksBuildPhase(const BuildSetup &setup) {
 	framework_OSX->_properties["files"] = osx_files;
 
 	_frameworksBuildPhase.add(framework_OSX);
+
+	//////////////////////////////////////////////////////////////////////////
+	// ScummVM-tvOS
+	Object *framework_tvOS = new Object(this, "PBXFrameworksBuildPhase_" + _targets[TVOS_TARGET], "PBXFrameworksBuildPhase", "PBXFrameworksBuildPhase", "", "Frameworks");
+
+	framework_tvOS->addProperty("buildActionMask", "2147483647", "", kSettingsNoValue);
+	framework_tvOS->addProperty("runOnlyForDeploymentPostprocessing", "0", "", kSettingsNoValue);
+
+	// List of frameworks
+	Property tvOS_files;
+	tvOS_files._hasOrder = true;
+	tvOS_files._flags = kSettingsAsList;
+
+	ValueList frameworks_tvOS;
+	frameworks_tvOS.push_back("CoreAudio.framework");
+	frameworks_tvOS.push_back("CoreGraphics.framework");
+	frameworks_tvOS.push_back("CoreFoundation.framework");
+	frameworks_tvOS.push_back("Foundation.framework");
+	frameworks_tvOS.push_back("GameController.framework");
+	frameworks_tvOS.push_back("UIKit.framework");
+	frameworks_tvOS.push_back("SystemConfiguration.framework");
+	frameworks_tvOS.push_back("AudioToolbox.framework");
+	frameworks_tvOS.push_back("QuartzCore.framework");
+	frameworks_tvOS.push_back("OpenGLES.framework");
+
+	if (CONTAINS_DEFINE(setup.defines, "USE_FAAD")) {
+		frameworks_tvOS.push_back("libfaad.a");
+	}
+	if (CONTAINS_DEFINE(setup.defines, "USE_FLAC")) {
+		frameworks_tvOS.push_back("libFLAC.a");
+	}
+	if (CONTAINS_DEFINE(setup.defines, "USE_FREETYPE2")) {
+		frameworks_tvOS.push_back("libfreetype.a");
+		frameworks_tvOS.push_back("libbz2.a");
+	}
+	if (CONTAINS_DEFINE(setup.defines, "USE_JPEG")) {
+		frameworks_tvOS.push_back("libjpeg.a");
+	}
+	if (CONTAINS_DEFINE(setup.defines, "USE_PNG")) {
+		frameworks_tvOS.push_back("libpng.a");
+	}
+	if (CONTAINS_DEFINE(setup.defines, "USE_GIF")) {
+		frameworks_tvOS.push_back("libgif.a");
+	}
+	if (CONTAINS_DEFINE(setup.defines, "USE_OGG")) {
+		frameworks_tvOS.push_back("libogg.a");
+	}
+	if (CONTAINS_DEFINE(setup.defines, "USE_VORBIS")) {
+		frameworks_tvOS.push_back("libvorbis.a");
+		frameworks_tvOS.push_back("libvorbisfile.a");
+	}
+	if (CONTAINS_DEFINE(setup.defines, "USE_TREMOR")) {
+		frameworks_tvOS.push_back("libvorbisidec.a");
+	}
+	if (CONTAINS_DEFINE(setup.defines, "USE_THEORADEC")) {
+		frameworks_tvOS.push_back("libtheoradec.a");
+	}
+	if (CONTAINS_DEFINE(setup.defines, "USE_MAD")) {
+		frameworks_tvOS.push_back("libmad.a");
+	}
+	if (CONTAINS_DEFINE(setup.defines, "USE_MPEG2")) {
+		frameworks_tvOS.push_back("libmpeg2.a");
+	}
+	if (CONTAINS_DEFINE(setup.defines, "USE_FRIBIDI")) {
+		frameworks_tvOS.push_back("libfribidi.a");
+	}
+	if (CONTAINS_DEFINE(setup.defines, "USE_FLUIDSYNTH") &&
+		!CONTAINS_DEFINE(setup.defines, "USE_FLUIDLITE")) {
+		frameworks_tvOS.push_back("libfluidsynth.a");
+		frameworks_tvOS.push_back("libglib-2.0.a");
+		frameworks_tvOS.push_back("libintl.a");
+		frameworks_tvOS.push_back("libffi.a");
+		frameworks_tvOS.push_back("CoreMIDI.framework");
+		frameworks_tvOS.push_back("libiconv.tbd");
+	}
+	if (CONTAINS_DEFINE(setup.defines, "USE_ZLIB")) {
+		frameworks_tvOS.push_back("libz.tbd");
+	}
+	if (CONTAINS_DEFINE(setup.defines, "USE_LIBCURL")) {
+		frameworks_tvOS.push_back("libcurl.a");
+		frameworks_tvOS.push_back("Security.framework");
+	}
+	if (CONTAINS_DEFINE(setup.defines, "USE_SDL_NET")) {
+		if (setup.useSDL2)
+			frameworks_tvOS.push_back("libSDL2_net.a");
+		else
+			frameworks_tvOS.push_back("libSDL_net.a");
+	}
+
+	for (ValueList::iterator framework = frameworks_tvOS.begin(); framework != frameworks_tvOS.end(); framework++) {
+		std::string id = "Frameworks_" + *framework + "_appletv";
+		std::string comment = *framework + " in Frameworks";
+
+		ADD_SETTING_ORDER_NOVALUE(tvOS_files, getHash(id), comment, order++);
+		ADD_BUILD_FILE(id, *framework, getHash(*framework), comment);
+		ADD_FILE_REFERENCE(*framework, *framework, properties[*framework]);
+	}
+
+	framework_tvOS->_properties["files"] = tvOS_files;
+
+	_frameworksBuildPhase.add(framework_tvOS);
 }
 
 void XcodeProvider::setupNativeTarget() {
@@ -816,6 +937,7 @@ void XcodeProvider::setupProject() {
 	targets._flags = kSettingsAsList;
 	targets._settings[getHash("PBXNativeTarget_" + _targets[IOS_TARGET])] = Setting("", _targets[IOS_TARGET], kSettingsNoValue, 0, 0);
 	targets._settings[getHash("PBXNativeTarget_" + _targets[OSX_TARGET])] = Setting("", _targets[OSX_TARGET], kSettingsNoValue, 0, 1);
+	targets._settings[getHash("PBXNativeTarget_" + _targets[TVOS_TARGET])] = Setting("", _targets[TVOS_TARGET], kSettingsNoValue, 0, 2);
 	project->_properties["targets"] = targets;
 
 	// Force list even when there is only a single target
@@ -863,6 +985,7 @@ XcodeProvider::ValueList& XcodeProvider::getResourceFiles(const BuildSetup &setu
 		files.push_back("dists/engine-data/ultima.dat");
 		files.push_back("dists/engine-data/wintermute.zip");
 		files.push_back("dists/ios7/LaunchScreen_ios.storyboard");
+		files.push_back("dists/tvos/LaunchScreen_tvos.storyboard");
 		files.push_back("dists/pred.dic");
 		files.push_back("dists/networking/wwwroot.zip");
 		if (CONTAINS_DEFINE(setup.defines, "ENABLE_GRIME")) {
@@ -1287,6 +1410,85 @@ void XcodeProvider::setupBuildConfiguration(const BuildSetup &setup) {
 	_buildConfiguration.add(scummvmOSX_Debug_Object);
 	_buildConfiguration.add(scummvmOSX_Release_Object);
 
+	///****************************************
+	// * ScummVM - tvOS Target
+	// ****************************************/
+
+	// Debug
+	Object *tvOS_Debug_Object = new Object(this, "XCBuildConfiguration_" PROJECT_DESCRIPTION "-tvOS_Debug", _targets[TVOS_TARGET] /* ScummVM-tvOS */, "XCBuildConfiguration", "PBXNativeTarget", "Debug");
+	Property tvOS_Debug;
+	ADD_SETTING_QUOTE(tvOS_Debug, "CODE_SIGN_IDENTITY", "iPhone Developer");
+	ADD_SETTING_QUOTE_VAR(tvOS_Debug, "CODE_SIGN_IDENTITY[sdk=appletvos*]", "iPhone Developer");
+	ADD_SETTING(tvOS_Debug, "COPY_PHASE_STRIP", "NO");
+	ADD_SETTING_QUOTE(tvOS_Debug, "DEBUG_INFORMATION_FORMAT", "dwarf");
+	ValueList tvOS_FrameworkSearchPaths;
+	tvOS_FrameworkSearchPaths.push_back("$(inherited)");
+	tvOS_FrameworkSearchPaths.push_back("\"$(SDKROOT)$(SYSTEM_LIBRARY_DIR)/PrivateFrameworks\"");
+	ADD_SETTING_LIST(tvOS_Debug, "FRAMEWORK_SEARCH_PATHS", tvOS_FrameworkSearchPaths, kSettingsAsList, 5);
+	ADD_SETTING(tvOS_Debug, "GCC_DYNAMIC_NO_PIC", "NO");
+	ADD_SETTING(tvOS_Debug, "GCC_ENABLE_CPP_EXCEPTIONS", "NO");
+	ADD_SETTING(tvOS_Debug, "GCC_OPTIMIZATION_LEVEL", "0");
+	ADD_SETTING(tvOS_Debug, "GCC_PRECOMPILE_PREFIX_HEADER", "NO");
+	ADD_SETTING(tvOS_Debug, "GCC_WARN_64_TO_32_BIT_CONVERSION", "NO");
+	ADD_SETTING_QUOTE(tvOS_Debug, "GCC_PREFIX_HEADER", "");
+	ADD_SETTING(tvOS_Debug, "GCC_UNROLL_LOOPS", "YES");
+	ValueList tvOS_HeaderSearchPaths;
+	tvOS_HeaderSearchPaths.push_back("$(SRCROOT)/engines/");
+	tvOS_HeaderSearchPaths.push_back("$(SRCROOT)");
+	for (StringList::const_iterator i = setup.includeDirs.begin(); i != setup.includeDirs.end(); ++i)
+		tvOS_HeaderSearchPaths.push_back("\"" + *i + "\"");
+	tvOS_HeaderSearchPaths.push_back("\"" + projectOutputDirectory + "\"");
+	tvOS_HeaderSearchPaths.push_back("\"" + projectOutputDirectory + "/include\"");
+	if (CONTAINS_DEFINE(setup.defines, "USE_SDL_NET")) {
+		if (setup.useSDL2)
+			tvOS_HeaderSearchPaths.push_back("\"" + projectOutputDirectory + "/include/SDL2\"");
+		else
+			tvOS_HeaderSearchPaths.push_back("\"" + projectOutputDirectory + "include/SDL\"");
+	}
+	ADD_SETTING_LIST(tvOS_Debug, "HEADER_SEARCH_PATHS", tvOS_HeaderSearchPaths, kSettingsAsList | kSettingsQuoteVariable, 5);
+	ADD_SETTING_QUOTE(tvOS_Debug, "INFOPLIST_FILE", "$(SRCROOT)/dists/tvos/Info.plist");
+	ValueList tvOS_LibPaths;
+	for (StringList::const_iterator i = setup.libraryDirs.begin(); i != setup.libraryDirs.end(); ++i)
+		tvOS_LibPaths.push_back("\"" + *i + "\"");
+	tvOS_LibPaths.push_back("$(inherited)");
+	tvOS_LibPaths.push_back("\"" + projectOutputDirectory + "/lib\"");
+	ADD_SETTING_LIST(tvOS_Debug, "LIBRARY_SEARCH_PATHS", tvOS_LibPaths, kSettingsAsList, 5);
+	ADD_SETTING(tvOS_Debug, "ONLY_ACTIVE_ARCH", "YES");
+	ADD_SETTING(tvOS_Debug, "PRODUCT_NAME", PROJECT_NAME);
+	ADD_SETTING(tvOS_Debug, "PRODUCT_BUNDLE_IDENTIFIER", "\"org.scummvm.${PRODUCT_NAME}\"");
+	ADD_SETTING(tvOS_Debug, "TVOS_DEPLOYMENT_TARGET", "9.0");
+	ADD_SETTING_QUOTE_VAR(tvOS_Debug, "PROVISIONING_PROFILE[sdk=appletvos*]", "");
+	ADD_SETTING(tvOS_Debug, "SDKROOT", "appletvos");
+	ADD_SETTING_QUOTE(tvOS_Debug, "TARGETED_DEVICE_FAMILY", "3");
+	ValueList scummvmTVOS_defines;
+	ADD_DEFINE(scummvmTVOS_defines, "\"$(inherited)\"");
+	ADD_DEFINE(scummvmTVOS_defines, "IPHONE");
+	ADD_DEFINE(scummvmTVOS_defines, "IPHONE_IOS7");
+	ADD_DEFINE(scummvmTVOS_defines, "IPHONE_SANDBOXED");
+	if (CONTAINS_DEFINE(setup.defines, "USE_SDL_NET"))
+		ADD_DEFINE(scummvmTVOS_defines, "WITHOUT_SDL");
+	ADD_SETTING_LIST(tvOS_Debug, "GCC_PREPROCESSOR_DEFINITIONS", scummvmTVOS_defines, kSettingsNoQuote | kSettingsAsList, 5);
+	ADD_SETTING(tvOS_Debug, "ASSETCATALOG_COMPILER_APPICON_NAME", "AppIcon");
+	ADD_SETTING(tvOS_Debug, "ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME", "LaunchImage");
+	tvOS_Debug_Object->addProperty("name", "Debug", "", kSettingsNoValue);
+	tvOS_Debug_Object->_properties["buildSettings"] = tvOS_Debug;
+
+	// Release
+	Object *tvOS_Release_Object = new Object(this, "XCBuildConfiguration_" PROJECT_DESCRIPTION "-tvOS_Release", _targets[TVOS_TARGET] /* ScummVM-tvOS */, "XCBuildConfiguration", "PBXNativeTarget", "Release");
+	Property tvOS_Release(tvOS_Debug);
+	ADD_SETTING(tvOS_Release, "GCC_OPTIMIZATION_LEVEL", "3");
+	ADD_SETTING(tvOS_Release, "COPY_PHASE_STRIP", "YES");
+	REMOVE_SETTING(tvOS_Release, "GCC_DYNAMIC_NO_PIC");
+	ADD_SETTING(tvOS_Release, "WRAPPER_EXTENSION", "app");
+	REMOVE_SETTING(tvOS_Release, "DEBUG_INFORMATION_FORMAT");
+	ADD_SETTING_QUOTE(tvOS_Release, "DEBUG_INFORMATION_FORMAT", "dwarf-with-dsym");
+
+	tvOS_Release_Object->addProperty("name", "Release", "", kSettingsNoValue);
+	tvOS_Release_Object->_properties["buildSettings"] = tvOS_Release;
+
+	_buildConfiguration.add(tvOS_Debug_Object);
+	_buildConfiguration.add(tvOS_Release_Object);
+
 	// Warning: This assumes we have all configurations with a Debug & Release pair
 	for (std::vector<Object *>::iterator config = _buildConfiguration._objects.begin(); config != _buildConfiguration._objects.end(); config++) {
 
@@ -1310,16 +1512,24 @@ void XcodeProvider::setupBuildConfiguration(const BuildSetup &setup) {
 void XcodeProvider::setupImageAssetCatalog(const BuildSetup &setup) {
 	const std::string filename = "Images.xcassets";
 	const std::string absoluteCatalogPath = _projectRoot + "/dists/ios7/" + filename;
+	const std::string absoluteCatalogPathTVOS = _projectRoot + "/dists/tvos/" + filename;
 	const std::string id = "FileReference_" + absoluteCatalogPath;
+	const std::string idTVOS = "FileReference_" + absoluteCatalogPathTVOS;
 	Group *group = touchGroupsForPath(absoluteCatalogPath);
+	Group *groupTVOS = touchGroupsForPath(absoluteCatalogPathTVOS);
 	group->addChildFile(filename);
+	groupTVOS->addChildFile(filename);
 	addBuildFile(absoluteCatalogPath, filename, getHash(id), "Image Asset Catalog");
+	addBuildFile(absoluteCatalogPathTVOS, filename, getHash(idTVOS), "Image Asset Catalog");
 }
 
 void XcodeProvider::setupAdditionalSources(std::string targetName, Property &files, int &order) {
 	if (targetIsIOS(targetName)) {
 		const std::string absoluteCatalogPath = _projectRoot + "/dists/ios7/Images.xcassets";
 		ADD_SETTING_ORDER_NOVALUE(files, getHash(absoluteCatalogPath), "Image Asset Catalog", order++);
+	} else if (targetIsTVOS(targetName)) {
+		const std::string absoluteCatalogPath = _projectRoot + "/dists/tvos/Images.xcassets";
+		ADD_SETTING_ORDER_NOVALUE(files, getHash(absoluteCatalogPath), "Image Asset Catalog", order++);
 	}
 }
 


Commit: 5f54aedbb9c952578afa0bc09548702d994c34d0
    https://github.com/scummvm/scummvm/commit/5f54aedbb9c952578afa0bc09548702d994c34d0
Author: Lars Sundström (l.sundstrom at gmail.com)
Date: 2023-01-29T21:13:51Z

Commit Message:
IOS7: Put iOS specific code within platform specific macros

iOS and tvOS shares a lot of code. However some there are parts that are
specific to iOS, for instance handling of UI device orientation and
certain types of gestures.

Currently there are also some limitations on the Apple TV that needs to
be flagged to the  engine. There is no support for virtual keyboard, no
clipboard support and no possibility to open URLs.

Put code specific for iOS within the ObjC platfrom macro TARGET_OS_IOS.
The code specific for tvOS are put within the macro TARGET_OS_TV.

Changed paths:
    backends/platform/ios7/ios7_app_delegate.mm
    backends/platform/ios7/ios7_keyboard.mm
    backends/platform/ios7/ios7_osys_main.cpp
    backends/platform/ios7/ios7_osys_misc.mm
    backends/platform/ios7/ios7_osys_video.mm
    backends/platform/ios7/ios7_video.h
    backends/platform/ios7/ios7_video.mm


diff --git a/backends/platform/ios7/ios7_app_delegate.mm b/backends/platform/ios7/ios7_app_delegate.mm
index 831e319877f..4a8140a383b 100644
--- a/backends/platform/ios7/ios7_app_delegate.mm
+++ b/backends/platform/ios7/ios7_app_delegate.mm
@@ -59,17 +59,21 @@
 	_controller = [[iOS7ScummVMViewController alloc] init];
 
 	_view = [[iPhoneView alloc] initWithFrame:rect];
+#if TARGET_OS_IOS
 	_view.multipleTouchEnabled = YES;
+#endif
 	_controller.view = _view;
 
 	[_window setRootViewController:_controller];
 	[_window makeKeyAndVisible];
 
+#if TARGET_OS_IOS
 	[[UIDevice currentDevice] beginGeneratingDeviceOrientationNotifications];
 	[[NSNotificationCenter defaultCenter] addObserver:self
 	                                         selector:@selector(didRotate:)
 	                                             name:@"UIDeviceOrientationDidChangeNotification"
 	                                           object:nil];
+#endif
 
 	// Force creation of the shared instance on the main thread
 	iOS7_buildSharedOSystemInstance();
@@ -93,8 +97,10 @@
 
 	// Make sure we have the correct orientation in case the orientation was changed while
 	// the app was inactive.
+#if TARGET_OS_IOS
 	UIDeviceOrientation screenOrientation = [[UIDevice currentDevice] orientation];
 	[_view deviceOrientationChanged:screenOrientation];
+#endif
 }
 
 - (void)applicationDidEnterBackground:(UIApplication *)application {
@@ -119,8 +125,10 @@
 }
 
 - (void)didRotate:(NSNotification *)notification {
+#if TARGET_OS_IOS
 	UIDeviceOrientation screenOrientation = [[UIDevice currentDevice] orientation];
 	[_view deviceOrientationChanged:screenOrientation];
+#endif
 }
 
 + (iOS7AppDelegate *)iOS7AppDelegate {
@@ -145,7 +153,12 @@
 @end
 
 const char *iOS7_getDocumentsDir() {
-	NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
+	NSArray *paths;
+#if TARGET_OS_IOS
+	paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
+#else
+	paths = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES);
+#endif
 	NSString *documentsDirectory = [paths objectAtIndex:0];
 	return [documentsDirectory UTF8String];
 }
diff --git a/backends/platform/ios7/ios7_keyboard.mm b/backends/platform/ios7/ios7_keyboard.mm
index e378eb1e0e3..0ee0fb9d523 100644
--- a/backends/platform/ios7/ios7_keyboard.mm
+++ b/backends/platform/ios7/ios7_keyboard.mm
@@ -30,7 +30,9 @@
 
 @interface TextInputHandler : UITextView {
 	SoftKeyboard *softKeyboard;
+#if TARGET_OS_IOS
 	UIToolbar *toolbar;
+#endif
 	UIScrollView *scrollView;
 }
 
@@ -51,7 +53,7 @@
 	[self setAutocorrectionType:UITextAutocorrectionTypeNo];
 	[self setAutocapitalizationType:UITextAutocapitalizationTypeNone];
 	[self setEnablesReturnKeyAutomatically:NO];
-
+#if TARGET_OS_IOS
 	// Hide the input assistent bar. The API is only available since IOS 9.0.
 	// The code only compils with the iOS 9.0+ SDK, and only works on iOS 9.0
 	// or above.
@@ -118,11 +120,14 @@
 	[scrollView addSubview:toolbar];
 	self.inputAccessoryView = scrollView;
 
+#endif
 	return self;
 }
 
 -(void)dealloc {
+#if TARGET_OS_IOS
 	[toolbar release];
+#endif
 	[scrollView release];
 	[super dealloc];
 }
@@ -133,9 +138,11 @@
 //	self.inputAccessoryView = scrollView;
 //	[self reloadInputViews];
 	// We need at least a width of 768 pt for the toolbar. If we add more buttons this may need to be increased.
+#if TARGET_OS_IOS
 	toolbar.frame = CGRectMake(0, 0, MAX(768, [[UIScreen mainScreen] bounds].size.width), toolbar.frame.size.height);
 	toolbar.bounds = toolbar.frame;
 	scrollView.contentSize = toolbar.frame.size;
+#endif
 }
 
 - (void)detachAccessoryView {
@@ -276,7 +283,9 @@
 	inputDelegate = nil;
 	inputView = [[TextInputHandler alloc] initWithKeyboard:self];
 	inputView.delegate = self;
+#if TARGET_OS_IOS
 	[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(prepareKeyboard:) name:UIKeyboardWillShowNotification object:nil];
+#endif
 	return self;
 }
 
@@ -314,6 +323,7 @@
 }
 
 - (void)prepareKeyboard:(NSNotification *)notification {
+#if TARGET_OS_IOS
 	// Check if a hardware keyboard is connected, and only show the accessory view if there isn't one.
 	// If there is a hardware keyboard, the software one will only contains the text assistance bar
 	// and will be small (less than 100 pt, but use a bit more in case it changes with future iOS versions).
@@ -326,6 +336,7 @@
 		[inputView detachAccessoryView];
 	else
 		[inputView attachAccessoryView];
+#endif
 }
 
 - (void)showKeyboard {
diff --git a/backends/platform/ios7/ios7_osys_main.cpp b/backends/platform/ios7/ios7_osys_main.cpp
index 417882b127e..4757283df91 100644
--- a/backends/platform/ios7/ios7_osys_main.cpp
+++ b/backends/platform/ios7/ios7_osys_main.cpp
@@ -159,7 +159,9 @@ bool OSystem_iOS7::hasFeature(Feature f) {
 	case kFeatureCursorPalette:
 	case kFeatureFilteringMode:
 	case kFeatureVirtualKeyboard:
+#if TARGET_OS_IOS
 	case kFeatureClipboardSupport:
+#endif
 	case kFeatureOpenUrl:
 	case kFeatureNoQuit:
 		return true;
diff --git a/backends/platform/ios7/ios7_osys_misc.mm b/backends/platform/ios7/ios7_osys_misc.mm
index 4c7c9bce09d..214dfebb3b7 100644
--- a/backends/platform/ios7/ios7_osys_misc.mm
+++ b/backends/platform/ios7/ios7_osys_misc.mm
@@ -49,13 +49,18 @@ Common::String OSystem_iOS7::getSystemLanguage() const {
 }
 
 bool OSystem_iOS7::hasTextInClipboard() {
+#if TARGET_OS_IOS
 	return [[UIPasteboard generalPasteboard] containsPasteboardTypes:UIPasteboardTypeListString];
+#else
+	return false;
+#endif
 }
 
 Common::U32String OSystem_iOS7::getTextFromClipboard() {
 	if (!hasTextInClipboard())
 		return Common::U32String();
 
+#if TARGET_OS_IOS
 	UIPasteboard *pb = [UIPasteboard generalPasteboard];
 	NSString *str = pb.string;
 	if (str == nil)
@@ -81,9 +86,13 @@ Common::U32String OSystem_iOS7::getTextFromClipboard() {
 	delete[] text;
 
 	return u32String;
+#else
+	return Common::U32String();
+#endif
 }
 
 bool OSystem_iOS7::setTextInClipboard(const Common::U32String &text) {
+#if TARGET_OS_IOS
 #ifdef SCUMM_LITTLE_ENDIAN
 	NSStringEncoding stringEncoding = NSUTF32LittleEndianStringEncoding;
 #else
@@ -94,6 +103,9 @@ bool OSystem_iOS7::setTextInClipboard(const Common::U32String &text) {
 	[pb setString:nsstring];
 	[nsstring release];
 	return true;
+#else
+	return false;
+#endif
 }
 
 bool OSystem_iOS7::openUrl(const Common::String &url) {
diff --git a/backends/platform/ios7/ios7_osys_video.mm b/backends/platform/ios7/ios7_osys_video.mm
index 3b010161bcf..7d7830b4655 100644
--- a/backends/platform/ios7/ios7_osys_video.mm
+++ b/backends/platform/ios7/ios7_osys_video.mm
@@ -28,6 +28,7 @@
 #include "graphics/blit.h"
 #include "backends/platform/ios7/ios7_app_delegate.h"
 
+#if TARGET_OS_IOS
 @interface iOS7AlertHandler : NSObject<UIAlertViewDelegate>
 @end
 
@@ -49,8 +50,10 @@ static void displayAlert(void *ctx) {
 	[alert show];
 	[alert autorelease];
 }
+#endif
 
 void OSystem_iOS7::fatalError() {
+#if TARGET_OS_IOS
 	if (_lastErrorMessage.size()) {
 		dispatch_async_f(dispatch_get_main_queue(), (void *)_lastErrorMessage.c_str(), displayAlert);
 		for(;;);
@@ -58,6 +61,7 @@ void OSystem_iOS7::fatalError() {
 	else {
 		OSystem::fatalError();
 	}
+#endif
 }
 
 void OSystem_iOS7::logMessage(LogMessageType::Type type, const char *message) {
diff --git a/backends/platform/ios7/ios7_video.h b/backends/platform/ios7/ios7_video.h
index 2ff3f843588..e909f914f7b 100644
--- a/backends/platform/ios7/ios7_video.h
+++ b/backends/platform/ios7/ios7_video.h
@@ -113,7 +113,9 @@ typedef struct {
 - (void)updateMouseCursorScaling;
 - (void)updateMouseCursor;
 
+#if TARGET_OS_IOS
 - (void)deviceOrientationChanged:(UIDeviceOrientation)orientation;
+#endif
 
 - (void)showKeyboard;
 - (void)hideKeyboard;
diff --git a/backends/platform/ios7/ios7_video.mm b/backends/platform/ios7/ios7_video.mm
index 81517656699..25fadcd0dd4 100644
--- a/backends/platform/ios7/ios7_video.mm
+++ b/backends/platform/ios7/ios7_video.mm
@@ -54,7 +54,11 @@ void printOglError(const char *file, int line) {
 }
 
 bool iOS7_isBigDevice() {
+#if TARGET_OS_IOS
 	return UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad;
+#elif TARGET_OS_TV
+	return true;
+#endif
 }
 
 static inline void execute_on_main_thread(void (^block)(void)) {
@@ -338,6 +342,7 @@ uint getSizeNextPOT(uint size) {
 }
 
 - (void)setupGestureRecognizers {
+#if TARGET_OS_IOS
 	UIPinchGestureRecognizer *pinchKeyboard = [[UIPinchGestureRecognizer alloc] initWithTarget:self action:@selector(keyboardPinch:)];
 
 	UISwipeGestureRecognizer *swipeRight = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:@selector(twoFingersSwipeRight:)];
@@ -415,6 +420,7 @@ uint getSizeNextPOT(uint size) {
 	[swipeUp3 release];
 	[swipeDown3 release];
 	[doubleTapTwoFingers release];
+#endif
 }
 
 - (id)initWithFrame:(struct CGRect)frame {
@@ -424,7 +430,7 @@ uint getSizeNextPOT(uint size) {
 
 	[self setupGestureRecognizers];
 
-	if (@available(iOS 14.0, *)) {
+	if (@available(iOS 14.0, tvOS 14.0, *)) {
 		_controllers.push_back([[MouseController alloc] initWithView:self]);
 		_controllers.push_back([[GamepadController alloc] initWithView:self]);
 	}
@@ -720,14 +726,15 @@ uint getSizeNextPOT(uint size) {
 	// available when running on iOS 11+ if it has been compiled on iOS 11+
 #ifdef __IPHONE_11_0
 #if __has_builtin(__builtin_available)
-	if ( @available(iOS 11,*) ) {
+	if ( @available(iOS 11, tvOS 11, *) ) {
 #else
 	if ( [[[UIApplication sharedApplication] keyWindow] respondsToSelector:@selector(safeAreaInsets)] ) {
 #endif
 		CGRect screenSize = [[UIScreen mainScreen] bounds];
+		CGRect newFrame = screenSize;
+#if TARGET_OS_IOS
 		UIEdgeInsets inset = [[[UIApplication sharedApplication] keyWindow] safeAreaInsets];
 		UIInterfaceOrientation orientation = [[UIApplication sharedApplication] statusBarOrientation];
-		CGRect newFrame = screenSize;
 		if ( orientation == UIInterfaceOrientationPortrait ) {
 			newFrame = CGRectMake(screenSize.origin.x, screenSize.origin.y + inset.top, screenSize.size.width, screenSize.size.height - inset.top);
 		} else if ( orientation == UIInterfaceOrientationLandscapeLeft ) {
@@ -735,6 +742,7 @@ uint getSizeNextPOT(uint size) {
 		} else if ( orientation == UIInterfaceOrientationLandscapeRight ) {
 			newFrame = CGRectMake(screenSize.origin.x + inset.left, screenSize.origin.y, screenSize.size.width - inset.left, screenSize.size.height);
 		}
+#endif
 		self.frame = newFrame;
 	}
 #endif
@@ -834,7 +842,7 @@ uint getSizeNextPOT(uint size) {
 }
 
 - (BOOL)isMouseControllerConnected {
-	if (@available(iOS 14.0, *)) {
+	if (@available(iOS 14.0, tvOS 14.0, *)) {
 		return [self isControllerTypeConnected:MouseController.class];
 	} else {
 		// Fallback on earlier versions
@@ -843,7 +851,7 @@ uint getSizeNextPOT(uint size) {
 }
 
 - (BOOL)isGamepadControllerConnected {
-	if (@available(iOS 14.0, *)) {
+	if (@available(iOS 14.0, tvOS 14.0, *)) {
 		return [self isControllerTypeConnected:GamepadController.class];
 	} else {
 		// Fallback on earlier versions
@@ -851,6 +859,7 @@ uint getSizeNextPOT(uint size) {
 	}
 }
 
+#if TARGET_OS_IOS
 - (void)deviceOrientationChanged:(UIDeviceOrientation)orientation {
 	[self addEvent:InternalEvent(kInputOrientationChanged, orientation, 0)];
 
@@ -861,6 +870,7 @@ uint getSizeNextPOT(uint size) {
 		[self showKeyboard];
 	}
 }
+#endif
 
 - (void)showKeyboard {
 	[_keyboardView showKeyboard];
@@ -908,12 +918,14 @@ uint getSizeNextPOT(uint size) {
 	}
 }
 
+#if TARGET_OS_IOS
 - (void)keyboardPinch:(UIPinchGestureRecognizer *)recognizer {
 	if ([recognizer scale] < 0.8)
 		[self showKeyboard];
 	else if ([recognizer scale] > 1.25)
 		[self hideKeyboard];
 }
+#endif
 
 - (void)twoFingersSwipeRight:(UISwipeGestureRecognizer *)recognizer {
 	[self addEvent:InternalEvent(kInputSwipe, kUIViewSwipeRight, 2)];


Commit: c24ee0d61e20836e54efa2e5db34b0d791aff2a4
    https://github.com/scummvm/scummvm/commit/c24ee0d61e20836e54efa2e5db34b0d791aff2a4
Author: Lars Sundström (l.sundstrom at gmail.com)
Date: 2023-01-29T21:13:51Z

Commit Message:
IOS7: Add missing break to kInputJoystickButtonUp

Joystick button up events was not sent to the EventManager due to a
missing break in the kInputJoystickButtonUp case. This caused button
presses in the launcher and dialogs not to be triggered.

Adding the break enables use of joystick buttons in ScummVM GUIs.

Changed paths:
    backends/platform/ios7/ios7_osys_events.cpp


diff --git a/backends/platform/ios7/ios7_osys_events.cpp b/backends/platform/ios7/ios7_osys_events.cpp
index 66b15a390b5..290a84b63e7 100644
--- a/backends/platform/ios7/ios7_osys_events.cpp
+++ b/backends/platform/ios7/ios7_osys_events.cpp
@@ -137,6 +137,7 @@ bool OSystem_iOS7::pollEvent(Common::Event &event) {
 		case kInputJoystickButtonUp:
 			event.type = Common::EVENT_JOYBUTTON_UP;
 			event.joystick.button = internalEvent.value1;
+			break;
 
 		case kInputChanged:
 			event.type = Common::EVENT_INPUT_CHANGED;


Commit: 5aeef796bc356285250d0daf7e24f32fc98f6328
    https://github.com/scummvm/scummvm/commit/5aeef796bc356285250d0daf7e24f32fc98f6328
Author: Lars Sundström (l.sundstrom at gmail.com)
Date: 2023-01-29T21:13:51Z

Commit Message:
IOS7: Implement support for Apple TV remote

The Apple TV remote has a touch area which functions as a touch
controller. It also has a few buttons that can be programmed for
different actions.

The "touchpad mode" is not really relevant for the Apple TV remote.
However the pointer should be moved when swiping on the touch area
on the remote. Since we don't want to generate actions on touchBegan
and touchEnded for the remote, make sure these are only triggered if
the touch is made on direct contact with the screen, UITouchTypeDirect.

Implement the button handling by implement the microGamepad profile in
the GamepadController class. Only buttons A, X and the menu buttons are
relevant since the touch area is using the touch controller class.
The tvOS simulator however doesn't call the lambda functions defined for
the microGamepad buttons, hence the implementation of the "pressesBegan"
and "pressesEnded" which is called instead when running the simulator.

Implement common handling of the menu button. If the menu button is
pressed the soft keyboard will be shown. If pressing the menu button
again the soft keyboard will be hidden. If pressing the menu button
a third time the application will be suspended.

Implement new gesture recognizers that can be used with the Apple TV
remote. Up/down/left/right actions are triggered on press on the arrow
buttons, or tap on the edges of the touch area.

A long press, 5 seconds, of "Play/Pause" button toggles Mouse-click-and-
drag mode needed by some games.

Changed paths:
    backends/platform/ios7/ios7_gamepad_controller.mm
    backends/platform/ios7/ios7_touch_controller.mm
    backends/platform/ios7/ios7_video.mm
    dists/tvos/Info.plist
    dists/tvos/Info.plist.in


diff --git a/backends/platform/ios7/ios7_gamepad_controller.mm b/backends/platform/ios7/ios7_gamepad_controller.mm
index e7b34758d1a..9f3c0826109 100644
--- a/backends/platform/ios7/ios7_gamepad_controller.mm
+++ b/backends/platform/ios7/ios7_gamepad_controller.mm
@@ -27,10 +27,6 @@
 #include "backends/platform/ios7/ios7_video.h"
 #include <GameController/GameController.h>
 
-// This value will be multiplied with the x and y values of a thumbstick
-// value (-1, 1). Should ideally be configurable through ScummVM settings
-#define GAMEPAD_SENSITIVITY 20
-
 @implementation GamepadController {
 	GCController *_controller;
 }
@@ -50,10 +46,25 @@
 }
 
 - (void)controllerDidConnect:(NSNotification *)notification {
-	[self setIsConnected:YES];
 	_controller = (GCController*)notification.object;
 
+#if TARGET_OS_TV
+	if (_controller.microGamepad != nil) {
+		[self setIsConnected:YES];
+
+		_controller.microGamepad.buttonA.valueChangedHandler = ^(GCControllerButtonInput * _Nonnull button, float value, BOOL pressed) {
+			[self handleJoystickButtonAction:Common::JOYSTICK_BUTTON_A isPressed:pressed];
+		};
+
+		_controller.microGamepad.buttonX.valueChangedHandler = ^(GCControllerButtonInput * _Nonnull button, float value, BOOL pressed) {
+			// Map button X to button B because B is mapped to left button
+			[self handleJoystickButtonAction:Common::JOYSTICK_BUTTON_B isPressed:pressed];
+		};
+	}
+#endif
 	if (_controller.extendedGamepad != nil) {
+		[self setIsConnected:YES];
+
 		_controller.extendedGamepad.leftThumbstick.valueChangedHandler = ^(GCControllerDirectionPad * _Nonnull dpad, float xValue, float yValue) {
 			// Convert the given axis values in float (-1 to 1) to ScummVM Joystick
 			// Axis value as integers (0 to int16_max)
@@ -105,12 +116,6 @@
 		_controller.extendedGamepad.rightShoulder.valueChangedHandler = ^(GCControllerButtonInput * _Nonnull button, float value, BOOL pressed) {
 			[self handleJoystickButtonAction:Common::JOYSTICK_BUTTON_RIGHT_SHOULDER isPressed:pressed];
 		};
-#ifdef __IPHONE_13_0
-		_controller.extendedGamepad.buttonMenu.valueChangedHandler = ^(GCControllerButtonInput * _Nonnull button, float value, BOOL pressed) {
-			[[self view] addEvent:InternalEvent(kInputMainMenu, 0, 0)];
-
-		};
-#endif
 	}
 }
 
diff --git a/backends/platform/ios7/ios7_touch_controller.mm b/backends/platform/ios7/ios7_touch_controller.mm
index 6e567b4aaea..e68fbe4d2e8 100644
--- a/backends/platform/ios7/ios7_touch_controller.mm
+++ b/backends/platform/ios7/ios7_touch_controller.mm
@@ -59,23 +59,21 @@
 	NSSet *allTouches = [event allTouches];
 	if (allTouches.count == 1) {
 		_firstTouch = [allTouches anyObject];
-		if (_firstTouch.type == UITouchTypeDirect) {
-			if (iOS7_touchpadModeEnabled()) {
-				// In touchpad mode the action should occur on the current pointer position
-				[self handleMouseButtonAction:kGameControllerMouseButtonLeft isPressed:YES at:[[self view] pointerPosition]];
-			} else {
-				// Only move the pointer to the new position if not in touchpadMode else it's very hard to click on items
-				[self handlePointerMoveTo:[_firstTouch locationInView: [self view]]];
-				[self handleMouseButtonAction:kGameControllerMouseButtonLeft isPressed:YES at:[_firstTouch locationInView:[self view]]];
-			}
+		if (iOS7_touchpadModeEnabled()) {
+			// In touchpad mode the action should occur on the current pointer position
+			[self handleMouseButtonAction:kGameControllerMouseButtonLeft isPressed:YES at:[[self view] pointerPosition]];
+		} else if (_firstTouch.type == UITouchTypeDirect) {
+			// Only move the pointer to the new position if not in touchpadMode else it's very hard to click on items
+			[self handlePointerMoveTo:[_firstTouch locationInView: [self view]]];
+			[self handleMouseButtonAction:kGameControllerMouseButtonLeft isPressed:YES at:[_firstTouch locationInView:[self view]]];
 		}
 	} else if (allTouches.count == 2) {
 		_secondTouch = [self secondTouchOtherTouchThan:_firstTouch in:allTouches];
-		if (_secondTouch && _secondTouch.type == UITouchTypeDirect) {
+		if (_secondTouch) {
 			if (iOS7_touchpadModeEnabled()) {
 				// In touchpad mode the action should occur on the current pointer position
 				[self handleMouseButtonAction:kGameControllerMouseButtonRight isPressed:YES at:[[self view] pointerPosition]];
-			} else {
+			} else if (_secondTouch.type == UITouchTypeDirect) {
 				[self handleMouseButtonAction:kGameControllerMouseButtonRight isPressed:YES at:[_secondTouch locationInView:[self view]]];
 			}
 		}
@@ -87,18 +85,16 @@
 	for (UITouch *touch in allTouches) {
 		if (touch == _firstTouch ||
 			touch == _secondTouch) {
-			if (touch.type == UITouchTypeDirect) {
-				if (iOS7_touchpadModeEnabled()) {
-					// Calculate new position for the pointer based on delta of the current and previous location of the touch
-					CGPoint pointerLocation = [[self view] pointerPosition];
-					CGPoint touchLocation = [touch locationInView:[self view]];
-					CGPoint previousTouchLocation = [touch previousLocationInView:[self view]];
-					pointerLocation.y += touchLocation.y - previousTouchLocation.y;
-					pointerLocation.x += touchLocation.x - previousTouchLocation.x;
-					[self handlePointerMoveTo:pointerLocation];
-				} else {
-					[self handlePointerMoveTo:[touch locationInView: [self view]]];
-				}
+			if (iOS7_touchpadModeEnabled() || _firstTouch.type == UITouchTypeIndirect) {
+				// Calculate new position for the pointer based on delta of the current and previous location of the touch
+				CGPoint pointerLocation = [[self view] pointerPosition];
+				CGPoint touchLocation = [touch locationInView:[self view]];
+				CGPoint previousTouchLocation = [touch previousLocationInView:[self view]];
+				pointerLocation.y += touchLocation.y - previousTouchLocation.y;
+				pointerLocation.x += touchLocation.x - previousTouchLocation.x;
+				[self handlePointerMoveTo:pointerLocation];
+			} else if (_firstTouch.type == UITouchTypeDirect) {
+				[self handlePointerMoveTo:[touch locationInView: [self view]]];
 			}
 		}
 	}
@@ -108,12 +104,16 @@
 	NSSet *allTouches = [event allTouches];
 	if (allTouches.count == 1) {
 		UITouch *touch = [allTouches anyObject];
-		if (touch.type == UITouchTypeDirect) {
+		if (iOS7_touchpadModeEnabled()) {
+			[self handleMouseButtonAction:kGameControllerMouseButtonLeft isPressed:NO at:[[self view] pointerPosition]];
+		} else if (touch.type == UITouchTypeDirect) {
 			[self handleMouseButtonAction:kGameControllerMouseButtonLeft isPressed:NO at:[touch locationInView:[self view]]];
 		}
 	} else if (allTouches.count == 2) {
 		UITouch *touch = [[allTouches allObjects] objectAtIndex:1];
-		if (touch.type == UITouchTypeDirect) {
+		if (iOS7_touchpadModeEnabled()) {
+			[self handleMouseButtonAction:kGameControllerMouseButtonRight isPressed:NO at:[[self view] pointerPosition]];
+		} else if (touch.type == UITouchTypeDirect) {
 			[self handleMouseButtonAction:kGameControllerMouseButtonRight isPressed:NO at:[touch locationInView:[self view]]];
 		}
 	}
diff --git a/backends/platform/ios7/ios7_video.mm b/backends/platform/ios7/ios7_video.mm
index 25fadcd0dd4..cfdfcb14657 100644
--- a/backends/platform/ios7/ios7_video.mm
+++ b/backends/platform/ios7/ios7_video.mm
@@ -22,6 +22,7 @@
 // Disable symbol overrides so that we can use system headers.
 #define FORBIDDEN_SYMBOL_ALLOW_ALL
 
+#include "common/events.h"
 #include "backends/platform/ios7/ios7_video.h"
 #include "backends/platform/ios7/ios7_touch_controller.h"
 #include "backends/platform/ios7/ios7_mouse_controller.h"
@@ -420,6 +421,34 @@ uint getSizeNextPOT(uint size) {
 	[swipeUp3 release];
 	[swipeDown3 release];
 	[doubleTapTwoFingers release];
+#elif TARGET_OS_TV
+	UITapGestureRecognizer *tapUpGestureRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(threeFingersSwipeUp:)];
+	[tapUpGestureRecognizer setAllowedPressTypes:@[@(UIPressTypeUpArrow)]];
+
+	UITapGestureRecognizer *tapDownGestureRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(threeFingersSwipeDown:)];
+	[tapDownGestureRecognizer setAllowedPressTypes:@[@(UIPressTypeDownArrow)]];
+
+	UITapGestureRecognizer *tapLeftGestureRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(threeFingersSwipeLeft:)];
+	[tapLeftGestureRecognizer setAllowedPressTypes:@[@(UIPressTypeLeftArrow)]];
+
+	UITapGestureRecognizer *tapRightGestureRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(threeFingersSwipeRight:)];
+	[tapRightGestureRecognizer setAllowedPressTypes:@[@(UIPressTypeRightArrow)]];
+
+	UILongPressGestureRecognizer *longPressGestureRecognizer = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(showKeyboard)];
+	[longPressGestureRecognizer setAllowedPressTypes:@[[NSNumber numberWithInteger:UIPressTypePlayPause]]];
+	[longPressGestureRecognizer setMinimumPressDuration:1.0];
+
+	[self addGestureRecognizer:tapUpGestureRecognizer];
+	[self addGestureRecognizer:tapDownGestureRecognizer];
+	[self addGestureRecognizer:tapLeftGestureRecognizer];
+	[self addGestureRecognizer:tapRightGestureRecognizer];
+	[self addGestureRecognizer:longPressGestureRecognizer];
+
+	[tapUpGestureRecognizer release];
+	[tapDownGestureRecognizer release];
+	[tapLeftGestureRecognizer release];
+	[tapRightGestureRecognizer release];
+	[longPressGestureRecognizer release];
 #endif
 }
 
@@ -918,6 +947,58 @@ uint getSizeNextPOT(uint size) {
 	}
 }
 
+#if TARGET_OS_TV
+// UIKit calls these methods when a button is pressed by the user.
+// These methods are used to determine which button was pressed and
+// to take any needed actions. The default implementation of these
+// methods forwardsm the message up the responder chain.
+// Button presses are already handled by the GameController class for
+// connected game controllers (including the Apple TV remote).
+// The Apple TV remote is not registered as a micro game controller
+// when running the application in tvOS simulator, hence these methods
+// only needs to be implemented for the tvOS simulator to handle presses
+// on the Apple TV remote.
+-(void)pressesBegan:(NSSet<UIPress *> *)presses withEvent:(UIPressesEvent *)event {
+#if TARGET_OS_SIMULATOR
+	UIPress *press = [presses anyObject];
+	if (press.type == UIPressTypeMenu) {
+		// Trigger on pressesEnded
+	} else if (press.type == UIPressTypeSelect || press.type == UIPressTypePlayPause) {
+		[self addEvent:InternalEvent(kInputJoystickButtonDown, press.type == UIPressTypeSelect ? Common::JOYSTICK_BUTTON_A : Common::JOYSTICK_BUTTON_B, 0)];
+	}
+	else {
+		[super pressesBegan:presses withEvent:event];
+	}
+#endif
+}
+
+-(void)pressesEnded:(NSSet<UIPress *> *)presses withEvent:(UIPressesEvent *)event {
+#if TARGET_OS_SIMULATOR
+	UIPress *press = [presses anyObject];
+	if (press.type == UIPressTypeMenu) {
+		[self handleMainMenuKey];
+	} else if (press.type == UIPressTypeSelect || press.type == UIPressTypePlayPause) {
+		[self addEvent:InternalEvent(kInputJoystickButtonUp, press.type == UIPressTypeSelect ? Common::JOYSTICK_BUTTON_A : Common::JOYSTICK_BUTTON_B, 0)];
+	}
+	else {
+		[super pressesEnded:presses withEvent:event];
+	}
+#endif
+}
+
+-(void)pressesChanged:(NSSet<UIPress *> *)presses withEvent:(UIPressesEvent *)event {
+#if TARGET_OS_SIMULATOR
+	[super pressesChanged:presses withEvent:event];
+#endif
+}
+
+-(void)pressesCancelled:(NSSet<UIPress *> *)presses withEvent:(UIPressesEvent *)event {
+#if TARGET_OS_SIMULATOR
+	[super pressesCancelled:presses withEvent:event];
+#endif
+}
+#endif
+
 #if TARGET_OS_IOS
 - (void)keyboardPinch:(UIPinchGestureRecognizer *)recognizer {
 	if ([recognizer scale] < 0.8)
diff --git a/dists/tvos/Info.plist b/dists/tvos/Info.plist
index bf93f76be75..394b91bc925 100644
--- a/dists/tvos/Info.plist
+++ b/dists/tvos/Info.plist
@@ -28,6 +28,10 @@
 			<key>ProfileName</key>
 			<string>ExtendedGamepad</string>
 		</dict>
+		<dict>
+			<key>ProfileName</key>
+			<string>MicroGamepad</string>
+		</dict>
 	</array>
 	<key>GCSupportsControllerUserInteraction</key>
 	<true/>
diff --git a/dists/tvos/Info.plist.in b/dists/tvos/Info.plist.in
index 5603246fcd8..b32a3444b08 100644
--- a/dists/tvos/Info.plist.in
+++ b/dists/tvos/Info.plist.in
@@ -28,6 +28,10 @@
 			<key>ProfileName</key>
 			<string>ExtendedGamepad</string>
 		</dict>
+		<dict>
+			<key>ProfileName</key>
+			<string>MicroGamepad</string>
+		</dict>
 	</array>
 	<key>GCSupportsControllerUserInteraction</key>
 	<true/>


Commit: d731c9c290759a3c07b081e32c0a3a2bd1cfe18a
    https://github.com/scummvm/scummvm/commit/d731c9c290759a3c07b081e32c0a3a2bd1cfe18a
Author: Lars Sundström (l.sundstrom at gmail.com)
Date: 2023-01-29T21:13:51Z

Commit Message:
IOS7: Implement keyboard support for Apple TV OS

The UITextView is becoming focused by default in iOS and brings up the
keyboard for user input. This is not the case in tvOS. UITextView in
tvOS is not becoming focused by default and if manually setting it to
focused it will still not bring up the keyboard screen.

The UITextField is however becoming focused in both iOS and tvOS and
requires basically the same implementation. So the UITextView is
replaced with UITextField to bring up keyboard in both iOS and tvOS.

The UIToolbar class is not supported in tvOS. Instead implement the
toolbar as a UITabBar. The UITabBar is set directly as the
inputAccessoryView to the keyboard view in tvOS while in iOS it's put in
a UIScrollView (as the previous UIToolbar) to be able to scale the
inputAccessoryView better for small screens.

The UITabBar behaves a little bit different on iOS and tvOS where in
tvOS the delegate function
-(void)tabBar:(UITabBar *)tabBar didSelectItem:(UITabBarItem *)item
is called when navigated to a specific toolbar item, while in iOS called
when clicking on an item. To get the tvOS to trigger action on presses,
add a gesture recognizer to handle touch events.

Since the keyboard view on Apple TV always full screen prompted texts
gets hidden behind the keyboard. Delay the showing of the keyboard to
allow the user to understand what's requested as input.

Changed paths:
    backends/platform/ios7/ios7_keyboard.h
    backends/platform/ios7/ios7_keyboard.mm
    backends/platform/ios7/ios7_osys_video.mm


diff --git a/backends/platform/ios7/ios7_keyboard.h b/backends/platform/ios7/ios7_keyboard.h
index 3fe443dfa36..7efcb84ebc5 100644
--- a/backends/platform/ios7/ios7_keyboard.h
+++ b/backends/platform/ios7/ios7_keyboard.h
@@ -27,14 +27,14 @@
 
 @class TextInputHandler;
 
- at interface SoftKeyboard : UIView<UITextViewDelegate> {
+ at interface SoftKeyboard : UIView<UITextFieldDelegate> {
 	id inputDelegate;
 	TextInputHandler *inputView;
 }
 
 - (id)initWithFrame:(CGRect)frame;
 - (void)dealloc;
-- (UITextView *)inputView;
+- (UITextField *)inputView;
 - (void)setInputDelegate:(id)delegate;
 - (void)handleKeyPress:(unichar)c;
 - (void)handleMainMenuKey;
diff --git a/backends/platform/ios7/ios7_keyboard.mm b/backends/platform/ios7/ios7_keyboard.mm
index 0ee0fb9d523..5db19e1a02d 100644
--- a/backends/platform/ios7/ios7_keyboard.mm
+++ b/backends/platform/ios7/ios7_keyboard.mm
@@ -28,11 +28,9 @@
 - (void)setEnablesReturnKeyAutomatically:(BOOL)val;
 @end
 
- at interface TextInputHandler : UITextView {
+ at interface TextInputHandler : UITextField<UITabBarDelegate> {
 	SoftKeyboard *softKeyboard;
-#if TARGET_OS_IOS
-	UIToolbar *toolbar;
-#endif
+	UITabBar *toolbar;
 	UIScrollView *scrollView;
 }
 
@@ -69,47 +67,66 @@
 			item.trailingBarButtonGroups = @[];
 		}
 	}
+#endif
 #endif
 
-	toolbar = [[UIToolbar alloc] initWithFrame:CGRectMake(0.0f, 0.0f, 0.0f, 0.0f)];
+	toolbar = [[UITabBar alloc] initWithFrame:CGRectMake(0.0f, 0.0f, 0.0f, 0.0f)];
 	toolbar.barTintColor = keyboard.backgroundColor;
 	toolbar.tintColor = keyboard.tintColor;
 	toolbar.translucent = NO;
+	toolbar.delegate = self;
 
 	toolbar.items = @[
 		// GMM button
-		[[[UIBarButtonItem alloc] initWithTitle:@"\u2630" style:UIBarButtonItemStylePlain target:self action:@selector(mainMenuKey)] autorelease],
+		[[[UITabBarItem alloc] initWithTitle:@"\u2630" image:nil tag:1] autorelease],
 		// Escape key
-		[[[UIBarButtonItem alloc] initWithTitle:@"Esc" style:UIBarButtonItemStylePlain target:self action:@selector(escapeKey)] autorelease],
+		[[[UITabBarItem alloc] initWithTitle:@"Esc" image:nil tag:2] autorelease],
 		// Tab key
-		[[[UIBarButtonItem alloc] initWithTitle:@"Tab" style:UIBarButtonItemStylePlain target:self action:@selector(tabKey)] autorelease],
+		[[[UITabBarItem alloc] initWithTitle:@"Tab" image:nil tag:3] autorelease],
 		// Return key
-		[[[UIBarButtonItem alloc] initWithTitle:@"\u23ce" style:UIBarButtonItemStylePlain target:self action:@selector(returnKey)] autorelease],
+		[[[UITabBarItem alloc] initWithTitle:@"\u23ce" image:nil tag:4] autorelease],
 		// Function keys
-		[[[UIBarButtonItem alloc] initWithTitle:@"F1" style:UIBarButtonItemStylePlain target:self action:@selector(fn1Key)] autorelease],
-		[[[UIBarButtonItem alloc] initWithTitle:@"F2" style:UIBarButtonItemStylePlain target:self action:@selector(fn2Key)] autorelease],
-		[[[UIBarButtonItem alloc] initWithTitle:@"F3" style:UIBarButtonItemStylePlain target:self action:@selector(fn3Key)] autorelease],
-		[[[UIBarButtonItem alloc] initWithTitle:@"F4" style:UIBarButtonItemStylePlain target:self action:@selector(fn4Key)] autorelease],
-		[[[UIBarButtonItem alloc] initWithTitle:@"F5" style:UIBarButtonItemStylePlain target:self action:@selector(fn5Key)] autorelease],
-		[[[UIBarButtonItem alloc] initWithTitle:@"F6" style:UIBarButtonItemStylePlain target:self action:@selector(fn6Key)] autorelease],
-		[[[UIBarButtonItem alloc] initWithTitle:@"F7" style:UIBarButtonItemStylePlain target:self action:@selector(fn7Key)] autorelease],
-		[[[UIBarButtonItem alloc] initWithTitle:@"F8" style:UIBarButtonItemStylePlain target:self action:@selector(fn8Key)] autorelease],
-		[[[UIBarButtonItem alloc] initWithTitle:@"F9" style:UIBarButtonItemStylePlain target:self action:@selector(fn9Key)] autorelease],
-		[[[UIBarButtonItem alloc] initWithTitle:@"F10" style:UIBarButtonItemStylePlain target:self action:@selector(fn10Key)] autorelease],
-		[[[UIBarButtonItem alloc] initWithTitle:@"F11" style:UIBarButtonItemStylePlain target:self action:@selector(fn11Key)] autorelease],
-		[[[UIBarButtonItem alloc] initWithTitle:@"F12" style:UIBarButtonItemStylePlain target:self action:@selector(fn12Key)] autorelease],
+		[[[UITabBarItem alloc] initWithTitle:@"F1" image:nil tag:5] autorelease],
+		[[[UITabBarItem alloc] initWithTitle:@"F2" image:nil tag:6] autorelease],
+		[[[UITabBarItem alloc] initWithTitle:@"F3" image:nil tag:7] autorelease],
+		[[[UITabBarItem alloc] initWithTitle:@"F4" image:nil tag:8] autorelease],
+		[[[UITabBarItem alloc] initWithTitle:@"F5" image:nil tag:9] autorelease],
+		[[[UITabBarItem alloc] initWithTitle:@"F6" image:nil tag:10] autorelease],
+		[[[UITabBarItem alloc] initWithTitle:@"F7" image:nil tag:11] autorelease],
+		[[[UITabBarItem alloc] initWithTitle:@"F8" image:nil tag:12] autorelease],
+		[[[UITabBarItem alloc] initWithTitle:@"F9" image:nil tag:13] autorelease],
+		[[[UITabBarItem alloc] initWithTitle:@"F10" image:nil tag:14] autorelease],
+		[[[UITabBarItem alloc] initWithTitle:@"F11" image:nil tag:15] autorelease],
+		[[[UITabBarItem alloc] initWithTitle:@"F12" image:nil tag:16] autorelease],
 		// Arrow keys
-		[[[UIBarButtonItem alloc] initWithTitle:@"\u2190" style:UIBarButtonItemStylePlain target:self action:@selector(leftArrowKey)] autorelease],
-		[[[UIBarButtonItem alloc] initWithTitle:@"\u2191" style:UIBarButtonItemStylePlain target:self action:@selector(upArrowKey)] autorelease],
-		[[[UIBarButtonItem alloc] initWithTitle:@"\u2192" style:UIBarButtonItemStylePlain target:self action:@selector(rightArrowKey)] autorelease],
-		[[[UIBarButtonItem alloc] initWithTitle:@"\u2193" style:UIBarButtonItemStylePlain target:self action:@selector(downArrowKey)] autorelease],
-		// Spacer at the end
-		[[[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace target:nil action:nil] autorelease],
+		[[[UITabBarItem alloc] initWithTitle:@"\u2190" image:nil tag:17] autorelease],
+		[[[UITabBarItem alloc] initWithTitle:@"\u2191" image:nil tag:18] autorelease],
+		[[[UITabBarItem alloc] initWithTitle:@"\u2192" image:nil tag:19] autorelease],
+		[[[UITabBarItem alloc] initWithTitle:@"\u2193" image:nil tag:20] autorelease]
 	];
 
+	// Increase the font size on the UITabBarItems to make them readable on small displays
+	for (UITabBarItem *item in toolbar.items) {
+		[item setTitleTextAttributes: [NSDictionary dictionaryWithObjectsAndKeys: [UIFont fontWithName:@"Helvetica" size:20.0], NSFontAttributeName, nil] forState:UIControlStateNormal];
+	}
+
+#if TARGET_OS_TV
+	// In tvOS a UITabBarItem is selected when moving to the selected item, in other words
+	// no click is required. This is not a great user experience since the user needs to
+	// scroll to the wanted UITabBarItem causing the delegate function
+	// tabBar:(UITabBar *)tabBar didSelectItem:(UITabBarItem *)item to be called multiple
+	// times. Instead add a tap gesture on the UITabBar and let the delegate function set
+	// the selected item. Then trigger the action when the user press the button.
+	UITapGestureRecognizer *tapGesture = [[[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(selectUITabBarItem:)] autorelease];
+	[toolbar addGestureRecognizer:tapGesture];
+#endif
+
 	self.inputAccessoryView = toolbar;
 	[toolbar sizeToFit];
 
+#if TARGET_OS_IOS
+	// In tvOS the UITabBar is scrollable but not in iOS. In iOS the UITabBar must be
+	// put in a UIScrollView to be scrollable.
 	scrollView = [[UIScrollView alloc] init];
 	scrollView.frame = toolbar.frame;
 	scrollView.bounds = toolbar.bounds;
@@ -125,22 +142,96 @@
 }
 
 -(void)dealloc {
-#if TARGET_OS_IOS
 	[toolbar release];
-#endif
 	[scrollView release];
 	[super dealloc];
 }
 
+-(void)selectUITabBarItem:(UITapGestureRecognizer *)recognizer {
+	switch ([[toolbar selectedItem] tag]) {
+	case 1:
+		[self mainMenuKey];
+		break;
+	case 2:
+		[self escapeKey];
+		break;
+	case 3:
+		[self tabKey];
+		break;
+	case 4:
+		[self returnKey];
+		break;
+	case 5:
+		[self fn1Key];
+		break;
+	case 6:
+		[self fn2Key];
+		break;
+	case 7:
+		[self fn3Key];
+		break;
+	case 8:
+		[self fn4Key];
+		break;
+	case 9:
+		[self fn5Key];
+		break;
+	case 10:
+		[self fn6Key];
+		break;
+	case 11:
+		[self fn7Key];
+		break;
+	case 12:
+		[self fn8Key];
+		break;
+	case 13:
+		[self fn9Key];
+		break;
+	case 14:
+		[self fn10Key];
+		break;
+	case 15:
+		[self fn11Key];
+		break;
+	case 16:
+		[self fn12Key];
+		break;
+	case 17:
+		[self leftArrowKey];
+		break;
+	case 18:
+		[self upArrowKey];
+		break;
+	case 19:
+		[self rightArrowKey];
+		break;
+	case 20:
+		[self downArrowKey];
+		break;
+	default:
+		break;
+	}
+}
+
+-(void)tabBar:(UITabBar *)tabBar didSelectItem:(UITabBarItem *)item {
+#if TARGET_OS_IOS
+	// In iOS the UITabBarItem is selected on touch. Trigger the action
+	// on the selected item.
+	[self selectUITabBarItem:nil];
+#endif
+}
+
 - (void)attachAccessoryView {
 	self.inputAccessoryView.hidden = NO;
 	// Alternatively we could add/remove instead of show/hide the inpute accessory view
 //	self.inputAccessoryView = scrollView;
 //	[self reloadInputViews];
-	// We need at least a width of 768 pt for the toolbar. If we add more buttons this may need to be increased.
-#if TARGET_OS_IOS
-	toolbar.frame = CGRectMake(0, 0, MAX(768, [[UIScreen mainScreen] bounds].size.width), toolbar.frame.size.height);
+	// We need at least a width of 1024 pt for the toolbar. If we add more buttons this may need to be increased.
+	toolbar.frame = CGRectMake(0, 0, MAX(1024, [[UIScreen mainScreen] bounds].size.width), toolbar.frame.size.height);
 	toolbar.bounds = toolbar.frame;
+	toolbar.selectedItem = nil;
+#if TARGET_OS_IOS
 	scrollView.contentSize = toolbar.frame.size;
 #endif
 }
@@ -283,6 +374,9 @@
 	inputDelegate = nil;
 	inputView = [[TextInputHandler alloc] initWithKeyboard:self];
 	inputView.delegate = self;
+	inputView.clearsOnBeginEditing = YES;
+	[inputView layoutIfNeeded];
+
 #if TARGET_OS_IOS
 	[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(prepareKeyboard:) name:UIKeyboardWillShowNotification object:nil];
 #endif
@@ -294,7 +388,7 @@
 	[super dealloc];
 }
 
-- (BOOL)textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text {
+- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)text {
 	unichar c;
 	if (text.length) {
 		c = [text characterAtIndex:0];
@@ -306,7 +400,14 @@
 	return YES;
 }
 
-- (UITextView *)inputView {
+- (void)textFieldDidBeginEditing:(UITextField *)textField {
+	[inputView attachAccessoryView];
+}
+- (void)textFieldDidEndEditing:(UITextField *)textField {
+	[inputView detachAccessoryView];
+}
+
+-(UITextField *)inputView {
 	return inputView;
 }
 
diff --git a/backends/platform/ios7/ios7_osys_video.mm b/backends/platform/ios7/ios7_osys_video.mm
index 7d7830b4655..53026d0b857 100644
--- a/backends/platform/ios7/ios7_osys_video.mm
+++ b/backends/platform/ios7/ios7_osys_video.mm
@@ -587,9 +587,18 @@ void OSystem_iOS7::updateMouseTexture() {
 
 void OSystem_iOS7::setShowKeyboard(bool show) {
 	if (show) {
+#if TARGET_OS_IOS
 		execute_on_main_thread(^ {
 			[[iOS7AppDelegate iPhoneView] showKeyboard];
 		});
+#elif TARGET_OS_TV
+		// Delay the showing of keyboard 1 second so the user
+		// is able to see the message
+		dispatch_time_t delay = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1.0 * NSEC_PER_SEC));
+		dispatch_after(delay, dispatch_get_main_queue(), ^(void){
+			[[iOS7AppDelegate iPhoneView] showKeyboard];
+		});
+#endif
 	} else {
 		// Do not hide the keyboard in portrait mode as it is shown automatically and not
 		// just when asked with the kFeatureVirtualKeyboard.


Commit: 14ee8b07d35f1cc31adc6fae3d1ad4803a412d48
    https://github.com/scummvm/scummvm/commit/14ee8b07d35f1cc31adc6fae3d1ad4803a412d48
Author: Lars Sundström (l.sundstrom at gmail.com)
Date: 2023-01-29T21:13:51Z

Commit Message:
IOS7: Forward backward key presses when textField is empty

There's a difference between UITextFields and UITextViews that the
delegate function textView:shouldChangeTextInRange:replacementText:
is called when pressing the backward button on a keyboard also when
the textView is empty. This is not the case for UITextFields, the
function textField:shouldChangeTextInRange:replacementText: is not
called if the textField is empty which is problematic in the cases
where there's already text in the open dialog (e.g. the save dialog
when the user wants to overwrite an existing slot). There's currently
no possibility to propagate existing text elements from dialog into
the textField. To be able to handle the cases where the user wants to
delete existing texts when the textField is empty the inputView has
to implement the UITextInput protocol function deleteBackward that is
called every time the backward key is pressed.

Changed paths:
    backends/platform/ios7/ios7_keyboard.mm


diff --git a/backends/platform/ios7/ios7_keyboard.mm b/backends/platform/ios7/ios7_keyboard.mm
index 5db19e1a02d..632eb14e7c4 100644
--- a/backends/platform/ios7/ios7_keyboard.mm
+++ b/backends/platform/ios7/ios7_keyboard.mm
@@ -28,7 +28,7 @@
 - (void)setEnablesReturnKeyAutomatically:(BOOL)val;
 @end
 
- at interface TextInputHandler : UITextField<UITabBarDelegate> {
+ at interface TextInputHandler : UITextField<UITabBarDelegate, UITextInput> {
 	SoftKeyboard *softKeyboard;
 	UITabBar *toolbar;
 	UIScrollView *scrollView;
@@ -147,6 +147,34 @@
 	[super dealloc];
 }
 
+/* There's a difference between UITextFields and UITextViews that the
+ * delegate function textView:shouldChangeTextInRange:replacementText:
+ * is called when pressing the backward button on a keyboard also when
+ * the textView is empty. This is not the case for UITextFields, the
+ * function textField:shouldChangeTextInRange:replacementText: is not
+ * called if the textField is empty which is problematic in the cases
+ * where there's already text in the open dialog (e.g. the save dialog
+ * when the user wants to overwrite an existing slot). There's currently
+ * no possibility to propagate existing text elements from dialog into
+ * the textField. To be able to handle the cases where the user wants to
+ * delete existing texts when the textField is empty the inputView has
+ * to implement the UITextInput protocol function deleteBackward that is
+ * called every time the backward key is pressed. */
+-(void)deleteBackward {
+	if ([self hasText]) {
+		/* If the textField has text the backward key presses will be
+		 * forwarded to the EventManager in the delegate function
+		 * textField:shouldChangeTextInRange:replacementText:
+		 * call the super class to delete characters in the textField */
+		[super deleteBackward];
+	} else {
+		/* Forward the key press to the EventManager also in the cases
+		 * where the textField is empty to remove prefilled characters
+		 * in dialogs. */
+		[softKeyboard handleKeyPress:'\b'];
+	}
+}
+
 -(void)selectUITabBarItem:(UITapGestureRecognizer *)recognizer {
 	switch ([[toolbar selectedItem] tag]) {
 	case 1:


Commit: 3dae4b033ecf0c2e814dc9a4dbc74e3d04391cd5
    https://github.com/scummvm/scummvm/commit/3dae4b033ecf0c2e814dc9a4dbc74e3d04391cd5
Author: Lars Sundström (l.sundstrom at gmail.com)
Date: 2023-01-29T21:13:51Z

Commit Message:
IOS7: Replace UIAlertView with UIAlertAction

The UIAlertView was deprecated in iOS 9 and therefore not supported in
tvOS. Replace the UIAlertView with the suggested UIAlertAction, which is
supported by both iOS and tvOS.

Define a macro to find the root view controller of a view. Use the view
controller of the iPhoneView to present the alert.

Changed paths:
    backends/platform/ios7/ios7_osys_video.mm


diff --git a/backends/platform/ios7/ios7_osys_video.mm b/backends/platform/ios7/ios7_osys_video.mm
index 53026d0b857..7278c877134 100644
--- a/backends/platform/ios7/ios7_osys_video.mm
+++ b/backends/platform/ios7/ios7_osys_video.mm
@@ -28,32 +28,29 @@
 #include "graphics/blit.h"
 #include "backends/platform/ios7/ios7_app_delegate.h"
 
-#if TARGET_OS_IOS
- at interface iOS7AlertHandler : NSObject<UIAlertViewDelegate>
- at end
-
- at implementation iOS7AlertHandler
+#define UIViewParentController(__view) ({ \
+	UIResponder *__responder = __view; \
+	while ([__responder isKindOfClass:[UIView class]]) \
+		__responder = [__responder nextResponder]; \
+	(UIViewController *)__responder; \
+})
 
-- (void)alertView:(UIAlertView *)alertView willDismissWithButtonIndex:(NSInteger)buttonIndex {
-	OSystem_iOS7::sharedInstance()->quit();
-	abort();
-}
+static void displayAlert(void *ctx) {
+	UIAlertController* alert = [UIAlertController alertControllerWithTitle:@"Fatal Error"
+								message:[NSString stringWithCString:(const char *)ctx 	encoding:NSUTF8StringEncoding]
+								preferredStyle:UIAlertControllerStyleAlert];
 
- at end
+	UIAlertAction* defaultAction = [UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleDefault
+	   handler:^(UIAlertAction * action) {
+		OSystem_iOS7::sharedInstance()->quit();
+		abort();
+	}];
 
-static void displayAlert(void *ctx) {
-	UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Fatal Error"
-	                                                message:[NSString stringWithCString:(const char *)ctx encoding:NSUTF8StringEncoding]
-	                                               delegate:[[iOS7AlertHandler alloc] init]
-	                                      cancelButtonTitle:@"OK"
-	                                      otherButtonTitles:nil];
-	[alert show];
-	[alert autorelease];
+	[alert addAction:defaultAction];
+	[UIViewParentController([iOS7AppDelegate iPhoneView]) presentViewController:alert animated:YES completion:nil];
 }
-#endif
 
 void OSystem_iOS7::fatalError() {
-#if TARGET_OS_IOS
 	if (_lastErrorMessage.size()) {
 		dispatch_async_f(dispatch_get_main_queue(), (void *)_lastErrorMessage.c_str(), displayAlert);
 		for(;;);
@@ -61,7 +58,6 @@ void OSystem_iOS7::fatalError() {
 	else {
 		OSystem::fatalError();
 	}
-#endif
 }
 
 void OSystem_iOS7::logMessage(LogMessageType::Type type, const char *message) {


Commit: 8a2a6aa19795da35d9952045ae4c6be3cfaf6aa7
    https://github.com/scummvm/scummvm/commit/8a2a6aa19795da35d9952045ae4c6be3cfaf6aa7
Author: Lars Sundström (l.sundstrom at gmail.com)
Date: 2023-01-29T21:13:51Z

Commit Message:
IOS7: Show inputAccessoryView when hardware keyboad is connected

The inputAccessoryView is only shown if no hardware keyboard is
connected. Some hardware keyboards doesn't necessary have all keys,
e.g. the Apple magic keyboard to the iPads which lacks the escape
key and all function keys.

To give the user the possibility to use these buttons, always show
the inputAccessoryView.

Changed paths:
    backends/platform/ios7/ios7_keyboard.h
    backends/platform/ios7/ios7_keyboard.mm


diff --git a/backends/platform/ios7/ios7_keyboard.h b/backends/platform/ios7/ios7_keyboard.h
index 7efcb84ebc5..d33cdc980e7 100644
--- a/backends/platform/ios7/ios7_keyboard.h
+++ b/backends/platform/ios7/ios7_keyboard.h
@@ -39,7 +39,6 @@
 - (void)handleKeyPress:(unichar)c;
 - (void)handleMainMenuKey;
 
-- (void)prepareKeyboard:(NSNotification *)notification;
 - (void)showKeyboard;
 - (void)hideKeyboard;
 
diff --git a/backends/platform/ios7/ios7_keyboard.mm b/backends/platform/ios7/ios7_keyboard.mm
index 632eb14e7c4..95d5460b7a1 100644
--- a/backends/platform/ios7/ios7_keyboard.mm
+++ b/backends/platform/ios7/ios7_keyboard.mm
@@ -405,9 +405,6 @@
 	inputView.clearsOnBeginEditing = YES;
 	[inputView layoutIfNeeded];
 
-#if TARGET_OS_IOS
-	[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(prepareKeyboard:) name:UIKeyboardWillShowNotification object:nil];
-#endif
 	return self;
 }
 
@@ -451,23 +448,6 @@
 	[inputDelegate handleMainMenuKey];
 }
 
-- (void)prepareKeyboard:(NSNotification *)notification {
-#if TARGET_OS_IOS
-	// Check if a hardware keyboard is connected, and only show the accessory view if there isn't one.
-	// If there is a hardware keyboard, the software one will only contains the text assistance bar
-	// and will be small (less than 100 pt, but use a bit more in case it changes with future iOS versions).
-	// This only works with iOS 9 and above. For ealier version the keyboard size is fixed and instead it
-	// only shows part of the keyboard (which could be detected with the origin position, but that would
-	// depend on the current orientation and screen resolution).
-	NSDictionary* info = [notification userInfo];
-	CGRect keyboardEndFrame = [[info objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue];
-	if (keyboardEndFrame.size.height < 140)
-		[inputView detachAccessoryView];
-	else
-		[inputView attachAccessoryView];
-#endif
-}
-
 - (void)showKeyboard {
 	[inputView becomeFirstResponder];
 }


Commit: b2b2d2cf9f003f76f6c7da6be828299f291177f4
    https://github.com/scummvm/scummvm/commit/b2b2d2cf9f003f76f6c7da6be828299f291177f4
Author: Lars Sundström (l.sundstrom at gmail.com)
Date: 2023-01-29T21:13:51Z

Commit Message:
IOS7: Trigger joystick presses only once for buttons A and B

All buttons and triggers on MFi game controllers are pressure sensitive
which means that when pressing buttons the registered
valueChangedHandler function is called multiple times providing updates
on the pressure value the button is pressed with. This causes multiple
kInputJoystickButtonDown events to be sent to the EventManager.
In adventure games the pressure value is not relevant and could cause
problems for the user that it triggers multiple presses on e.g. the B
button which often is mapped to the right mouse button. In some games
a click on the right mouse button changes what action that should be
performed.

Keep track on if the joystick buttons A or B (often mapped as left and
right mouse buttons) are being pressed. If the button is already
pressed do not add a new event until the button isn't pressed anymore.

To not interfere with any open dialog, don't send key events while the
keyboard is visible.

Changed paths:
    backends/platform/ios7/ios7_game_controller.mm


diff --git a/backends/platform/ios7/ios7_game_controller.mm b/backends/platform/ios7/ios7_game_controller.mm
index 1c0c365ad6b..4c17e058c0f 100644
--- a/backends/platform/ios7/ios7_game_controller.mm
+++ b/backends/platform/ios7/ios7_game_controller.mm
@@ -117,7 +117,30 @@
 }
 
 - (void)handleJoystickButtonAction:(int)button isPressed:(bool)pressed {
-	[view addEvent:InternalEvent(pressed ? kInputJoystickButtonDown : kInputJoystickButtonUp, button, 0)];
+	bool addEvent = true;
+	if (button == Common::JOYSTICK_BUTTON_A) {
+		if (_firstButtonPressed) {
+			if (pressed) {
+				addEvent = false;
+			}
+		}
+		_firstButtonPressed = pressed;
+	} else if (button == Common::JOYSTICK_BUTTON_B) {
+		if (_secondButtonPressed) {
+			if (pressed) {
+				addEvent = false;
+			}
+		}
+		_secondButtonPressed = pressed;
+	}
+	// Do not send button presses if keyboard is shown because if e.g.
+	// the "Do you want to quit?" dialog is shown the wait for user
+	// input will end (treating the button push as a mouse click) while
+	// the user tried to select the "y" or "n" character on the tvOS
+	// keyboard.
+	if (addEvent && ![view isKeyboardShown]) {
+		[view addEvent:InternalEvent(pressed ? kInputJoystickButtonDown : kInputJoystickButtonUp, button, 0)];
+	}
 }
 
 @end


Commit: 4c0cd6f2ebd574362a0376e6ce1dff20ccc9b23f
    https://github.com/scummvm/scummvm/commit/4c0cd6f2ebd574362a0376e6ce1dff20ccc9b23f
Author: Lars Sundström (l.sundstrom at gmail.com)
Date: 2023-01-29T21:13:51Z

Commit Message:
IOS7: Check keyboard visible if inputView being first responder

The keyboard can be presented and dismissed without being triggered by
the showKeyboard/hideKeyboard functions e.g. by pressing the menu button
on the Apple TV remote while the keyboard is shown.
If the keyboard visibility is not set entirely by the showKeyboard/
hideKeyboard functions that means that the _keyboardVisible state
variable can be out of sync.

Check if the keyboard is shown based on if the inputView is the first
responder or not. The check has to be made on the main thread.

Changed paths:
    backends/platform/ios7/ios7_keyboard.h
    backends/platform/ios7/ios7_keyboard.mm
    backends/platform/ios7/ios7_osys_video.mm
    backends/platform/ios7/ios7_video.h
    backends/platform/ios7/ios7_video.mm


diff --git a/backends/platform/ios7/ios7_keyboard.h b/backends/platform/ios7/ios7_keyboard.h
index d33cdc980e7..3e6f7c7930c 100644
--- a/backends/platform/ios7/ios7_keyboard.h
+++ b/backends/platform/ios7/ios7_keyboard.h
@@ -41,6 +41,7 @@
 
 - (void)showKeyboard;
 - (void)hideKeyboard;
+- (BOOL)isKeyboardShown;
 
 @end
 
diff --git a/backends/platform/ios7/ios7_keyboard.mm b/backends/platform/ios7/ios7_keyboard.mm
index 95d5460b7a1..a20568eb767 100644
--- a/backends/platform/ios7/ios7_keyboard.mm
+++ b/backends/platform/ios7/ios7_keyboard.mm
@@ -456,4 +456,7 @@
 	[inputView endEditing:YES];
 }
 
+- (BOOL)isKeyboardShown {
+	return [inputView isFirstResponder];
+}
 @end
diff --git a/backends/platform/ios7/ios7_osys_video.mm b/backends/platform/ios7/ios7_osys_video.mm
index 7278c877134..f7cef30905e 100644
--- a/backends/platform/ios7/ios7_osys_video.mm
+++ b/backends/platform/ios7/ios7_osys_video.mm
@@ -607,5 +607,9 @@ void OSystem_iOS7::setShowKeyboard(bool show) {
 }
 
 bool OSystem_iOS7::isKeyboardShown() const {
-	return [[iOS7AppDelegate iPhoneView] isKeyboardShown];
+	__block bool isShown = false;
+	execute_on_main_thread(^{
+		isShown = [[iOS7AppDelegate iPhoneView] isKeyboardShown];
+	});
+	return isShown;
 }
diff --git a/backends/platform/ios7/ios7_video.h b/backends/platform/ios7/ios7_video.h
index e909f914f7b..2fc85651e1f 100644
--- a/backends/platform/ios7/ios7_video.h
+++ b/backends/platform/ios7/ios7_video.h
@@ -47,7 +47,6 @@ typedef struct {
 	Common::List<InternalEvent> _events;
 	NSLock *_eventLock;
 	SoftKeyboard *_keyboardView;
-	BOOL _keyboardVisible;
 	Common::List<GameController*> _controllers;
 
 	UIBackgroundTaskIdentifier _backgroundSaveStateTask;
diff --git a/backends/platform/ios7/ios7_video.mm b/backends/platform/ios7/ios7_video.mm
index cfdfcb14657..c58476c41bb 100644
--- a/backends/platform/ios7/ios7_video.mm
+++ b/backends/platform/ios7/ios7_video.mm
@@ -468,7 +468,6 @@ uint getSizeNextPOT(uint size) {
 	[self setContentScaleFactor:[[UIScreen mainScreen] scale]];
 
 	_keyboardView = nil;
-	_keyboardVisible = NO;
 	_screenTexture = 0;
 	_overlayTexture = 0;
 	_mouseCursorTexture = 0;
@@ -903,16 +902,14 @@ uint getSizeNextPOT(uint size) {
 
 - (void)showKeyboard {
 	[_keyboardView showKeyboard];
-	_keyboardVisible = YES;
 }
 
 - (void)hideKeyboard {
 	[_keyboardView hideKeyboard];
-	_keyboardVisible = NO;
 }
 
 - (BOOL)isKeyboardShown {
-	return _keyboardVisible;
+	return [_keyboardView isKeyboardShown];
 }
 
 - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {


Commit: 770ab0ca50e4fe9c8727b00a6a65e1e817943177
    https://github.com/scummvm/scummvm/commit/770ab0ca50e4fe9c8727b00a6a65e1e817943177
Author: Lars Sundström (l.sundstrom at gmail.com)
Date: 2023-01-29T21:13:52Z

Commit Message:
IOS7: Suspend application if menu key pressed and no game is running

Add isInGame property to track if the launcher is shown of if a game is
running. Handle press on menu key different depending on if launcher is
shown or not. If launcher is shown suspend the application to return to
Apple TV Home Screen since that is the parent view of the launcher. If
in game pause the game and show menu. This is according to Apple
guidelines which can ge read here:
https://developer.apple.com/design/human-interface-guidelines/inputs/remotes

Changed paths:
    backends/platform/ios7/ios7_osys_video.mm
    backends/platform/ios7/ios7_video.h
    backends/platform/ios7/ios7_video.mm


diff --git a/backends/platform/ios7/ios7_osys_video.mm b/backends/platform/ios7/ios7_osys_video.mm
index f7cef30905e..44a37e07016 100644
--- a/backends/platform/ios7/ios7_osys_video.mm
+++ b/backends/platform/ios7/ios7_osys_video.mm
@@ -84,6 +84,7 @@ void OSystem_iOS7::engineInit() {
 	dispatch_async(dispatch_get_main_queue(), ^{
 		[[UIApplication sharedApplication] setIdleTimerDisabled:YES];
 	});
+	[[iOS7AppDelegate iPhoneView] setIsInGame:YES];
 }
 
 void OSystem_iOS7::engineDone() {
@@ -92,6 +93,7 @@ void OSystem_iOS7::engineDone() {
 	dispatch_async(dispatch_get_main_queue(), ^{
 		[[UIApplication sharedApplication] setIdleTimerDisabled:NO];
 	});
+	[[iOS7AppDelegate iPhoneView] setIsInGame:NO];
 }
 
 void OSystem_iOS7::initVideoContext() {
diff --git a/backends/platform/ios7/ios7_video.h b/backends/platform/ios7/ios7_video.h
index 2fc85651e1f..dbada0670c3 100644
--- a/backends/platform/ios7/ios7_video.h
+++ b/backends/platform/ios7/ios7_video.h
@@ -91,6 +91,7 @@ typedef struct {
 }
 
 @property (nonatomic, assign) CGPoint pointerPosition;
+ at property (nonatomic, assign) BOOL isInGame;
 
 - (id)initWithFrame:(struct CGRect)frame;
 
diff --git a/backends/platform/ios7/ios7_video.mm b/backends/platform/ios7/ios7_video.mm
index c58476c41bb..fe401a7fd94 100644
--- a/backends/platform/ios7/ios7_video.mm
+++ b/backends/platform/ios7/ios7_video.mm
@@ -1050,7 +1050,11 @@ uint getSizeNextPOT(uint size) {
 }
 
 - (void)handleMainMenuKey {
-	[self addEvent:InternalEvent(kInputMainMenu, 0, 0)];
+	if ([self isInGame]) {
+		[self addEvent:InternalEvent(kInputMainMenu, 0, 0)];
+	} else {
+		[[UIApplication sharedApplication] performSelector:@selector(suspend)];
+	}
 }
 
 - (void)applicationSuspend {


Commit: fde0aa965d2ee3390fd7f4970a1cf74dc3f6da1f
    https://github.com/scummvm/scummvm/commit/fde0aa965d2ee3390fd7f4970a1cf74dc3f6da1f
Author: Lars Sundström (l.sundstrom at gmail.com)
Date: 2023-01-29T21:13:52Z

Commit Message:
IOS7: Add general handling of the menu button on game controllers

Expose the handleMainMenuKey function and call that when pressing the
menu button on game controllers.

Changed paths:
    backends/platform/ios7/ios7_game_controller.h
    backends/platform/ios7/ios7_game_controller.mm
    backends/platform/ios7/ios7_gamepad_controller.mm
    backends/platform/ios7/ios7_video.h


diff --git a/backends/platform/ios7/ios7_game_controller.h b/backends/platform/ios7/ios7_game_controller.h
index f219710cd66..7a061d1f8c0 100644
--- a/backends/platform/ios7/ios7_game_controller.h
+++ b/backends/platform/ios7/ios7_game_controller.h
@@ -50,6 +50,7 @@ typedef enum {
 - (void)handleJoystickAxisMotionX:(int)x andY:(int)y forJoystick:(GameControllerJoystick)joystick;
 - (void)handleJoystickButtonAction:(int)button isPressed:(bool)pressed;
 
+- (void)handleMainMenu:(BOOL)pressed;
 @end
 
 #endif /* BACKENDS_PLATFORM_IOS7_IOS7_GAME_CONTROLLER_H */
diff --git a/backends/platform/ios7/ios7_game_controller.mm b/backends/platform/ios7/ios7_game_controller.mm
index 4c17e058c0f..35af7994c65 100644
--- a/backends/platform/ios7/ios7_game_controller.mm
+++ b/backends/platform/ios7/ios7_game_controller.mm
@@ -143,4 +143,9 @@
 	}
 }
 
+- (void)handleMainMenu:(BOOL)pressed {
+	if (!pressed) { // released
+		[view handleMainMenuKey];
+	}
+}
 @end
diff --git a/backends/platform/ios7/ios7_gamepad_controller.mm b/backends/platform/ios7/ios7_gamepad_controller.mm
index 9f3c0826109..75b26a71903 100644
--- a/backends/platform/ios7/ios7_gamepad_controller.mm
+++ b/backends/platform/ios7/ios7_gamepad_controller.mm
@@ -60,6 +60,12 @@
 			// Map button X to button B because B is mapped to left button
 			[self handleJoystickButtonAction:Common::JOYSTICK_BUTTON_B isPressed:pressed];
 		};
+
+		if (@available(iOS 13.0, tvOS 13.0, *)) {
+			_controller.microGamepad.buttonMenu.valueChangedHandler = ^(GCControllerButtonInput * _Nonnull button, float value, BOOL pressed) {
+				[self handleMainMenu:pressed];
+			};
+		}
 	}
 #endif
 	if (_controller.extendedGamepad != nil) {
@@ -116,6 +122,14 @@
 		_controller.extendedGamepad.rightShoulder.valueChangedHandler = ^(GCControllerButtonInput * _Nonnull button, float value, BOOL pressed) {
 			[self handleJoystickButtonAction:Common::JOYSTICK_BUTTON_RIGHT_SHOULDER isPressed:pressed];
 		};
+
+#ifdef __IPHONE_13_0
+		if (@available(iOS 13.0, tvOS 13.0, *)) {
+			_controller.extendedGamepad.buttonMenu.valueChangedHandler = ^(GCControllerButtonInput * _Nonnull button, float value, BOOL pressed) {
+				[self handleMainMenu:pressed];
+			};
+		}
+#endif
 	}
 }
 
diff --git a/backends/platform/ios7/ios7_video.h b/backends/platform/ios7/ios7_video.h
index dbada0670c3..70b44569f1e 100644
--- a/backends/platform/ios7/ios7_video.h
+++ b/backends/platform/ios7/ios7_video.h
@@ -121,6 +121,8 @@ typedef struct {
 - (void)hideKeyboard;
 - (BOOL)isKeyboardShown;
 
+- (void)handleMainMenuKey;
+
 - (void)applicationSuspend;
 - (void)applicationResume;
 


Commit: 235ebcbfb8c9245d8cb36b4a3af9907fb039ce80
    https://github.com/scummvm/scummvm/commit/235ebcbfb8c9245d8cb36b4a3af9907fb039ce80
Author: Lars Sundström (l.sundstrom at gmail.com)
Date: 2023-01-29T21:13:52Z

Commit Message:
IOS7: Fix compiler warnings

This commit fixes the compiler warnings regarding:
- The local declaration of 'view' hides instance variable [-Wshadow-ivar]
- Some of the gamepad controller buttons is only available in specific
versions of iOS and tvOS.
- Use of non-standard escape character '\E'. \E is a GNU shortcut.

Changed paths:
    backends/platform/ios7/ios7_game_controller.h
    backends/platform/ios7/ios7_game_controller.mm
    backends/platform/ios7/ios7_gamepad_controller.mm
    backends/platform/ios7/ios7_video.mm


diff --git a/backends/platform/ios7/ios7_game_controller.h b/backends/platform/ios7/ios7_game_controller.h
index 7a061d1f8c0..21d03b04ebb 100644
--- a/backends/platform/ios7/ios7_game_controller.h
+++ b/backends/platform/ios7/ios7_game_controller.h
@@ -43,7 +43,7 @@ typedef enum {
 @property (nonatomic, readwrite, retain) iPhoneView *view;
 @property (nonatomic, assign) BOOL isConnected;
 
-- (id)initWithView:(iPhoneView *)view;
+- (id)initWithView:(iPhoneView *)v;
 
 - (void)handlePointerMoveTo:(CGPoint)point;
 - (void)handleMouseButtonAction:(GameControllerMouseButton)button isPressed:(bool)pressed at:(CGPoint)point;
diff --git a/backends/platform/ios7/ios7_game_controller.mm b/backends/platform/ios7/ios7_game_controller.mm
index 35af7994c65..0695df281a8 100644
--- a/backends/platform/ios7/ios7_game_controller.mm
+++ b/backends/platform/ios7/ios7_game_controller.mm
@@ -35,10 +35,10 @@
 
 @synthesize view;
 
-- (id)initWithView:(iPhoneView *)view {
+- (id)initWithView:(iPhoneView *)v {
 	self = [super init];
 	if (self) {
-		[self setView:view];
+		[self setView:v];
 	}
 	_firstButtonPressed = _secondButtonPressed = NO;
 	return self;
diff --git a/backends/platform/ios7/ios7_gamepad_controller.mm b/backends/platform/ios7/ios7_gamepad_controller.mm
index 75b26a71903..07af27f7d34 100644
--- a/backends/platform/ios7/ios7_gamepad_controller.mm
+++ b/backends/platform/ios7/ios7_gamepad_controller.mm
@@ -107,13 +107,17 @@
 			[self handleJoystickButtonAction:Common::JOYSTICK_BUTTON_Y isPressed:pressed];
 		};
 #ifdef __IPHONE_12_1
-		_controller.extendedGamepad.leftThumbstickButton.valueChangedHandler = ^(GCControllerButtonInput * _Nonnull button, float value, BOOL pressed) {
-			[self handleJoystickButtonAction:Common::JOYSTICK_BUTTON_LEFT_STICK isPressed:pressed];
-		};
+		if (@available(iOS 12.1, tvOS 12.1, *)) {
+			_controller.extendedGamepad.leftThumbstickButton.valueChangedHandler = ^(GCControllerButtonInput * _Nonnull button, float value, BOOL pressed) {
+				[self handleJoystickButtonAction:Common::JOYSTICK_BUTTON_LEFT_STICK isPressed:pressed];
+			};
+		}
 
-		_controller.extendedGamepad.rightThumbstickButton.valueChangedHandler = ^(GCControllerButtonInput * _Nonnull button, float value, BOOL pressed) {
-			[self handleJoystickButtonAction:Common::JOYSTICK_BUTTON_RIGHT_STICK isPressed:pressed];
-		};
+		if (@available(iOS 12.1, tvOS 12.1, *)) {
+			_controller.extendedGamepad.rightThumbstickButton.valueChangedHandler = ^(GCControllerButtonInput * _Nonnull button, float value, BOOL pressed) {
+				[self handleJoystickButtonAction:Common::JOYSTICK_BUTTON_RIGHT_STICK isPressed:pressed];
+			};
+		}
 #endif
 		_controller.extendedGamepad.leftShoulder.valueChangedHandler = ^(GCControllerButtonInput * _Nonnull button, float value, BOOL pressed) {
 			[self handleJoystickButtonAction:Common::JOYSTICK_BUTTON_LEFT_SHOULDER isPressed:pressed];
diff --git a/backends/platform/ios7/ios7_video.mm b/backends/platform/ios7/ios7_video.mm
index fe401a7fd94..bb9feb45eb6 100644
--- a/backends/platform/ios7/ios7_video.mm
+++ b/backends/platform/ios7/ios7_video.mm
@@ -1043,7 +1043,7 @@ uint getSizeNextPOT(uint size) {
 
 - (void)handleKeyPress:(unichar)c {
 	if (c == '`') {
-		[self addEvent:InternalEvent(kInputKeyPressed, '\E', 0)];
+		[self addEvent:InternalEvent(kInputKeyPressed, '\033', 0)];
 	} else {
 		[self addEvent:InternalEvent(kInputKeyPressed, c, 0)];
 	}


Commit: dec343730e0005ae82d0a0c9886b4bd3ea8c1fb8
    https://github.com/scummvm/scummvm/commit/dec343730e0005ae82d0a0c9886b4bd3ea8c1fb8
Author: Le Philousophe (lephilousophe at users.noreply.github.com)
Date: 2023-01-29T21:13:52Z

Commit Message:
IOS7: Add AppleTV support to configure

Changed paths:
    configure
    dists/tvos/Info.plist
    dists/tvos/Info.plist.in
    ports.mk


diff --git a/configure b/configure
index f27bd05acea..c84791f0424 100755
--- a/configure
+++ b/configure
@@ -849,6 +849,7 @@ Special configuration feature:
                                            psp for PlayStation Portable
                                            samsungtv for Samsung TV
                                            switch for Nintendo Switch
+										   tvos for Apple TV (tvOS 9.0+)
                                            wasm32-unknown-emscripten for WebAssembly
                                            wii for Nintendo Wii
 
@@ -1728,6 +1729,12 @@ switch)
 	datadir='${datarootdir}'
 	docdir='${prefix}/doc'
 	;;
+tvos)
+	_host_os=iphone
+	# Remains of configure not knowing about arm64
+	_host_cpu=aarch64
+	_host_alias=arm64-apple-darwin11
+	;;
 wasm32-*)
 	_endian=little # the endian check below fails, but emscripten is always little endian anyway
 	_host_os=emscripten
@@ -3710,6 +3717,13 @@ if test -n "$_host"; then
 			_mt32emu=no
 			_port_mk="backends/platform/psp/psp.mk"
 			;;
+		tvos)
+			add_line_to_config_mk 'IPHONE = 1'
+			append_var DEFINES "-DIPHONE -DIPHONE_IOS7 -DIPHONE_SANDBOXED"
+			_backend="ios7"
+			_seq_midi=no
+			_timidity=no
+			;;
 		samsungtv)
 			append_var DEFINES "-DSAMSUNGTV"
 			append_var DEFINES "-DDISABLE_COMMAND_LINE"
@@ -3813,7 +3827,11 @@ case $_backend in
 		append_var LIBS "-framework QuartzCore -framework CoreFoundation -framework Foundation"
 		append_var LIBS "-framework AudioToolbox -framework CoreAudio -framework SystemConfiguration "
 		append_var LIBS "-framework GameController"
-		if test "$_host_cpu" = 'aarch64' ; then
+		if test "$_host" = 'tvos'; then
+			append_var LDFLAGS "-mtvos-version-min=9 -arch arm64"
+			append_var CFLAGS "-mtvos-version-min=9 -arch arm64"
+			append_var CXXFLAGS "-mtvos-version-min=9 -arch arm64"
+		elif test "$_host_cpu" = 'aarch64' ; then
 			append_var LDFLAGS "-miphoneos-version-min=7.1 -arch arm64"
 			append_var CFLAGS "-miphoneos-version-min=7.1 -arch arm64"
 			append_var CXXFLAGS "-miphoneos-version-min=7.1 -arch arm64"
diff --git a/dists/tvos/Info.plist b/dists/tvos/Info.plist
index 394b91bc925..b32a3444b08 100644
--- a/dists/tvos/Info.plist
+++ b/dists/tvos/Info.plist
@@ -46,7 +46,7 @@
 	<key>UILaunchImages</key>
 	<array/>
 	<key>UILaunchStoryboardName</key>
-	<string></string>
+	<string>LaunchScreen_tvos</string>
 	<key>UIPrerenderedIcon</key>
 	<true/>
 	<key>UIRequiresFullScreen</key>
diff --git a/dists/tvos/Info.plist.in b/dists/tvos/Info.plist.in
index b32a3444b08..217894c02fd 100644
--- a/dists/tvos/Info.plist.in
+++ b/dists/tvos/Info.plist.in
@@ -17,11 +17,11 @@
 	<key>CFBundlePackageType</key>
 	<string>APPL</string>
 	<key>CFBundleShortVersionString</key>
-	<string>2.7.0git</string>
+	<string>@VERSION@</string>
 	<key>CFBundleSignature</key>
 	<string>????</string>
 	<key>CFBundleVersion</key>
-	<string>2.7.0git</string>
+	<string>@VERSION@</string>
 	<key>GCSupportedGameControllers</key>
 	<array>
 		<dict>
diff --git a/ports.mk b/ports.mk
index 03cfc299a6b..5b7d78a4a8b 100644
--- a/ports.mk
+++ b/ports.mk
@@ -239,22 +239,6 @@ ios7bundle: iphone
 			print "\t\t</dict>";\
 			print "\t</dict>";\
 			s=2}\
-		/<key>CFBundleIcons~ipad<\/key>/ {\
-			print $$0;\
-			print "\t<dict>";\
-			print "\t\t<key>CFBundlePrimaryIcon</key>";\
-			print "\t\t<dict>";\
-			print "\t\t\t<key>CFBundleIconFiles</key>";\
-			print "\t\t\t<array>";\
-			print "\t\t\t\t<string>AppIcon29x29</string>";\
-			print "\t\t\t\t<string>AppIcon40x40</string>";\
-			print "\t\t\t\t<string>AppIcon60x60</string>";\
-			print "\t\t\t\t<string>AppIcon76x76</string>";\
-			print "\t\t\t\t<string>AppIcon83.5x83.5</string>";\
-			print "\t\t\t</array>";\
-			print "\t\t</dict>";\
-			print "\t</dict>";\
-			s=2}\
 		/<key>UILaunchImages<\/key>/ {\
 			print $$0;\
 			print "\t<array>";\
@@ -359,6 +343,74 @@ endif
 	cp $(srcdir)/dists/ios7/Images.xcassets/LaunchImage.launchimage/ScummVM-splash-750x1334.png $(bundle_name)/LaunchImage-800-667h at 2x.png
 	codesign -s - --deep --force $(bundle_name)
 
+tvosbundle: iphone
+	mkdir -p $(bundle_name)
+	awk 'BEGIN {s=0}\
+		/<key>CFBundleIcons<\/key>/ {\
+			print $$0;\
+			print "\t<dict>";\
+			print "\t\t<key>CFBundlePrimaryIcon</key>";\
+			print "\t\t<string>App Icon</string>";\
+			print "\t</dict>";\
+			s=2}\
+		/<key>TVTopShelfImage<\/key>/ {\
+			print $$0;\
+			print "\t<dict>";\
+			print "\t\t<key>TVTopShelfPrimaryImageWide</key>";\
+			print "\t\t<string>Top Shelf Image</string>";\
+			print "\t\t<key>TVTopShelfPrimaryImage</key>";\
+			print "\t\t<string>Top Shelf Image Wide</string>";\
+			print "\t</dict>";\
+			s=2}\
+		/<key>UILaunchImages<\/key>/ {\
+			print $$0;\
+			print "\t<array>";\
+			print "\t\t<dict>";\
+			print "\t\t\t<key>UILaunchImageMinimumOSVersion</key>";\
+			print "\t\t\t<string>9.0</string>";\
+			print "\t\t\t<key>UILaunchImageName</key>";\
+			print "\t\t\t<string>LaunchImage</string>";\
+			print "\t\t\t<key>UILaunchImageOrientation</key>";\
+			print "\t\t\t<string>Landscape</string>";\
+			print "\t\t\t<key>UILaunchImageSize</key>";\
+			print "\t\t\t<string>{1920, 1080}</string>";\
+			print "\t\t</dict>";\
+			print "\t\t<dict>";\
+			print "\t\t\t<key>UILaunchImageMinimumOSVersion</key>";\
+			print "\t\t\t<string>11.0</string>";\
+			print "\t\t\t<key>UILaunchImageName</key>";\
+			print "\t\t\t<string>LaunchImage</string>";\
+			print "\t\t\t<key>UILaunchImageOrientation</key>";\
+			print "\t\t\t<string>Landscape</string>";\
+			print "\t\t\t<key>UILaunchImageSize</key>";\
+			print "\t\t\t<string>{1920, 1080}</string>";\
+			print "\t\t</dict>";\
+			print "\t</array>";\
+			s=2}\
+		s==0 {print $$0}\
+		s > 0 { s-- }' $(srcdir)/dists/tvos/Info.plist >$(bundle_name)/Info.plist
+	sed -i'' -e 's/$$(PRODUCT_BUNDLE_IDENTIFIER)/org.scummvm.scummvm/' $(bundle_name)/Info.plist
+	sed -i'' -e 's/$$(EXECUTABLE_NAME)/ScummVM/' $(bundle_name)/Info.plist
+	sed -i'' -e '/UILaunchStoryboardName/{N;d;}' $(bundle_name)/Info.plist
+	cp $(DIST_FILES_DOCS) $(bundle_name)/
+	cp $(DIST_FILES_THEMES) $(bundle_name)/
+ifdef DIST_FILES_NETWORKING
+	cp $(DIST_FILES_NETWORKING) $(bundle_name)/
+endif
+ifdef DIST_FILES_ENGINEDATA
+	cp $(DIST_FILES_ENGINEDATA) $(bundle_name)/
+endif
+ifdef DIST_FILES_VKEYBD
+	cp $(DIST_FILES_VKEYBD) $(bundle_name)/
+endif
+ifneq ($(DIST_FILES_SHADERS),)
+	cp $(DIST_FILES_SHADERS) $(bundle_name)/
+endif
+	$(STRIP) scummvm
+	chmod 755 scummvm
+	cp scummvm $(bundle_name)/ScummVM
+	cp -r $(srcdir)/dists/tvos/Assets.car $(bundle_name)/Assets.car
+	codesign -s - --deep --force $(bundle_name)
 
 ifndef WITHOUT_SDL
 OSX_STATIC_LIBS := `$(SDLCONFIG) --prefix=$(STATICLIBPATH) --static-libs`


Commit: 92b22e4ba644c0c54fd95337931dfa3a4abcf9b3
    https://github.com/scummvm/scummvm/commit/92b22e4ba644c0c54fd95337931dfa3a4abcf9b3
Author: Lars Sundström (l.sundstrom at gmail.com)
Date: 2023-01-29T21:13:52Z

Commit Message:
DOCS: Add draft documentation of Apple TV platform

Add basic documentation needed starting using or developing ScummVM on
the Apple TV.

Changed paths:
  A doc/docportal/other_platforms/tvos.rst


diff --git a/doc/docportal/other_platforms/tvos.rst b/doc/docportal/other_platforms/tvos.rst
new file mode 100644
index 00000000000..0f221bb7946
--- /dev/null
+++ b/doc/docportal/other_platforms/tvos.rst
@@ -0,0 +1,112 @@
+
+==============
+Apple TV OS
+==============
+
+---
+**NOTE**
+
+This page is under development. Only basic information is given to enable ScummVM on Apple TV.
+
+---
+
+This page contains all the information you need to get ScummVM up and running on an Apple TV.
+
+
+Installing ScummVM
+=====================
+There are two ways to install ScummVM on an Apple TV depending on if building the project or downloading a bundle.
+
+Building the project
+************************************
+
+Since the port for Apple TV shares the same code base as the iOS port the instructions for building the project is the same as for iOS. Follow the :doc:`./ios` with the differences that the `tvOS libraries <https://github.com/larsamannen/scummvm-tvos-libs-v1>`_ should be used instead and the ``ScummVM-tvOS`` target should be chosen in Xcode. Use the libraries in the ``appletv`` folder if building for real target and ``appletvsimulator`` if building for simulator. Note that the libraries are built without bitcode since it's not required since tvOS 16.
+
+Downloading and installing ScummVM
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Instructions will be added when packages are available for download.
+
+
+Transferring game files
+========================
+
+---
+**NOTE**
+
+Note that Apple TV applications doesn't have a ``Documents`` folder in which games can be stored. All games are stored in the ``cache`` folder which can be deleted when the system requires the needed space. This could happen if having limited available space and streaming high definition content or installing other applications. Please see https://developer.apple.com/library/archive/documentation/General/Conceptual/AppleTV_PG/OnDemandResources.html for more information.
+
+Make sure to make backups of savegames.
+
+---
+
+ScummVM has built-in cloud functionality, which lets you connect your Google Drive, OneDrive, Box or Dropbox account. For more information, see the :doc:`../use_scummvm/connect_cloud` page. ScummVM also has the ability to run a local web server. For more information, see the :doc:`../use_scummvm/LAN` page.
+
+.. note::
+
+ ScummVM's cloud functionality does not currently support iCloud, however you can upload game folders to your iCloud and then use the Files app on your iOS device to copy these folders into the local ScummVM folder.
+
+
+See :doc:`../use_scummvm/game_files` for more information about game file requirements.
+
+Controls
+============
+
+The Apple TV supports several controllers however no mouse support. External keyboards can be used to help entering text input. Usually the Apple TV remote controller will be used.
+
+Game controllers
+^^^^^^^^^^^^^^^^^^^^
+If running tvOS 14 and later there is support for connected gamepad controllers using the Apple Game Controller framework. "Micro Gamepad Controllers ""Extended Gamepad Controllers" are supported at the moment. For more information visit
+https://developer.apple.com/documentation/gamecontroller/gcmicrogamepad
+https://developer.apple.com/documentation/gamecontroller/gcextendedgamepad
+
+Key mappings on Apple TV remote (also remote app on iOS)
+^^^^^^^^^^^^^^^^^^^^
+
+.. csv-table::
+    :widths: 40 60
+    :header-rows: 1
+    :class: controls
+
+        Button, Action
+        Swipe on Touch area, Controls pointer
+        Press Touch area, Left mouse click
+        Play/Pause, Right mouse click
+        Back/Menu in game, Global Main menu
+        Back/Menu in launcher, Apple TV Home
+        Hold Play/Pause, Show keyboard with extra keys
+        Touch (not press) on top of Touch area, Up arrow key
+        Touch (not press) on left of Touch area, Left arrow key
+        Touch (not press) on right of Touch area, Right arrow key
+        Touch (not press) on bottom of Touch area, Down arrow key
+
+Key mappings on Extended gamepad controller
+^^^^^^^^^^^^^^^^^^^^
+
+.. csv-table::
+    :widths: 40 60
+    :header-rows: 1
+    :class: controls
+
+        Button, Action
+        Left analog joystick, Controls pointer
+        D-Pad, Up, Left, Right, Down arrow buttons
+        A, Left mouse click
+        B, Right mouse click
+        Hold X, Show keyboard with extra keys
+        Menu in game, Global Main menu
+        Menu in launcher, Apple TV Home
+        L1, show game original menu
+
+Paths
+=======
+
+Saved games
+**************
+
+``Savegames/`` in the cache root folder. Access this folder through :doc:`../use_scummvm/LAN`.
+
+Configuration file
+*********************
+
+``Preferences`` in the cache folder. Access this folder through :doc:`../use_scummvm/LAN`.




More information about the Scummvm-git-logs mailing list