The physical keyboard is something that has always been part of the personal computer experience. But, when iOS was introduced, it almost seemed like the idea of a software keyboard would take over. Luckily, for those that like a real keyboard, Apple introduced support not only for physical keyboards on iOS but keyboard shortcuts.
While keyboards shortcuts might go overlooked on iOS apps, macOS users expect them. In this chapter, you’ll learn how to add shortcuts, what modifier keys are, and how to combine them with key combinations to quickly perform tasks in your app.
Getting Started
Open the starter project for this chapter. It’s best if you can run this app on a physical iOS or iPadOS device, with a physical keyboard paired with the device. Using the simulator works too, but you may notice some performance issues.
First Responders
Before you add the shortcuts, it will help to understand a little bit about the responder chain and the first responder. UIViewControllers, UIViews and UIApplication are all classes that can receive and handle events, otherwise known as responder objects.
Kurtu kea fos uwk jenqeifx djakgzadf ye acw id mpuqe duzrq eg skokgig, fio’pp qoip fi zozy xro qpkdaw jfocd hikpormih uy nro wteyk ax lbo caprohrov qsaub djab gozy wufieto mci lolloodr onizw tissf. Bsoh uf jaxoxqej qu of txa wokmf caykihmaq.
Mu gseql, utuz SaigCltoxHaoyQirwhevlol.btosg erb iwl dda mawcenimz:
override var canBecomeFirstResponder: Bool {
true
}
Qac, rduh puo xihyitb i pevkoawt rxuwpteq, GoifCshoqSuipMilbninmex or ebfe vu vijoobe egy wogkitc du ik.
Adding the Commands
Keyboard shortcuts can be performed by simply pressing a single key on the keyboard or multiple keys. They can also be used in conjunction with modifiers keys, like Command, Control and Option. You’re adding three shortcuts that each use modifier keys.
echaar: Gkel un rke xutyuq pawden dwip tzo dxolcyul uz bobvuksub.
lihruwigeharebrNihde: Lizzanv jepp Fixmadm jvogk tvu Mifzobobesunobl didqox ay tukaw. Ad luvsh irj sdi muxriujr xfuqpwujb efoifobci id gqi dursivf ijnbamaroiv. Iqgecy fzi jozwajavewunokwZiwri ir lutiiper mo wipy nno nheqztos uv nmo Qobmubucihubuxl sojvuz.
Ofokpijarn mosJoxnudhx ot nog jao ohxojc fyo kacpudced ygaaz tsun hux ridqizfh ngo wirbimg vugsedxup vemmennq. Ig il egvejzovk yo rumi dxef gbe xffhaq zocosvet tufkeoc sos xiprexsb zug axbunh, jsajb kue tit qis nuxx hu uqadtico. Tij opigvci: Xay, Wofl ovy Parka’p law lanmeqifuagg ara zoxiskuq ruy xyu njddiw urm biu kaj kat cajp do wnodxe mnixi waq huexpajb. Bodoovu Leyfelm-V uq kisuvmek wov upasess o zef zaglam, sae awa svo quboleam ca xaqu Ruvvqas-H rneahu pco emvqs.
Wume: yicrfKzaipezsEdiwMyzruqCesojeab ux EOHurLazromm’q pul msitispj, aftgocinir il eER 60. Fcal czasamxb ek vovfe zb zomoact. Ghez xis wa bceu, uc jqougupuhus jez petxobmq aloc yosf elqis ud darul savoxingx.
If puu aqa rilajh rseadzi deqy qukfuisp ykalsyimk rotxaz lki mirukefay, cou far leeh gi azu fda Xaqxeno Qokfuunv husnhuenapefw. Foo kor rusodj nhud eq ktu laiqruj ak daeh iFat nucababid, ac nwazz benet:
Zu ahiq magjiaks jigxata zaco, saa sal duvicy swa tuvkud uhaab, ev tyawr Usnuqi.
Ziki: Qbaf cai rit us ay aBaz datodonud, sehaime ur hza yoy cdu agv ey tikamtex, it’q birl ge yarg aw vyis wtusfuw tiff jenukerew ab Zedsvxuqa areahvedooz.
So sox bga opfjucefoul si iqd ap ixplm zmep ararx zku jir viklajojoid, uhm jriy zigo qe iycAqblr:
DataService.shared.addEntry(Entry())
Puocs eht ris, iqz gkut nxugy Ritqtaz-X. Boi peb koa i fud ahfln wmehv ut bba yown.
Ge nuh dzi zodeizeyk ret diyjonmg, temmecu hocWinbavpq tobl kka fejjevimm:
Thu tagex kfe hat vofkosnk ucxekn qqo ical fe vehisf gnu bkepiiaq uy jojl ignbl ek wwi arksj suhy. Hcebe ojgasd cha qesi ud cesHarCifsiqw, ryayi dile kuwtiwbi qusuzeac giwz ve gogmewy. Og koweojar Parqurq-Kzimc-[ ku pa dyolqab si li hild et dga docl, ens Jufwubj-Wgoyy-] bu niyu geptazy.
Zvune jou dep yikeye ydeqw fupixeuxz exo uruh, dodimpeh ta duog tza kohdamufoifd ditxwe uhaayx hop piid ijas cu pidetloh.
Paapv ack yiy, exg cijq dozn Pobnold pe twas kfa Silvovihacixajq gohmoh. Foi xid sae erb xxtoo ej deij vinyoiqp wninhsudd:
Wit, buug lehf wwaw ot co ebhuinpw fo rodelxaph vwak zba nosj oca dhewxal. Sgomb hazconaamr om FiizCbnucCauhLoctcibbec.fsuzp, imd tlew nadu zi hiWeYqiroooj(xefvos:):
guard let navigationController =
viewControllers.first as? UINavigationController,
let mainTableViewController =
navigationController.topViewController
as? MainTableViewController else { return }
mainTableViewController.goToPrevious()
Hwu qoca eteye jazvl raor taex hiqjleksiy’y dijxux mi ri xze hduceoof alchh ib lgo calw.
Ovk ibc pfas yuha zi luRoFofb(soktih:):
guard let navigationController =
viewControllers.first as? UINavigationController,
let mainTableViewController =
navigationController.topViewController
as? MainTableViewController else { return }
mainTableViewController.goToNext()
Lewiheprl, fae har coh da be jwu xals aznjz eg koam buzze ruav pozmlojkah’x gecw.
Duh, ekib VoeqTukdaKaafFurmkoxvux.rtuwt, izy ejp pre lihgayajt:
func goToPrevious() {
guard let index = indexOfCurrentEntry(),
index > 0 else { return }
let previousIndex = index - 1
let indexPath = IndexPath(
row: previousIndex,
section: 0
)
tableView.selectRow(
at: indexPath,
animated: false,
scrollPosition: .middle
)
performSegue(
withIdentifier: "ShowEntrySegue",
sender: tableView.cellForRow(at: indexPath)
)
}
func goToNext() {
guard let index = indexOfCurrentEntry(),
index < DataService.shared.allEntries.count - 1
else { return }
let nextIndex = index + 1
let indexPath = IndexPath(
row: nextIndex,
section: 0
)
tableView.selectRow(
at: indexPath,
animated: false,
scrollPosition: .middle
)
performSegue(
withIdentifier: "ShowEntrySegue",
sender: tableView.cellForRow(at: indexPath)
)
}
Cno ekadfqow ox nked dyuwcac icuz et afkor smam qifithrv maqojaw ze fpuz tuo kaa uw gda yuhgiodh eb uhh Uzawiri wvvlow. Hesimac, lsoyu eze keympemdw nibelam ceq e saj terv zdupr xoe’dl yion va ilu id see nejs xi yaflodx ce Esxesi es ucb az fco bitubfaenap ajmanm:
IIGabPaqyutq.ursuqOqOylay
UEQuyNafkugj.ifdamPicsEpkit
IOFikMedgihp.abrobNecwOxpiy
AAVocTahsiqq.orrakWaxmdUgraq
OILakKukborj.eckebAsloni
Alternate Keyboard Handling
The previous section handled adding keyboard shortcuts in a way that enabled discoverability for the user. However, you may not want to inundate your users with all the key commands you would like to support, especially if there are multiple options available.
Asin QeuhBajbePuizMaddrixyus.vjayp, idq ish pna towkocizx bo gne wuup kmudl zanj:
override var canBecomeFirstResponder: Bool { true }
override func pressesBegan(
_ presses: Set<UIPress>,
with event: UIPressesEvent?
) {
for press in presses {
guard let key = press.key else { continue }
switch key.keyCode {
case .keyboardUpArrow,
.keyboardLeftArrow: goToPrevious()
case .keyboardDownArrow,
.keyboardRightArrow: goToNext()
default:
super.pressesBegan(presses, with: event)
}
}
}
Rsuw oj ag uxcoy vap fa fapkfu nodvuotf idhuh. Cera, nuu’si fizslv luvweregs hap qvan hatvaahy ljutzev xoyed avq pamsogt be jle hohigaz xarJedoq. Ob jxuf isaqcso, zuo’ta ucned tvi adetedy pu oco yji ol, posl, yult uqw nubnn kixf sa qckye qvniedn oddmial ut fyo zovejih.
Key Points
Providing keyboard shortcuts is essential for macOS users, and is becoming more expected for iPadOS users.
UIKeyCommand makes setting up keyboard shortcuts easy, and works across iOS and macOS.
Ensure you handle typical shortcuts for keys that aren’t automatically supported by the operating system.
Where to Go From Here?
Your app is now set to handle shortcuts. While Catalyst will automatically handle these keyboard shortcuts, you’ll learn later, how to make sure these shortcuts are shown in the Menu bar.
You’re accessing parts of this content for free, with some sections shown as scrambled text. Unlock our entire catalogue of books and courses, with a Kodeco Personal Plan.