use a view model to interface with the view; support shift toggle for keys

This commit is contained in:
Yoshi Sugawara 2020-08-02 00:20:51 -10:00
parent 1b3d11c06b
commit 094bafd898
2 changed files with 103 additions and 53 deletions

View File

@ -10,7 +10,6 @@ import UIKit
class KeyboardButton: UIButton {
let key: KeyCoded
var isModifierToggle = false
var toggleState = false
// MARK: - Functions
@ -39,14 +38,13 @@ class KeyboardButton: UIButton {
override open var isSelected: Bool {
didSet {
let shouldHighlight = isModifierToggle ? toggleState : isSelected
let shouldHighlight = key.isModifier ? toggleState : isSelected
backgroundColor = shouldHighlight ? .red : .black
}
}
required init(key: KeyCoded, isModifier: Bool = false) {
required init(key: KeyCoded) {
self.key = key
self.isModifierToggle = isModifier
super.init(frame: .zero)
}
required init?(coder aDecoder: NSCoder) {
@ -66,11 +64,13 @@ class KeyboardButton: UIButton {
class EmulatorKeyboardView: UIView {
@objc weak var delegate: EmulatorKeyboardKeyPressedDelegate?
@objc weak var modifierDelegate: EmulatorKeyboardModifierPressedDelegate?
var keyRowsDataSource: KeyRowsDataSource?
var viewModel = EmulatorKeyboardViewModel(keys: [[KeyCoded]]()) {
didSet {
setupWithModel(viewModel)
}
}
private var keyRowsStackView: UIStackView = {
private lazy var keyRowsStackView: UIStackView = {
let stackView = UIStackView()
stackView.translatesAutoresizingMaskIntoConstraints = false
stackView.axis = .vertical
@ -79,6 +79,15 @@ class EmulatorKeyboardView: UIView {
return stackView
}()
private lazy var alternateKeyRowsStackView: UIStackView = {
let stackView = UIStackView()
stackView.translatesAutoresizingMaskIntoConstraints = false
stackView.axis = .vertical
stackView.distribution = .equalCentering
stackView.spacing = 16
return stackView
}()
let dragMeView: UILabel = {
let label = UILabel(frame: .zero)
label.translatesAutoresizingMaskIntoConstraints = false
@ -121,57 +130,44 @@ class EmulatorKeyboardView: UIView {
@objc private func keyPressed(_ sender: KeyboardButton) {
let label = UILabel(frame: .zero)
label.text = sender.titleLabel?.text
// hmm need to convert frame
let converted = sender.convert(sender.bounds, to: self)
print("sender frame: \(sender.frame), bounds: \(sender.bounds), convertedBounds = \(converted)")
var labelFrame = converted.offsetBy(dx: 0, dy: -60)
labelFrame = CGRect(x: labelFrame.origin.x, y: labelFrame.origin.y, width: labelFrame.width * 2, height: labelFrame.height * 2)
label.backgroundColor = .purple
label.textColor = .green
label.frame = labelFrame
addSubview(label)
pressedKeyLabels[label.text ?? "😭"] = label
if sender.isModifierToggle {
let isPressed = modifierDelegate?.isModifierEnabled(key: sender.key) ?? false
modifierDelegate?.modifierPressedWithKey(sender.key, enable: !isPressed)
if viewModel.shouldShowKeyPressedVisualFeedbackForKey(sender.key) {
let label = UILabel(frame: .zero)
label.text = sender.titleLabel?.text
// hmm need to convert frame
let converted = sender.convert(sender.bounds, to: self)
print("sender frame: \(sender.frame), bounds: \(sender.bounds), convertedBounds = \(converted)")
var labelFrame = converted.offsetBy(dx: 0, dy: -60)
labelFrame = CGRect(x: labelFrame.origin.x, y: labelFrame.origin.y, width: labelFrame.width * 2, height: labelFrame.height * 2)
label.backgroundColor = .purple
label.textColor = .green
label.frame = labelFrame
addSubview(label)
pressedKeyLabels[label.text ?? "😭"] = label
}
delegate?.keyDown(sender.key)
viewModel.keyPressed(sender.key)
}
@objc private func keyReleased(_ sender: KeyboardButton) {
// pass to delegate
let title = sender.titleLabel?.text ?? "😭"
// pressedKeyLabels.forEach { _, value in
// value.removeFromSuperview()
// }
if let label = pressedKeyLabels[title] {
label.removeFromSuperview()
pressedKeyLabels.removeValue(forKey: title)
}
if sender.isModifierToggle {
if modifierDelegate?.isModifierEnabled(key: sender.key) ?? false {
sender.toggleState = true
sender.isSelected = true
} else {
sender.toggleState = false
sender.isSelected = false
}
}
delegate?.keyUp(sender.key)
let modifierState = viewModel.modifierKeyToggleStateForKey(sender.key)
sender.toggleState = modifierState
sender.isSelected = modifierState
viewModel.keyReleased(sender.key)
}
func setupWithModel(_ model: AppleIIKeysCluster) {
func setupWithModel(_ model: EmulatorKeyboardViewModel) {
for row in model.keys {
let keysInRow = createKeyRow(keys: row)
keyRowsStackView.addArrangedSubview(keysInRow)
}
keyRowsDataSource = model
}
private func createKey(_ keyCoded: KeyCoded) -> UIButton {
let testKey = KeyboardButton(key: keyCoded, isModifier: keyCoded.isModifier)
let testKey = KeyboardButton(key: keyCoded)
testKey.setTitle(keyCoded.keyLabel, for: .normal)
testKey.titleLabel?.font = UIFont.systemFont(ofSize: 12.0)
testKey.setTitleColor(.white, for: .normal)
@ -242,8 +238,25 @@ struct KeyPosition {
let column: Int
}
struct AppleIIKeysCluster: KeyRowsDataSource {
var keys = [[AppleIIKey]]()
@objc class EmulatorKeyboardViewModel: NSObject, KeyRowsDataSource {
var keys = [[KeyCoded]]()
var alternateKeys: [[KeyCoded]]?
var modifierState: Int16 = 0
@objc weak var delegate: EmulatorKeyboardKeyPressedDelegate?
@objc weak var modifierDelegate: EmulatorKeyboardModifierPressedDelegate?
init(keys: [[KeyCoded]], alternateKeys: [[KeyCoded]]? = nil) {
self.keys = keys
self.alternateKeys = alternateKeys
}
func createView() -> EmulatorKeyboardView {
let view = EmulatorKeyboardView()
view.viewModel = self
return view
}
func keyForPositionAt(_ position: KeyPosition) -> KeyCoded? {
guard position.row < keys.count else {
return nil
@ -254,16 +267,46 @@ struct AppleIIKeysCluster: KeyRowsDataSource {
}
return row[position.column]
}
func shouldShowKeyPressedVisualFeedbackForKey(_ key: KeyCoded) -> Bool {
return !key.isModifier
}
func modifierKeyToggleStateForKey(_ key: KeyCoded) -> Bool {
return key.isModifier && (modifierDelegate?.isModifierEnabled(key: key) ?? false)
}
func keyPressed(_ key: KeyCoded) {
if key.isModifier {
let isPressed = modifierDelegate?.isModifierEnabled(key: key) ?? false
modifierDelegate?.modifierPressedWithKey(key, enable: !isPressed)
}
delegate?.keyDown(key)
}
func keyReleased(_ key: KeyCoded) {
delegate?.keyUp(key)
}
// KeyCoded can support a shifted key label
// view can update with shifted key labels?
// cluster can support alternate keys and view can swap them out?
}
@objc class EmulatorKeyboardController: UIViewController {
@objc let leftKeyboardView = EmulatorKeyboardView()
@objc let rightKeyboardView = EmulatorKeyboardView()
@objc lazy var leftKeyboardView: EmulatorKeyboardView = {
leftKeyboardModel.createView()
}()
@objc lazy var rightKeyboardView: EmulatorKeyboardView = {
rightKeyboardModel.createView()
}()
var keyboardConstraints = [NSLayoutConstraint]()
// uses bitwise masks for the state of shift keys, control, open-apple keys, etc
@objc var modifierState: Int16 = 0
let leftKeyboardModel = AppleIIKeysCluster(keys:
@objc let leftKeyboardModel = EmulatorKeyboardViewModel(keys:
[
[
AppleIIKey(label: "q", code: AppleKeyboardKey.KEY_Q.rawValue),
@ -292,7 +335,7 @@ struct AppleIIKeysCluster: KeyRowsDataSource {
]
]
)
let rightKeyboardModel = AppleIIKeysCluster(keys:
@objc let rightKeyboardModel = EmulatorKeyboardViewModel(keys:
[
[
AppleIIKey(label: "y", code: AppleKeyboardKey.KEY_Y.rawValue),
@ -334,7 +377,7 @@ struct AppleIIKeysCluster: KeyRowsDataSource {
super.viewDidLoad()
// setupView()
setupViewFrames()
setupKeyModels()
// setupKeyModels()
let panGesture = UIPanGestureRecognizer(target: self, action: #selector(draggedView(_:)))
leftKeyboardView.dragMeView.isUserInteractionEnabled = true
@ -376,11 +419,11 @@ struct AppleIIKeysCluster: KeyRowsDataSource {
let keyboardWidth: CGFloat = 200.0
let bottomLeftFrame = CGRect(
x: self.view.safeAreaInsets.left,
y: screenFrame.size.height - self.view.safeAreaInsets.bottom - keyboardHeight,
y: screenFrame.size.height - self.view.safeAreaInsets.bottom - keyboardHeight - 20,
width: keyboardWidth, height: keyboardHeight)
let bottomRightFrame = CGRect(
x: screenFrame.size.width - self.view.safeAreaInsets.right - keyboardWidth,
y:screenFrame.size.height - self.view.safeAreaInsets.bottom - keyboardHeight,
y:screenFrame.size.height - self.view.safeAreaInsets.bottom - keyboardHeight - 20,
width: keyboardWidth, height: keyboardHeight
)
view.addSubview(leftKeyboardView)

View File

@ -447,9 +447,9 @@ int x_lock_zoom = 0;
[self.contentView addSubview:self.kbdc.view];
self.emuKeyboardController = [[EmulatorKeyboardController alloc] init];
self.emuKeyboardController.leftKeyboardView.delegate = self;
self.emuKeyboardController.leftKeyboardView.modifierDelegate = self;
self.emuKeyboardController.rightKeyboardView.delegate = self;
self.emuKeyboardController.leftKeyboardModel.delegate = self;
self.emuKeyboardController.leftKeyboardModel.modifierDelegate = self;
self.emuKeyboardController.rightKeyboardModel.delegate = self;
self.view = self.contentView;
@ -715,10 +715,17 @@ int x_lock_zoom = 0;
#pragma mark - EmulatorKeyboardKeyPressedDelegate
-(void)keyDown:(id<KeyCoded>)key {
NSLog(@"key down: %li modifier: %i",(long)key.keyCode, self.emuKeyboardController.modifierState);
if (self.emuKeyboardController.modifierState & shiftKey) {
add_event_modifier(shiftKey);
}
add_event_key((int)key.keyCode, 0);
}
-(void)keyUp:(id<KeyCoded>)key {
if (self.emuKeyboardController.modifierState & shiftKey) {
add_event_modifier(0);
}
add_event_key((int)key.keyCode, 1);
}