Automatically uses external game controllers when connected
This commit is contained in:
parent
61440ef994
commit
a58835e3ad
@ -1 +1 @@
|
|||||||
Subproject commit ff014bab5c42e5c0a5fcbacb5c3c737ef33564e7
|
Subproject commit 6e0ec5aedac746d1a5ea05d450884f1a9ad7b509
|
||||||
@ -385,11 +385,14 @@ private extension GameViewController
|
|||||||
{
|
{
|
||||||
@objc func updateControllers()
|
@objc func updateControllers()
|
||||||
{
|
{
|
||||||
guard let emulatorCore = self.emulatorCore, let game = self.game else { return }
|
let isExternalGameControllerConnected = ExternalGameControllerManager.shared.connectedControllers.contains(where: { $0.playerIndex != nil })
|
||||||
|
if !isExternalGameControllerConnected && Settings.localControllerPlayerIndex == nil
|
||||||
|
{
|
||||||
|
Settings.localControllerPlayerIndex = 0
|
||||||
|
}
|
||||||
|
|
||||||
let controllers = [self.controllerView as GameController] + ExternalGameControllerManager.shared.connectedControllers
|
// If Settings.localControllerPlayerIndex is non-nil, and there isn't a connected controller with same playerIndex, show controller view.
|
||||||
|
if let index = Settings.localControllerPlayerIndex, !ExternalGameControllerManager.shared.connectedControllers.contains { $0.playerIndex == index }
|
||||||
if let index = Settings.localControllerPlayerIndex
|
|
||||||
{
|
{
|
||||||
self.controllerView.playerIndex = index
|
self.controllerView.playerIndex = index
|
||||||
self.controllerView.isHidden = false
|
self.controllerView.isHidden = false
|
||||||
@ -398,32 +401,39 @@ private extension GameViewController
|
|||||||
{
|
{
|
||||||
self.controllerView.playerIndex = nil
|
self.controllerView.playerIndex = nil
|
||||||
self.controllerView.isHidden = true
|
self.controllerView.isHidden = true
|
||||||
}
|
|
||||||
|
Settings.localControllerPlayerIndex = nil
|
||||||
for gameController in controllers
|
|
||||||
{
|
|
||||||
if gameController.playerIndex != nil
|
|
||||||
{
|
|
||||||
if let inputMapping = GameControllerInputMapping.inputMapping(for: gameController, gameType: game.type, in: DatabaseManager.shared.viewContext)
|
|
||||||
{
|
|
||||||
gameController.addReceiver(self, inputMapping: inputMapping)
|
|
||||||
gameController.addReceiver(emulatorCore, inputMapping: inputMapping)
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
gameController.addReceiver(self)
|
|
||||||
gameController.addReceiver(emulatorCore)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
gameController.removeReceiver(self)
|
|
||||||
gameController.removeReceiver(emulatorCore)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
self.view.setNeedsLayout()
|
self.view.setNeedsLayout()
|
||||||
self.view.layoutIfNeeded()
|
self.view.layoutIfNeeded()
|
||||||
|
|
||||||
|
if let emulatorCore = self.emulatorCore, let game = self.game
|
||||||
|
{
|
||||||
|
let controllers = [self.controllerView as GameController] + ExternalGameControllerManager.shared.connectedControllers
|
||||||
|
|
||||||
|
for gameController in controllers
|
||||||
|
{
|
||||||
|
if gameController.playerIndex != nil
|
||||||
|
{
|
||||||
|
if let inputMapping = GameControllerInputMapping.inputMapping(for: gameController, gameType: game.type, in: DatabaseManager.shared.viewContext)
|
||||||
|
{
|
||||||
|
gameController.addReceiver(self, inputMapping: inputMapping)
|
||||||
|
gameController.addReceiver(emulatorCore, inputMapping: inputMapping)
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
gameController.addReceiver(self)
|
||||||
|
gameController.addReceiver(emulatorCore)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
gameController.removeReceiver(self)
|
||||||
|
gameController.removeReceiver(emulatorCore)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func updateControllerSkin()
|
func updateControllerSkin()
|
||||||
@ -751,7 +761,7 @@ extension GameViewController
|
|||||||
|
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
if let quickSaveState = try fetchRequest.execute().first
|
if let quickSaveState = try DatabaseManager.shared.viewContext.fetch(fetchRequest).first
|
||||||
{
|
{
|
||||||
self.load(quickSaveState)
|
self.load(quickSaveState)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -22,7 +22,6 @@ extension ControllersSettingsViewController
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private class LocalDeviceController: NSObject, GameController
|
private class LocalDeviceController: NSObject, GameController
|
||||||
{
|
{
|
||||||
var name: String {
|
var name: String {
|
||||||
@ -49,8 +48,17 @@ class ControllersSettingsViewController: UITableViewController
|
|||||||
|
|
||||||
fileprivate var gameController: GameController? {
|
fileprivate var gameController: GameController? {
|
||||||
didSet {
|
didSet {
|
||||||
oldValue?.playerIndex = nil
|
// Order matters since localDeviceController changes Settings.localControllerPlayerIndex, which sends out NSNotification.
|
||||||
self.gameController?.playerIndex = self.playerIndex
|
if oldValue == self.localDeviceController
|
||||||
|
{
|
||||||
|
self.gameController?.playerIndex = self.playerIndex
|
||||||
|
oldValue?.playerIndex = nil
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
oldValue?.playerIndex = nil
|
||||||
|
self.gameController?.playerIndex = self.playerIndex
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -150,7 +158,7 @@ private extension ControllersSettingsViewController
|
|||||||
cell.accessoryType = .checkmark
|
cell.accessoryType = .checkmark
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if let playerIndex = controller.playerIndex
|
if let playerIndex = controller.playerIndex
|
||||||
{
|
{
|
||||||
cell.detailTextLabel?.text = NSLocalizedString("Player \(playerIndex + 1)", comment: "")
|
cell.detailTextLabel?.text = NSLocalizedString("Player \(playerIndex + 1)", comment: "")
|
||||||
@ -183,14 +191,29 @@ private extension ControllersSettingsViewController
|
|||||||
|
|
||||||
if let index = self.connectedControllers.index(where: { $0 == controller })
|
if let index = self.connectedControllers.index(where: { $0 == controller })
|
||||||
{
|
{
|
||||||
|
self.tableView.beginUpdates()
|
||||||
|
|
||||||
if self.connectedControllers.count == 1
|
if self.connectedControllers.count == 1
|
||||||
{
|
{
|
||||||
self.tableView.insertSections(IndexSet(integer: Section.externalControllers.rawValue), with: .fade)
|
self.tableView.insertSections(IndexSet(integer: Section.externalControllers.rawValue), with: .fade)
|
||||||
|
|
||||||
|
if self.connectedControllers.first?.playerIndex == self.playerIndex
|
||||||
|
{
|
||||||
|
self.tableView.insertSections(IndexSet(integer: Section.customizeControls.rawValue), with: .fade)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
self.tableView.insertRows(at: [IndexPath(row: index, section: Section.externalControllers.rawValue)], with: .automatic)
|
self.tableView.insertRows(at: [IndexPath(row: index, section: Section.externalControllers.rawValue)], with: .automatic)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
self.tableView.endUpdates()
|
||||||
|
}
|
||||||
|
|
||||||
|
if controller.playerIndex == self.playerIndex
|
||||||
|
{
|
||||||
|
self.tableView.reloadSections(IndexSet(integer: Section.none.rawValue), with: .none)
|
||||||
|
self.tableView.reloadSections(IndexSet(integer: Section.localDevice.rawValue), with: .none)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -202,19 +225,29 @@ private extension ControllersSettingsViewController
|
|||||||
{
|
{
|
||||||
self.connectedControllers.remove(at: index)
|
self.connectedControllers.remove(at: index)
|
||||||
|
|
||||||
|
self.tableView.beginUpdates()
|
||||||
|
|
||||||
if self.connectedControllers.count == 0
|
if self.connectedControllers.count == 0
|
||||||
{
|
{
|
||||||
self.tableView.deleteSections(IndexSet(integer: Section.externalControllers.rawValue), with: .fade)
|
self.tableView.deleteSections(IndexSet(integer: Section.externalControllers.rawValue), with: .fade)
|
||||||
|
|
||||||
|
if controller.playerIndex != nil
|
||||||
|
{
|
||||||
|
self.tableView.deleteSections(IndexSet(integer: Section.customizeControls.rawValue), with: .fade)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
self.tableView.deleteRows(at: [IndexPath(row: index, section: Section.externalControllers.rawValue)], with: .automatic)
|
self.tableView.deleteRows(at: [IndexPath(row: index, section: Section.externalControllers.rawValue)], with: .automatic)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
self.tableView.endUpdates()
|
||||||
}
|
}
|
||||||
|
|
||||||
if controller.playerIndex == self.playerIndex
|
if controller.playerIndex == self.playerIndex
|
||||||
{
|
{
|
||||||
self.tableView.reloadSections(IndexSet(integer: Section.none.rawValue), with: .none)
|
self.tableView.reloadSections(IndexSet(integer: Section.none.rawValue), with: .none)
|
||||||
|
self.tableView.reloadSections(IndexSet(integer: Section.localDevice.rawValue), with: .none)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -240,7 +273,7 @@ extension ControllersSettingsViewController
|
|||||||
{
|
{
|
||||||
switch Section(rawValue: section)!
|
switch Section(rawValue: section)!
|
||||||
{
|
{
|
||||||
case .none: return 1
|
case .none: return 0
|
||||||
case .localDevice: return 1
|
case .localDevice: return 1
|
||||||
case .externalControllers: return self.connectedControllers.count
|
case .externalControllers: return self.connectedControllers.count
|
||||||
case .customizeControls: return 1
|
case .customizeControls: return 1
|
||||||
@ -266,6 +299,16 @@ extension ControllersSettingsViewController
|
|||||||
case .customizeControls: return nil
|
case .customizeControls: return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat
|
||||||
|
{
|
||||||
|
if section == Section.none.rawValue
|
||||||
|
{
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
return UITableViewAutomaticDimension
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
extension ControllersSettingsViewController
|
extension ControllersSettingsViewController
|
||||||
@ -315,8 +358,7 @@ extension ControllersSettingsViewController
|
|||||||
}
|
}
|
||||||
|
|
||||||
self.tableView.reloadRows(at: [indexPath], with: .none)
|
self.tableView.reloadRows(at: [indexPath], with: .none)
|
||||||
|
|
||||||
|
|
||||||
if self.numberOfSections(in: self.tableView) > self.tableView.numberOfSections
|
if self.numberOfSections(in: self.tableView) > self.tableView.numberOfSections
|
||||||
{
|
{
|
||||||
self.tableView.insertSections(IndexSet(integer: Section.customizeControls.rawValue), with: .fade)
|
self.tableView.insertSections(IndexSet(integer: Section.customizeControls.rawValue), with: .fade)
|
||||||
|
|||||||
@ -40,12 +40,14 @@ struct Settings
|
|||||||
/// Controllers
|
/// Controllers
|
||||||
static var localControllerPlayerIndex: Int? = 0 {
|
static var localControllerPlayerIndex: Int? = 0 {
|
||||||
didSet {
|
didSet {
|
||||||
|
guard self.localControllerPlayerIndex != oldValue else { return }
|
||||||
NotificationCenter.default.post(name: .settingsDidChange, object: nil, userInfo: [NotificationUserInfoKey.name: Name.localControllerPlayerIndex])
|
NotificationCenter.default.post(name: .settingsDidChange, object: nil, userInfo: [NotificationUserInfoKey.name: Name.localControllerPlayerIndex])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static var translucentControllerSkinOpacity: CGFloat {
|
static var translucentControllerSkinOpacity: CGFloat {
|
||||||
set {
|
set {
|
||||||
|
guard newValue != self.translucentControllerSkinOpacity else { return }
|
||||||
UserDefaults.standard.translucentControllerSkinOpacity = newValue
|
UserDefaults.standard.translucentControllerSkinOpacity = newValue
|
||||||
NotificationCenter.default.post(name: .settingsDidChange, object: nil, userInfo: [NotificationUserInfoKey.name: Name.translucentControllerSkinOpacity])
|
NotificationCenter.default.post(name: .settingsDidChange, object: nil, userInfo: [NotificationUserInfoKey.name: Name.translucentControllerSkinOpacity])
|
||||||
}
|
}
|
||||||
@ -113,6 +115,9 @@ struct Settings
|
|||||||
static func setPreferredControllerSkin(_ controllerSkin: ControllerSkin, for system: System, traits: DeltaCore.ControllerSkin.Traits)
|
static func setPreferredControllerSkin(_ controllerSkin: ControllerSkin, for system: System, traits: DeltaCore.ControllerSkin.Traits)
|
||||||
{
|
{
|
||||||
guard let userDefaultKey = self.preferredControllerSkinKey(for: system, traits: traits) else { return }
|
guard let userDefaultKey = self.preferredControllerSkinKey(for: system, traits: traits) else { return }
|
||||||
|
|
||||||
|
guard UserDefaults.standard.string(forKey: userDefaultKey) != controllerSkin.identifier else { return }
|
||||||
|
|
||||||
UserDefaults.standard.set(controllerSkin.identifier, forKey: userDefaultKey)
|
UserDefaults.standard.set(controllerSkin.identifier, forKey: userDefaultKey)
|
||||||
|
|
||||||
NotificationCenter.default.post(name: .settingsDidChange, object: controllerSkin, userInfo: [NotificationUserInfoKey.name: Name.preferredControllerSkin, NotificationUserInfoKey.system: system, NotificationUserInfoKey.traits: traits])
|
NotificationCenter.default.post(name: .settingsDidChange, object: controllerSkin, userInfo: [NotificationUserInfoKey.name: Name.preferredControllerSkin, NotificationUserInfoKey.system: system, NotificationUserInfoKey.traits: traits])
|
||||||
|
|||||||
@ -42,6 +42,8 @@ class SettingsViewController: UITableViewController
|
|||||||
|
|
||||||
fileprivate var selectionFeedbackGenerator: UISelectionFeedbackGenerator?
|
fileprivate var selectionFeedbackGenerator: UISelectionFeedbackGenerator?
|
||||||
|
|
||||||
|
fileprivate var previousSelectedRowIndexPath: IndexPath?
|
||||||
|
|
||||||
required init?(coder aDecoder: NSCoder)
|
required init?(coder aDecoder: NSCoder)
|
||||||
{
|
{
|
||||||
super.init(coder: aDecoder)
|
super.init(coder: aDecoder)
|
||||||
@ -62,7 +64,7 @@ class SettingsViewController: UITableViewController
|
|||||||
{
|
{
|
||||||
super.viewWillAppear(animated)
|
super.viewWillAppear(animated)
|
||||||
|
|
||||||
if let indexPath = self.tableView.indexPathForSelectedRow
|
if let indexPath = self.previousSelectedRowIndexPath
|
||||||
{
|
{
|
||||||
if indexPath.section == Section.controllers.rawValue
|
if indexPath.section == Section.controllers.rawValue
|
||||||
{
|
{
|
||||||
@ -89,6 +91,8 @@ class SettingsViewController: UITableViewController
|
|||||||
let indexPath = self.tableView.indexPath(for: cell)
|
let indexPath = self.tableView.indexPath(for: cell)
|
||||||
else { return }
|
else { return }
|
||||||
|
|
||||||
|
self.previousSelectedRowIndexPath = indexPath
|
||||||
|
|
||||||
switch segueType
|
switch segueType
|
||||||
{
|
{
|
||||||
case Segue.controllers:
|
case Segue.controllers:
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user