cheat finder enhancements

This commit is contained in:
Yoshi Sugawara 2021-09-19 10:21:12 -10:00
parent 04f65c9b1b
commit de8edd03f1
7 changed files with 244 additions and 55 deletions

View File

@ -11,8 +11,13 @@ class CheatFinderManager {
private(set) var matchedMemoryAddresses = [Int: UInt8]()
var comparisonMemory = [UInt8]()
private let dispatchQueue = DispatchQueue(label: "CheatFinderManager", qos: .background)
var timer: DispatchSourceTimer?
var savedMatches = [Int: (value: UInt8, enabled: Bool)]()
enum UIState {
case initial, startedNewSearch, isSearching, didSearch
case initial, startedNewSearch, isSearching, didSearch, showSaved
}
enum SearchMode {
@ -22,8 +27,30 @@ class CheatFinderManager {
var uiState = UIState.initial
func start() {
if timer == nil {
timer = DispatchSource.makeTimerSource(queue: dispatchQueue)
timer?.setEventHandler(handler: {
self.updateMemoryWithCheats()
})
timer?.schedule(deadline: .now(), repeating: .seconds(1))
timer?.resume()
}
}
func updateMemoryWithCheats() {
print("CheatFinderManager updating memory...")
let memory = EmuWrapper.memory()
for (address, memoryValue) in savedMatches {
if let memory = memory, memoryValue.enabled {
print("updating memory at \(String(format: "%05X",address)) to \(memoryValue.value)")
memory[address] = memoryValue.value
}
}
}
func update(with memory: UnsafeMutablePointer<UInt8>) {
for address in 0..<0x95ff {
for address in 0..<EmuMemoryModel.maxMemorySize {
matchedMemoryAddresses[address] = memory[address]
}
}
@ -46,13 +73,12 @@ class CheatFinderManager {
if matched {
newMatches[address] = newValue
}
// // avoid having too many matches
// if newMatches.count > 10000 {
// break
// }
}
matchedMemoryAddresses = newMatches
}
// start new search:
// put all memory into matched
//
// set less than
// run findNewMatches
}

View File

@ -9,7 +9,7 @@ import Foundation
class EmuMemoryModel {
let numToDisplayPerCell = 8
let maxMemorySize = 128 * 1024
static let maxMemorySize = 256 * 1024
private(set) var memory = EmuWrapper.memory()
private(set) var referencedAddresses = [UInt16: [AddressedInstruction]]()
@ -47,8 +47,8 @@ class EmuMemoryModel {
}
func getMemoryHexString(at address: Int) -> String {
guard address > 0 && address < maxMemorySize else {
print("Cannot get memory: address out of range \(address) > \(maxMemorySize)")
guard address > 0 && address < Self.maxMemorySize else {
print("Cannot get memory: address out of range \(address) > \(Self.maxMemorySize)")
return ""
}
guard let memory = memory else {
@ -63,8 +63,8 @@ class EmuMemoryModel {
}
func setMemory(at address:Int, value: UInt8) {
guard address > 0 && address < maxMemorySize else {
print("Cannot set memory: address out of range \(address) > \(maxMemorySize)")
guard address > 0 && address < Self.maxMemorySize else {
print("Cannot set memory: address out of range \(address) > \(Self.maxMemorySize)")
return
}
guard let memory = memory else {
@ -76,8 +76,8 @@ class EmuMemoryModel {
}
func getMemory(at address:Int) -> UInt8 {
guard address > 0 && address < maxMemorySize else {
print("Cannot get memory: address out of range \(address) > \(maxMemorySize)")
guard address > 0 && address < Self.maxMemorySize else {
print("Cannot get memory: address out of range \(address) > \(Self.maxMemorySize)")
return 0
}
guard let memory = memory else {

View File

@ -23,7 +23,7 @@ class DebugMemoryActionViewController: UIViewController {
}
var mode: Mode = .jumpToAddress
var cheatFinder = CheatFinderManager()
let cheatFinder: CheatFinderManager
var matchedInstructions = [AddressedInstruction]()
@ -73,8 +73,18 @@ class DebugMemoryActionViewController: UIViewController {
return button
}()
let addToCheatsButton: UIButton = {
let button = UIButton(type: .custom)
button.titleLabel?.font = UIFont(name: "Print Char 21", size: 12)
button.setTitle("Add to Cheats", for: .normal)
button.layer.borderWidth = 1
button.layer.borderColor = UIColor.orange.cgColor
button.addTarget(self, action: #selector(addToCheatButtonPressed(_:)), for: .touchUpInside )
return button
}()
lazy var editFieldsStackView: UIStackView = {
let stackView = UIStackView(arrangedSubviews: [memoryField, updateMemoryButton, resetMemoryButton])
let stackView = UIStackView(arrangedSubviews: [memoryField, updateMemoryButton, resetMemoryButton, addToCheatsButton])
stackView.translatesAutoresizingMaskIntoConstraints = false
stackView.axis = .horizontal
stackView.spacing = 4
@ -151,7 +161,8 @@ class DebugMemoryActionViewController: UIViewController {
}()
lazy var cheatFinderInitialActionsStackView: UIStackView = {
let stackView = UIStackView(arrangedSubviews: [cheatFinderNewSearchButton, cheatFinderContinueSearchButton, cheatFinderSearchLessButton, cheatFinderSearchGreaterButton, cheatFinderSearchEqualButton])
let stackView = UIStackView(arrangedSubviews: [cheatFinderNewSearchButton, cheatFinderContinueSearchButton, cheatFinderSearchLessButton, cheatFinderSearchGreaterButton, cheatFinderSearchEqualButton,
cheatFinderShowSavedButton])
stackView.translatesAutoresizingMaskIntoConstraints = false
stackView.axis = .horizontal
stackView.spacing = 4
@ -197,6 +208,26 @@ class DebugMemoryActionViewController: UIViewController {
return button
}()
lazy var cheatFinderShowSavedButton: ToggleButton = {
let button = ToggleButton()
button.titleLabel?.font = UIFont(name: "Print Char 21", size: 12)
button.setTitle("Matched", for: .normal)
button.setTitle("Saved", for: .selected)
button.layer.borderWidth = 1
button.layer.borderColor = UIColor.purple.cgColor
button.onTapped = { [weak self] wasSelected in
if wasSelected {
self?.cheatFinder.uiState = .showSaved
} else {
self?.cheatFinder.uiState = .didSearch
}
self?.cheatFinderUpdateUI()
}
button.tag = 3
button.translatesAutoresizingMaskIntoConstraints = false
return button
}()
let findCodeButton: DebugMemoryButton = {
let button = DebugMemoryButton()
button.titleLabel?.font = UIFont(name: "Print Char 21", size: 9)
@ -237,6 +268,25 @@ class DebugMemoryActionViewController: UIViewController {
return view
}()
lazy var cheatFinderSavedTableView: UITableView = {
let view = UITableView(frame: .zero)
view.translatesAutoresizingMaskIntoConstraints = false
view.backgroundColor = .clear
view.dataSource = self
view.delegate = self
view.register(UITableViewCell.self, forCellReuseIdentifier: "CheatFinderMatchCell")
return view
}()
init(cheatFinderManager: CheatFinderManager) {
self.cheatFinder = cheatFinderManager
super.init(nibName: nil, bundle: nil)
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
lazy var emulatorScreenView: UIImageView = {
let screenView = UIImageView(frame: .zero)
screenView.translatesAutoresizingMaskIntoConstraints = false
@ -261,6 +311,7 @@ class DebugMemoryActionViewController: UIViewController {
// view.addSubview(cheatFinderSearchStackView)
view.addSubview(cheatFinderPromptLabel)
view.addSubview(cheatFinderMatchesTableView)
view.addSubview(cheatFinderSavedTableView)
cheatFinderInitialActionsStackView.topAnchor.constraint(equalTo: segmentedControl.bottomAnchor, constant: 8).isActive = true
cheatFinderInitialActionsStackView.centerXAnchor.constraint(equalTo: segmentedControl.centerXAnchor).isActive = true
// cheatFinderInitialActionsStackView.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 16).isActive = true
@ -275,11 +326,15 @@ class DebugMemoryActionViewController: UIViewController {
cheatFinderMatchesTableView.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 24).isActive = true
cheatFinderMatchesTableView.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -24).isActive = true
cheatFinderMatchesTableView.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor, constant: 8).isActive = true
[cheatFinderInitialActionsStackView, cheatFinderPromptLabel, cheatFinderMatchesTableView].forEach{ $0.isHidden = true }
cheatFinderSavedTableView.topAnchor.constraint(equalTo: cheatFinderMatchesTableView.topAnchor).isActive = true
cheatFinderSavedTableView.leadingAnchor.constraint(equalTo: cheatFinderMatchesTableView.leadingAnchor).isActive = true
cheatFinderSavedTableView.trailingAnchor.constraint(equalTo: cheatFinderMatchesTableView.trailingAnchor).isActive = true
cheatFinderSavedTableView.bottomAnchor.constraint(equalTo: cheatFinderMatchesTableView.bottomAnchor).isActive = true
[cheatFinderInitialActionsStackView, cheatFinderPromptLabel, cheatFinderMatchesTableView, cheatFinderSavedTableView].forEach{ $0.isHidden = true }
}
func cheatFinderHide() {
[cheatFinderInitialActionsStackView, cheatFinderPromptLabel, cheatFinderMatchesTableView, cheatFinderSearchLessButton, cheatFinderSearchGreaterButton, cheatFinderNewSearchButton, cheatFinderContinueSearchButton, cheatFinderSearchEqualButton].forEach{ $0.isHidden = true }
[cheatFinderInitialActionsStackView, cheatFinderPromptLabel, cheatFinderMatchesTableView, cheatFinderSearchLessButton, cheatFinderSearchGreaterButton, cheatFinderNewSearchButton, cheatFinderContinueSearchButton, cheatFinderSearchEqualButton, cheatFinderShowSavedButton, cheatFinderSavedTableView].forEach{ $0.isHidden = true }
}
func cheatFinderUpdateUI() {
@ -292,19 +347,25 @@ class DebugMemoryActionViewController: UIViewController {
[cheatFinderInitialActionsStackView, cheatFinderNewSearchButton,
cheatFinderSearchLessButton, cheatFinderSearchGreaterButton,
cheatFinderSearchEqualButton,
cheatFinderPromptLabel].forEach{ $0.isHidden = false }
cheatFinderPromptLabel, cheatFinderShowSavedButton].forEach{ $0.isHidden = false }
cheatFinderPromptLabel.text = "New search started! Search to find matches..."
case .isSearching:
[cheatFinderInitialActionsStackView, cheatFinderNewSearchButton, cheatFinderSearchLessButton, cheatFinderSearchGreaterButton,
cheatFinderSearchEqualButton, cheatFinderPromptLabel].forEach{ $0.isHidden = false }
cheatFinderSearchEqualButton, cheatFinderPromptLabel, cheatFinderShowSavedButton].forEach{ $0.isHidden = false }
cheatFinderPromptLabel.text = "Search for values..."
case .didSearch:
[cheatFinderInitialActionsStackView, cheatFinderNewSearchButton,
cheatFinderSearchLessButton, cheatFinderSearchGreaterButton,
cheatFinderSearchEqualButton,
cheatFinderPromptLabel, cheatFinderMatchesTableView].forEach{ $0.isHidden = false }
cheatFinderPromptLabel, cheatFinderMatchesTableView, cheatFinderShowSavedButton].forEach{ $0.isHidden = false }
cheatFinderPromptLabel.text = "Number of matches: \(cheatFinder.matchedMemoryAddresses.count)"
cheatFinderMatchesTableView.reloadData()
case .showSaved:
[cheatFinderInitialActionsStackView, cheatFinderNewSearchButton,
cheatFinderSearchLessButton, cheatFinderSearchGreaterButton,
cheatFinderSearchEqualButton,
cheatFinderPromptLabel, cheatFinderShowSavedButton, cheatFinderSavedTableView].forEach{ $0.isHidden = false }
cheatFinderSavedTableView.reloadData()
}
}
@ -314,7 +375,7 @@ class DebugMemoryActionViewController: UIViewController {
return
}
cheatFinder.comparisonMemory = [UInt8]()
for address in 0..<0x95ff {
for address in 0..<EmuMemoryModel.maxMemorySize {
cheatFinder.comparisonMemory.append(memory[address])
}
switch sender.tag {
@ -442,7 +503,8 @@ class DebugMemoryActionViewController: UIViewController {
private func updateMatchedInstructions() {
if let delegate = delegate,
let text = memoryField.text,
let address = getAddressFromText(text) {
let address = getAddressFromText(text),
address < 0x10000 {
matchedInstructions = delegate.referencedMemoryAddresses[UInt16(address)] ?? [AddressedInstruction]()
findInCodeResultsTableView.reloadData()
}
@ -476,7 +538,7 @@ class DebugMemoryActionViewController: UIViewController {
}
let scanner = Scanner(string: text)
var address: UInt64 = 0
if scanner.scanHexInt64(&address) && address < 0x95ff {
if scanner.scanHexInt64(&address) && address < EmuMemoryModel.maxMemorySize {
return address
}
return nil
@ -491,11 +553,11 @@ class DebugMemoryActionViewController: UIViewController {
let charLimit: Int = {
switch mode {
case .jumpToAddress:
return 4
return 5
case .changeMemory:
return 2
default:
return 4
return 5
}
}()
if text.count > charLimit {
@ -581,6 +643,41 @@ class DebugMemoryActionViewController: UIViewController {
}
delegate?.updateMemory(at: selectedAddress, with: memory)
}
@objc func addToCheatButtonPressed(_ sender: UIButton) {
guard let selectedAddress = delegate?.selectedAddress,
let enteredText = memoryField.text,
let memory = UInt8(enteredText, radix: 16) else {
print("Could not get memory to update!")
return
}
cheatFinder.savedMatches[selectedAddress] = (value: memory, enabled: true)
cheatFinderSavedTableView.reloadData()
}
@objc func cheatTableCellActionButtonPressed(_ sender: UIButton) {
let address = sender.tag
guard let matched = cheatFinder.matchedMemoryAddresses[address] else {
print("Could not find matched address: \(address)")
return
}
if cheatFinder.savedMatches[address] != nil {
cheatFinder.savedMatches.removeValue(forKey: address)
} else {
cheatFinder.savedMatches[address] = (value: matched, enabled: true)
}
cheatFinderSavedTableView.reloadData()
}
@objc func cheatSavedTableSwitchPressed(_ sender: UISwitch) {
let address = sender.tag
guard let matched = cheatFinder.savedMatches[address] else {
print("could not find saved entry!")
return
}
cheatFinder.savedMatches[address] = (value: matched.value, enabled: sender.isOn)
cheatFinderSavedTableView.reloadData()
}
}
extension DebugMemoryActionViewController: EmulatorKeyboardKeyPressedDelegate {
@ -616,6 +713,8 @@ extension DebugMemoryActionViewController: UITableViewDataSource {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if tableView == findInCodeResultsTableView {
return matchedInstructions.count
} else if tableView == cheatFinderSavedTableView {
return cheatFinder.savedMatches.keys.count
} else {
return cheatFinder.matchedMemoryAddresses.keys.count
}
@ -630,15 +729,39 @@ extension DebugMemoryActionViewController: UITableViewDataSource {
cell.textLabel?.textColor = .yellow
cell.textLabel?.textAlignment = .center
return cell
} else if tableView == cheatFinderSavedTableView {
let cell = tableView.dequeueReusableCell(withIdentifier: "CheatFinderMatchCell", for: indexPath)
let addresses = cheatFinder.savedMatches.keys.sorted()
let index = addresses.index(addresses.startIndex, offsetBy: indexPath.row)
let address = addresses[index]
let saved = cheatFinder.savedMatches[address]!
cell.textLabel?.text = String(format: "%04X: %02X",address,saved.value)
cell.textLabel?.font = UIFont(name: "Print Char 21", size: 14)
cell.textLabel?.textColor = .red
cell.textLabel?.textAlignment = .left
let enableSwitch = UISwitch(frame: .zero)
enableSwitch.isOn = saved.enabled
enableSwitch.addTarget(self, action: #selector(cheatSavedTableSwitchPressed(_:)), for: .valueChanged)
enableSwitch.tag = address
cell.accessoryView = enableSwitch
return cell
} else {
let cell = tableView.dequeueReusableCell(withIdentifier: "CheatFinderMatchCell", for: indexPath)
let addresses = cheatFinder.matchedMemoryAddresses.keys
let addresses = cheatFinder.matchedMemoryAddresses.keys.sorted()
let index = addresses.index(addresses.startIndex, offsetBy: indexPath.row)
let address = addresses[index]
cell.textLabel?.text = String(format: "%04X: %02X",address,cheatFinder.matchedMemoryAddresses[address]!)
cell.textLabel?.font = UIFont(name: "Print Char 21", size: 14)
cell.textLabel?.textColor = .red
cell.textLabel?.textAlignment = .center
let isSaved = cheatFinder.savedMatches[address] != nil
let actionButton = isSaved ? UIButton(type: .custom) : UIButton(type: .contactAdd)
actionButton.tag = address
if isSaved {
actionButton.setTitle("Remove", for: .normal)
}
actionButton.addTarget(self, action: #selector(cheatTableCellActionButtonPressed(_:)), for: .touchUpInside)
cell.accessoryView = actionButton
return cell
}
}
@ -651,7 +774,7 @@ extension DebugMemoryActionViewController: UITableViewDelegate {
let address = instruction.address
delegate?.jump(to: Int(address))
} else {
let addresses = cheatFinder.matchedMemoryAddresses.keys
let addresses = tableView == cheatFinderSavedTableView ? cheatFinder.savedMatches.keys.sorted() : cheatFinder.matchedMemoryAddresses.keys.sorted()
let index = addresses.index(addresses.startIndex, offsetBy: indexPath.row)
let address = addresses[index]
delegate?.jump(to: address)

View File

@ -20,6 +20,9 @@ enum EmuMemoryMapSection: Int {
case highResGraphicsPage1
case highResGraphicsPage2
case applesoftStringData
case ioArea
case bankSwitched
case auxBanks
var range:Range<Int> {
switch self {
@ -33,7 +36,10 @@ enum EmuMemoryMapSection: Int {
case .freespace2: return 0xc00..<0x2000
case .highResGraphicsPage1: return 0x2000..<0x4000
case .highResGraphicsPage2: return 0x4000..<0x6000
case .applesoftStringData: return 0x6000..<0x95ff
case .applesoftStringData: return 0x6000..<0xc000
case .ioArea: return 0xc000..<0xd000
case .bankSwitched: return 0xd000..<0x10000
case .auxBanks: return 0x10000..<0x30000
}
}
@ -54,6 +60,9 @@ enum EmuMemoryMapSection: Int {
case .highResGraphicsPage1: return "High Resolution Graphics Page 1"
case .highResGraphicsPage2: return "High Resolution Graphics Page 2"
case .applesoftStringData: return "Applesoft String Data"
case .ioArea: return "IO Area"
case .bankSwitched: return "Bank Switched"
case .auxBanks: return "Auxilliary Memory? 😅"
}
}
@ -78,8 +87,16 @@ enum EmuMemoryMapSection: Int {
return .highResGraphicsPage1
} else if EmuMemoryMapSection.highResGraphicsPage2.range.contains(address) {
return .highResGraphicsPage2
} else {
} else if EmuMemoryMapSection.applesoftStringData.range.contains(address) {
return .applesoftStringData
} else if EmuMemoryMapSection.ioArea.range.contains(address) {
return .ioArea
} else if EmuMemoryMapSection.bankSwitched.range.contains(address) {
return .bankSwitched
} else if EmuMemoryMapSection.auxBanks.range.contains(address) {
return .auxBanks
} else {
return .auxBanks
}
}
}
@ -112,6 +129,8 @@ protocol DebugMemoryViewControllerDelegate: class {
var actionControllerAnimatorProgress = 0.0
var animator: UIViewPropertyAnimator?
var cheatFinder = CheatFinderManager()
private var displayLink: CADisplayLink?
private var framesSince = 0
private var framesSinceUpdateScreen = 0
@ -211,7 +230,7 @@ protocol DebugMemoryViewControllerDelegate: class {
}
func setupActionController() {
let actionController = DebugMemoryActionViewController()
let actionController = DebugMemoryActionViewController(cheatFinderManager: cheatFinder)
delegate = actionController
actionController.delegate = self
addChild(actionController)
@ -335,6 +354,7 @@ protocol DebugMemoryViewControllerDelegate: class {
super.viewDidAppear(animated)
dataTableView.reloadData()
delegate?.refreshActionController()
cheatFinder.start()
}
@objc func handlePan(_ recognizer: UIPanGestureRecognizer) {
@ -414,7 +434,7 @@ extension DebugMemoryViewController: UITableViewDataSource {
if tableView == codeTableView {
return 1
} else {
return EmuMemoryMapSection.applesoftStringData.rawValue + 1
return EmuMemoryMapSection.auxBanks.rawValue + 1
}
}

View File

@ -7,14 +7,8 @@
import Foundation
class DebugMemoryButton: UIButton {
class ToggleButton: UIButton {
var onTapped: ((Bool) -> Void)?
override open var isSelected: Bool {
didSet {
backgroundColor = isSelected ? .white : .clear
}
}
convenience init() {
self.init(type: .custom)
@ -27,7 +21,15 @@ class DebugMemoryButton: UIButton {
}
}
class DebugPauseResumeButton: DebugMemoryButton {
class DebugMemoryButton: ToggleButton {
override open var isSelected: Bool {
didSet {
backgroundColor = isSelected ? .white : .clear
}
}
}
class DebugPauseResumeButton: ToggleButton {
override open var isSelected: Bool {
didSet {
backgroundColor = isSelected ? .red : .clear

View File

@ -61,7 +61,7 @@ class DebugMemoryCell: UITableViewCell {
self.delegate = delegate
self.offset = offset
stackView.arrangedSubviews.forEach{ $0.removeFromSuperview() }
addressLabel.text = String(format: "%04X:", offset)
addressLabel.text = String(format: "%05X:", offset)
stackView.addArrangedSubview(addressLabel)
stackView.setCustomSpacing(3, after: addressLabel)
for (index, hexValue) in hexMemoryValues.enumerated() {

View File

@ -104,14 +104,23 @@ class EmulatorKeyboardView: UIView {
return stackView
}()
let dragMeView: UILabel = {
let label = UILabel(frame: .zero)
label.translatesAutoresizingMaskIntoConstraints = false
label.text = "DRAG ME!"
label.textColor = UIColor.systemRed
return label
let dragMeView: UIView = {
let view = UIView(frame: .zero)
view.backgroundColor = .white
view.translatesAutoresizingMaskIntoConstraints = false
view.widthAnchor.constraint(equalToConstant: 80).isActive = true
view.heightAnchor.constraint(equalToConstant: 2).isActive = true
let outerView = UIView(frame: .zero)
outerView.backgroundColor = .clear
outerView.translatesAutoresizingMaskIntoConstraints = false
outerView.addSubview(view)
view.centerXAnchor.constraint(equalTo: outerView.centerXAnchor).isActive = true
view.centerYAnchor.constraint(equalTo: outerView.centerYAnchor).isActive = true
outerView.heightAnchor.constraint(equalToConstant: 20).isActive = true
outerView.widthAnchor.constraint(equalToConstant: 100).isActive = true
return outerView
}()
private var pressedKeyLabels = [String: UILabel]()
convenience init() {
@ -145,7 +154,7 @@ class EmulatorKeyboardView: UIView {
alternateKeyRowsStackView.trailingAnchor.constraint(equalTo: layoutMarginsGuide.trailingAnchor, constant: -4.0).isActive = true
addSubview(dragMeView)
dragMeView.centerXAnchor.constraint(equalTo: centerXAnchor).isActive = true
dragMeView.bottomAnchor.constraint(equalTo: bottomAnchor, constant: -8.0).isActive = true
dragMeView.bottomAnchor.constraint(equalTo: bottomAnchor).isActive = true
}
@ -172,6 +181,14 @@ class EmulatorKeyboardView: UIView {
viewModel.keyPressed(sender.key)
}
@objc private func keyCancelled(_ sender: KeyboardButton) {
let title = sender.titleLabel?.text ?? "😭"
if let label = pressedKeyLabels[title] {
label.removeFromSuperview()
pressedKeyLabels.removeValue(forKey: title)
}
}
@objc private func keyReleased(_ sender: KeyboardButton) {
if sender.key.keyCode == AppleKeyboardKey.KEY_SPECIAL_TOGGLE.rawValue {
delegate?.toggleAlternateKeys()
@ -243,6 +260,7 @@ class EmulatorKeyboardView: UIView {
key.addTarget(self, action: #selector(keyPressed(_:)), for: .touchDown)
key.addTarget(self, action: #selector(keyReleased(_:)), for: .touchUpInside)
key.addTarget(self, action: #selector(keyReleased(_:)), for: .touchUpOutside)
key.addTarget(self, action: #selector(keyCancelled(_:)), for: .touchCancel)
if keyCoded.isModifier {
modifierButtons.update(with: key)
}
@ -560,7 +578,7 @@ struct KeyPosition {
AppleIIKey(label: "SPACE", code: AppleKeyboardKey.KEY_SPACE.rawValue, keySize: .wide),
AppleIIKey(label: "SHIFT", code: AppleKeyboardKey.KEY_SHIFT.rawValue,
keySize: .standard, isModifier: true, imageName: "shift", imageNameHighlighted: "shift.fill"),
AppleIIKey(label: "DELETE", code: AppleKeyboardKey.KEY_DELETE.rawValue, imageName: "delete.left", imageNameHighlighted: "delete.left.fill")
AppleIIKey(label: "DELETE", code: AppleKeyboardKey.KEY_DELETE.rawValue, imageName: "delete.left", imageNameHighlighted: "delete.left.fill")
],
[
AppleIIKey(label: "\(UnicodeScalar(0xe080)!)", code: AppleKeyboardKey.KEY_OPTION.rawValue,
@ -774,8 +792,8 @@ struct KeyPosition {
keyboardConstraints.removeAll()
leftKeyboardView.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(leftKeyboardView)
leftKeyboardView.heightAnchor.constraint(equalToConstant: 250).isActive = true
leftKeyboardView.widthAnchor.constraint(equalToConstant: 175).isActive = true
leftKeyboardView.heightAnchor.constraint(equalToConstant: 270).isActive = true
leftKeyboardView.widthAnchor.constraint(equalToConstant: 180).isActive = true
keyboardConstraints.append(contentsOf: [
leftKeyboardView.leadingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leadingAnchor),
leftKeyboardView.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor)
@ -786,8 +804,8 @@ struct KeyPosition {
rightKeyboardView.trailingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.trailingAnchor),
rightKeyboardView.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor)
])
rightKeyboardView.heightAnchor.constraint(equalToConstant: 250).isActive = true
rightKeyboardView.widthAnchor.constraint(equalToConstant: 175).isActive = true
rightKeyboardView.heightAnchor.constraint(equalToConstant: 270).isActive = true
rightKeyboardView.widthAnchor.constraint(equalToConstant: 180).isActive = true
NSLayoutConstraint.activate(keyboardConstraints)
}