123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198 |
- //
- // Copyright © 2022 osy. All rights reserved.
- //
- // Licensed under the Apache License, Version 2.0 (the "License");
- // you may not use this file except in compliance with the License.
- // You may obtain a copy of the License at
- //
- // http://www.apache.org/licenses/LICENSE-2.0
- //
- // Unless required by applicable law or agreed to in writing, software
- // distributed under the License is distributed on an "AS IS" BASIS,
- // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- // See the License for the specific language governing permissions and
- // limitations under the License.
- //
- import Foundation
- import SwiftTerm
- import SwiftUI
- @objc class VMDisplayTerminalViewController: VMDisplayViewController {
- private var terminalView: TerminalView!
- private var vmSerialPort: CSPort
-
- private var style: UTMConfigurationTerminal?
- private var keyboardDelta: CGFloat = 0
-
- required init(port: CSPort, style: UTMConfigurationTerminal? = nil) {
- self.vmSerialPort = port
- super.init(nibName: nil, bundle: nil)
- port.delegate = self
- self.style = style
- }
-
- required init?(coder: NSCoder) {
- return nil
- }
-
- override func loadView() {
- super.loadView()
- terminalView = TerminalView(frame: makeFrame (keyboardDelta: 0))
- terminalView.terminalDelegate = self
- view.insertSubview(terminalView, at: 0)
- styleTerminal()
- }
-
- override func viewDidLoad() {
- super.viewDidLoad()
- setupKeyboardMonitor()
- }
-
- override func enterLive() {
- super.enterLive()
- DispatchQueue.main.async {
- let terminalSize = CGSize(width: self.terminalView.getTerminal().cols, height: self.terminalView.getTerminal().rows)
- self.delegate.displayViewSize = terminalSize
- }
- }
-
- override func showKeyboard() {
- terminalView.becomeFirstResponder()
- }
-
- override func hideKeyboard() {
- _ = terminalView.resignFirstResponder()
- }
- }
- // MARK: - Layout terminal
- extension VMDisplayTerminalViewController {
- var useAutoLayout: Bool {
- get { true }
- }
-
- func makeFrame (keyboardDelta: CGFloat, _ fn: String = #function, _ ln: Int = #line) -> CGRect
- {
- if useAutoLayout {
- return CGRect.zero
- } else {
- return CGRect (x: view.safeAreaInsets.left,
- y: view.safeAreaInsets.top,
- width: view.frame.width - view.safeAreaInsets.left - view.safeAreaInsets.right,
- height: view.frame.height - view.safeAreaInsets.top - keyboardDelta)
- }
- }
-
- func setupKeyboardMonitor ()
- {
- if #available(iOS 15.0, *), useAutoLayout {
- terminalView.translatesAutoresizingMaskIntoConstraints = false
- terminalView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor).isActive = true
- terminalView.leftAnchor.constraint(equalTo: view.leftAnchor).isActive = true
- terminalView.rightAnchor.constraint(equalTo: view.rightAnchor).isActive = true
-
- terminalView.keyboardLayoutGuide.topAnchor.constraint(equalTo: terminalView.bottomAnchor).isActive = true
- } else {
- NotificationCenter.default.addObserver(
- self,
- selector: #selector(keyboardWillShow),
- name: UIWindow.keyboardWillShowNotification,
- object: nil)
- NotificationCenter.default.addObserver(
- self,
- selector: #selector(keyboardWillHide),
- name: UIWindow.keyboardWillHideNotification,
- object: nil)
- }
- }
-
- @objc private func keyboardWillShow(_ notification: NSNotification) {
- guard let keyboardValue = notification.userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as? NSValue else { return }
-
- let keyboardScreenEndFrame = keyboardValue.cgRectValue
- let keyboardViewEndFrame = view.convert(keyboardScreenEndFrame, from: view.window)
- keyboardDelta = keyboardViewEndFrame.height
- terminalView.frame = makeFrame(keyboardDelta: keyboardViewEndFrame.height)
- }
-
- @objc private func keyboardWillHide(_ notification: NSNotification) {
- //let key = UIResponder.keyboardFrameBeginUserInfoKey
- keyboardDelta = 0
- terminalView.frame = makeFrame(keyboardDelta: 0)
- }
- }
- // MARK: - Style terminal
- extension VMDisplayTerminalViewController {
- private func styleTerminal() {
- guard let style = style else {
- return
- }
- let fontSize = style.fontSize
- let fontName = style.font.rawValue
- if fontName != "" {
- let orig = terminalView.font
- let new = UIFont(name: fontName, size: CGFloat(fontSize)) ?? orig
- terminalView.font = new
- } else {
- let orig = terminalView.font
- let new = UIFont(descriptor: orig.fontDescriptor, size: CGFloat(fontSize))
- terminalView.font = new
- }
- if let consoleTextColor = style.foregroundColor,
- let textColor = Color(hexString: consoleTextColor),
- let consoleBackgroundColor = style.backgroundColor,
- let backgroundColor = Color(hexString: consoleBackgroundColor) {
- terminalView.nativeForegroundColor = UIColor(textColor)
- terminalView.nativeBackgroundColor = UIColor(backgroundColor)
- }
- }
- }
- // MARK: - TerminalViewDelegate
- extension VMDisplayTerminalViewController: TerminalViewDelegate {
- func sizeChanged(source: TerminalView, newCols: Int, newRows: Int) {
- delegate.displayViewSize = CGSize(width: newCols, height: newRows)
- }
-
- func setTerminalTitle(source: TerminalView, title: String) {
- }
-
- func requestOpenLink(source: TerminalView, link: String, params: [String : String]) {
- }
-
- func hostCurrentDirectoryUpdate(source: TerminalView, directory: String?) {
- }
-
- func send(source: TerminalView, data: ArraySlice<UInt8>) {
- delegate.displayDidAssertUserInteraction()
- vmSerialPort.write(Data(data))
- }
-
- func scrolled(source: TerminalView, position: Double) {
- delegate.displayDidAssertUserInteraction()
- }
-
- func bell(source: TerminalView) {
- }
- }
- // MARK: - CSPortDelegate
- extension VMDisplayTerminalViewController: CSPortDelegate {
- func portDidDisconect(_ port: CSPort) {
- }
-
- func port(_ port: CSPort, didError error: String) {
- showAlert(error, actions: nil)
- }
-
- func port(_ port: CSPort, didRecieveData data: Data) {
- if let terminalView = terminalView {
- let arr = [UInt8](data)[...]
- DispatchQueue.main.async {
- terminalView.feed(byteArray: arr)
- }
- }
- }
- }
|