diff --git a/Mini vMac.xcodeproj/project.pbxproj b/Mini vMac.xcodeproj/project.pbxproj index f4e29d7..10d35ca 100644 --- a/Mini vMac.xcodeproj/project.pbxproj +++ b/Mini vMac.xcodeproj/project.pbxproj @@ -9,6 +9,10 @@ /* Begin PBXBuildFile section */ 28848B621CDE97D600B86C45 /* InsertDiskViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 28848B611CDE97D600B86C45 /* InsertDiskViewController.m */; }; 28848B651CDE97E900B86C45 /* SettingsViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 28848B641CDE97E900B86C45 /* SettingsViewController.m */; }; + 28BA897E1CE7315400A98104 /* KBKey.m in Sources */ = {isa = PBXBuildFile; fileRef = 28BA89751CE7315400A98104 /* KBKey.m */; }; + 28BA897F1CE7315400A98104 /* KBKeyboardLayout.m in Sources */ = {isa = PBXBuildFile; fileRef = 28BA89771CE7315400A98104 /* KBKeyboardLayout.m */; }; + 28BA89801CE7315400A98104 /* KBKeyboardView.m in Sources */ = {isa = PBXBuildFile; fileRef = 28BA89791CE7315400A98104 /* KBKeyboardView.m */; }; + 28BA89821CE7336500A98104 /* Keyboard Layouts in Resources */ = {isa = PBXBuildFile; fileRef = 28BA89811CE7336500A98104 /* Keyboard Layouts */; }; 28CE8EB51CD4C3B200FE25A8 /* GLOBGLUE.c in Sources */ = {isa = PBXBuildFile; fileRef = 28CE8E931CD4C3B200FE25A8 /* GLOBGLUE.c */; }; 28CE8EB61CD4C3B200FE25A8 /* IWMEMDEV.c in Sources */ = {isa = PBXBuildFile; fileRef = 28CE8E961CD4C3B200FE25A8 /* IWMEMDEV.c */; }; 28CE8EB71CD4C3B200FE25A8 /* KBRDEMDV.c in Sources */ = {isa = PBXBuildFile; fileRef = 28CE8E981CD4C3B200FE25A8 /* KBRDEMDV.c */; }; @@ -40,6 +44,13 @@ 28848B611CDE97D600B86C45 /* InsertDiskViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = InsertDiskViewController.m; sourceTree = ""; }; 28848B631CDE97E900B86C45 /* SettingsViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SettingsViewController.h; sourceTree = ""; }; 28848B641CDE97E900B86C45 /* SettingsViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SettingsViewController.m; sourceTree = ""; }; + 28BA89741CE7315400A98104 /* KBKey.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = KBKey.h; sourceTree = ""; }; + 28BA89751CE7315400A98104 /* KBKey.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = KBKey.m; sourceTree = ""; }; + 28BA89761CE7315400A98104 /* KBKeyboardLayout.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = KBKeyboardLayout.h; sourceTree = ""; }; + 28BA89771CE7315400A98104 /* KBKeyboardLayout.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = KBKeyboardLayout.m; sourceTree = ""; }; + 28BA89781CE7315400A98104 /* KBKeyboardView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = KBKeyboardView.h; sourceTree = ""; }; + 28BA89791CE7315400A98104 /* KBKeyboardView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = KBKeyboardView.m; sourceTree = ""; }; + 28BA89811CE7336500A98104 /* Keyboard Layouts */ = {isa = PBXFileReference; lastKnownFileType = folder; path = "Keyboard Layouts"; sourceTree = ""; }; 28CE8E881CD4C33E00FE25A8 /* CNFGGLOB.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CNFGGLOB.h; sourceTree = ""; }; 28CE8E891CD4C33E00FE25A8 /* CNFGRAPI.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CNFGRAPI.h; sourceTree = ""; }; 28CE8E8A1CD4C33E00FE25A8 /* EMCONFIG.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = EMCONFIG.h; sourceTree = ""; }; @@ -109,6 +120,20 @@ /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ + 28BA896E1CE7314500A98104 /* Keyboard */ = { + isa = PBXGroup; + children = ( + 28BA89811CE7336500A98104 /* Keyboard Layouts */, + 28BA89741CE7315400A98104 /* KBKey.h */, + 28BA89751CE7315400A98104 /* KBKey.m */, + 28BA89761CE7315400A98104 /* KBKeyboardLayout.h */, + 28BA89771CE7315400A98104 /* KBKeyboardLayout.m */, + 28BA89781CE7315400A98104 /* KBKeyboardView.h */, + 28BA89791CE7315400A98104 /* KBKeyboardView.m */, + ); + name = Keyboard; + sourceTree = ""; + }; 28CE8E871CD4C33E00FE25A8 /* mnvm_cfg */ = { isa = PBXGroup; children = ( @@ -198,6 +223,7 @@ 28848B641CDE97E900B86C45 /* SettingsViewController.m */, 28F676C91CD15E0B00FC6FA6 /* Main.storyboard */, 28F676CC1CD15E0B00FC6FA6 /* Assets.xcassets */, + 28BA896E1CE7314500A98104 /* Keyboard */, 28F676CE1CD15E0B00FC6FA6 /* LaunchScreen.storyboard */, 28F676D11CD15E0B00FC6FA6 /* Info.plist */, 28CE8E8E1CD4C3B200FE25A8 /* mnvm_core */, @@ -274,6 +300,7 @@ files = ( 28F676D01CD15E0B00FC6FA6 /* LaunchScreen.storyboard in Resources */, 28F676CD1CD15E0B00FC6FA6 /* Assets.xcassets in Resources */, + 28BA89821CE7336500A98104 /* Keyboard Layouts in Resources */, 28F676CB1CD15E0B00FC6FA6 /* Main.storyboard in Resources */, ); runOnlyForDeploymentPostprocessing = 0; @@ -285,6 +312,7 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + 28BA897E1CE7315400A98104 /* KBKey.m in Sources */, 28CE8EC01CD4C3B200FE25A8 /* SCSIEMDV.c in Sources */, 28CE8EC11CD4C3B200FE25A8 /* SNDEMDEV.c in Sources */, 28CE8EB51CD4C3B200FE25A8 /* GLOBGLUE.c in Sources */, @@ -299,12 +327,14 @@ 28848B651CDE97E900B86C45 /* SettingsViewController.m in Sources */, 28CE8EB71CD4C3B200FE25A8 /* KBRDEMDV.c in Sources */, 28CE8EBC1CD4C3B200FE25A8 /* ROMEMDEV.c in Sources */, + 28BA897F1CE7315400A98104 /* KBKeyboardLayout.m in Sources */, 28CE8EBB1CD4C3B200FE25A8 /* PROGMAIN.c in Sources */, 28848B621CDE97D600B86C45 /* InsertDiskViewController.m in Sources */, 28F676C81CD15E0B00FC6FA6 /* ViewController.m in Sources */, 28D5A3FD1CD6868F001A33F6 /* TouchScreen.m in Sources */, 28CE8EC21CD4C3B200FE25A8 /* SONYEMDV.c in Sources */, 28F676C51CD15E0B00FC6FA6 /* AppDelegate.m in Sources */, + 28BA89801CE7315400A98104 /* KBKeyboardView.m in Sources */, 28CE8EBE1CD4C3B200FE25A8 /* SCCEMDEV.c in Sources */, 28CE8ECC1CD4CDC500FE25A8 /* MYOSGLUE.m in Sources */, 28F676C21CD15E0B00FC6FA6 /* main.m in Sources */, diff --git a/Mini vMac/AppDelegate.h b/Mini vMac/AppDelegate.h index fd7103b..2f627d2 100644 --- a/Mini vMac/AppDelegate.h +++ b/Mini vMac/AppDelegate.h @@ -38,6 +38,9 @@ typedef enum : NSUInteger { - (void)moveMouseX:(NSInteger)x Y:(NSInteger)y; - (void)setMouseButton:(BOOL)down; +- (void)keyDown:(int)scancode; +- (void)keyUp:(int)scancode; + - (BOOL)insertDisk:(NSString*)path; - (BOOL)isDiskInserted:(NSString*)path; diff --git a/Mini vMac/AppDelegate.m b/Mini vMac/AppDelegate.m index 6bf6306..9a784ba 100644 --- a/Mini vMac/AppDelegate.m +++ b/Mini vMac/AppDelegate.m @@ -22,6 +22,7 @@ IMPORTPROC SetMouseDelta(ui4r dh, ui4r dv); IMPORTFUNC blnr Sony_Insert1(NSString *filePath, blnr silentfail); IMPORTFUNC blnr Sony_IsInserted(NSString *filePath); EXPORTVAR(ui3b,SpeedValue); +IMPORTPROC SetKeyState(int key, blnr down); static AppDelegate *sharedAppDelegate = nil; NSString * const MNVMDidInsertDiskNotification = @"MNVMDidInsertDisk"; @@ -40,10 +41,18 @@ NSString * const MNVMDidEjectDiskNotification = @"MNVMDidEjectDisk"; - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { sharedAppDelegate = self; - // TODO: setup settings + // default settings + NSString *defaultKeyboardLayout = @"US.nfkeyboardlayout"; + NSLocale *locale = [NSLocale currentLocale]; + if ([[locale objectForKey:NSLocaleCountryCode] isEqualToString:@"GB"]) { + defaultKeyboardLayout = @"British.nfkeyboardlayout"; + } else if ([[locale objectForKey:NSLocaleLanguageCode] isEqualToString:@"es"]) { + defaultKeyboardLayout = @"Spanish.nfkeyboardlayout"; + } NSDictionary *defaults = @{@"speedValue": @(WantInitSpeedValue), @"trackpad": @([UIDevice currentDevice].userInterfaceIdiom != UIUserInterfaceIdiomPad), - @"frameskip": @(0) + @"frameskip": @(0), + @"keyboardLayout": defaultKeyboardLayout }; [[NSUserDefaults standardUserDefaults] registerDefaults:defaults]; @@ -206,6 +215,27 @@ NSString * const MNVMDidEjectDiskNotification = @"MNVMDidEjectDisk"; SetMouseButton(down); } +#pragma mark - Keyboard + +- (int)translateScanCode:(int)scancode { + switch (scancode) { + case 54: return 59; // left control + case 59: return 70; // arrow left + case 60: return 66; // arrow right + case 61: return 72; // arrow down + case 62: return 77; // arrow up + default: return scancode; + } +} + +- (void)keyDown:(int)scancode { + SetKeyState([self translateScanCode:scancode], true); +} + +- (void)keyUp:(int)scancode { + SetKeyState([self translateScanCode:scancode], false); +} + #pragma mark - Disk Drive - (BOOL)insertDisk:(NSString *)path { diff --git a/Mini vMac/Assets.xcassets/KBCapsLock.imageset/Contents.json b/Mini vMac/Assets.xcassets/KBCapsLock.imageset/Contents.json new file mode 100644 index 0000000..cbe56fb --- /dev/null +++ b/Mini vMac/Assets.xcassets/KBCapsLock.imageset/Contents.json @@ -0,0 +1,32 @@ +{ + "images" : [ + { + "idiom" : "iphone", + "scale" : "1x" + }, + { + "idiom" : "iphone", + "filename" : "KBCapsLock~iphone@2x.png", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "filename" : "KBCapsLock~iphone@3x.png", + "scale" : "3x" + }, + { + "idiom" : "ipad", + "filename" : "KBCapsLock~ipad.png", + "scale" : "1x" + }, + { + "idiom" : "ipad", + "filename" : "KBCapsLock~ipad@2x.png", + "scale" : "2x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Mini vMac/Assets.xcassets/KBCapsLock.imageset/KBCapsLock~ipad.png b/Mini vMac/Assets.xcassets/KBCapsLock.imageset/KBCapsLock~ipad.png new file mode 100644 index 0000000..b5bb1b3 Binary files /dev/null and b/Mini vMac/Assets.xcassets/KBCapsLock.imageset/KBCapsLock~ipad.png differ diff --git a/Mini vMac/Assets.xcassets/KBCapsLock.imageset/KBCapsLock~ipad@2x.png b/Mini vMac/Assets.xcassets/KBCapsLock.imageset/KBCapsLock~ipad@2x.png new file mode 100644 index 0000000..1032731 Binary files /dev/null and b/Mini vMac/Assets.xcassets/KBCapsLock.imageset/KBCapsLock~ipad@2x.png differ diff --git a/Mini vMac/Assets.xcassets/KBCapsLock.imageset/KBCapsLock~iphone@2x.png b/Mini vMac/Assets.xcassets/KBCapsLock.imageset/KBCapsLock~iphone@2x.png new file mode 100644 index 0000000..2ffc046 Binary files /dev/null and b/Mini vMac/Assets.xcassets/KBCapsLock.imageset/KBCapsLock~iphone@2x.png differ diff --git a/Mini vMac/Assets.xcassets/KBCapsLock.imageset/KBCapsLock~iphone@3x.png b/Mini vMac/Assets.xcassets/KBCapsLock.imageset/KBCapsLock~iphone@3x.png new file mode 100644 index 0000000..1dfefcf Binary files /dev/null and b/Mini vMac/Assets.xcassets/KBCapsLock.imageset/KBCapsLock~iphone@3x.png differ diff --git a/Mini vMac/Assets.xcassets/KBClearDown.imageset/Contents.json b/Mini vMac/Assets.xcassets/KBClearDown.imageset/Contents.json new file mode 100644 index 0000000..07d949d --- /dev/null +++ b/Mini vMac/Assets.xcassets/KBClearDown.imageset/Contents.json @@ -0,0 +1,32 @@ +{ + "images" : [ + { + "idiom" : "iphone", + "scale" : "1x" + }, + { + "idiom" : "iphone", + "filename" : "KBClearDown~iphone@2x.png", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "filename" : "KBClearDown~iphone@3x.png", + "scale" : "3x" + }, + { + "idiom" : "ipad", + "filename" : "KBClearDown~ipad.png", + "scale" : "1x" + }, + { + "idiom" : "ipad", + "filename" : "KBClearDown~ipad@2x.png", + "scale" : "2x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Mini vMac/Assets.xcassets/KBClearDown.imageset/KBClearDown~ipad.png b/Mini vMac/Assets.xcassets/KBClearDown.imageset/KBClearDown~ipad.png new file mode 100644 index 0000000..3ca10ed Binary files /dev/null and b/Mini vMac/Assets.xcassets/KBClearDown.imageset/KBClearDown~ipad.png differ diff --git a/Mini vMac/Assets.xcassets/KBClearDown.imageset/KBClearDown~ipad@2x.png b/Mini vMac/Assets.xcassets/KBClearDown.imageset/KBClearDown~ipad@2x.png new file mode 100644 index 0000000..d35aecb Binary files /dev/null and b/Mini vMac/Assets.xcassets/KBClearDown.imageset/KBClearDown~ipad@2x.png differ diff --git a/Mini vMac/Assets.xcassets/KBClearDown.imageset/KBClearDown~iphone@2x.png b/Mini vMac/Assets.xcassets/KBClearDown.imageset/KBClearDown~iphone@2x.png new file mode 100644 index 0000000..1063c2a Binary files /dev/null and b/Mini vMac/Assets.xcassets/KBClearDown.imageset/KBClearDown~iphone@2x.png differ diff --git a/Mini vMac/Assets.xcassets/KBClearDown.imageset/KBClearDown~iphone@3x.png b/Mini vMac/Assets.xcassets/KBClearDown.imageset/KBClearDown~iphone@3x.png new file mode 100644 index 0000000..2093155 Binary files /dev/null and b/Mini vMac/Assets.xcassets/KBClearDown.imageset/KBClearDown~iphone@3x.png differ diff --git a/Mini vMac/Assets.xcassets/KBClearUp.imageset/Contents.json b/Mini vMac/Assets.xcassets/KBClearUp.imageset/Contents.json new file mode 100644 index 0000000..83c2f96 --- /dev/null +++ b/Mini vMac/Assets.xcassets/KBClearUp.imageset/Contents.json @@ -0,0 +1,32 @@ +{ + "images" : [ + { + "idiom" : "iphone", + "scale" : "1x" + }, + { + "idiom" : "iphone", + "filename" : "KBClearUp~iphone.png", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "filename" : "KBClearUp~iphone@3x.png", + "scale" : "3x" + }, + { + "idiom" : "ipad", + "filename" : "KBClearUp~ipad.png", + "scale" : "1x" + }, + { + "idiom" : "ipad", + "filename" : "KBClearUp~ipad@2x.png", + "scale" : "2x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Mini vMac/Assets.xcassets/KBClearUp.imageset/KBClearUp~ipad.png b/Mini vMac/Assets.xcassets/KBClearUp.imageset/KBClearUp~ipad.png new file mode 100644 index 0000000..e4299d8 Binary files /dev/null and b/Mini vMac/Assets.xcassets/KBClearUp.imageset/KBClearUp~ipad.png differ diff --git a/Mini vMac/Assets.xcassets/KBClearUp.imageset/KBClearUp~ipad@2x.png b/Mini vMac/Assets.xcassets/KBClearUp.imageset/KBClearUp~ipad@2x.png new file mode 100644 index 0000000..0ae8d68 Binary files /dev/null and b/Mini vMac/Assets.xcassets/KBClearUp.imageset/KBClearUp~ipad@2x.png differ diff --git a/Mini vMac/Assets.xcassets/KBClearUp.imageset/KBClearUp~iphone.png b/Mini vMac/Assets.xcassets/KBClearUp.imageset/KBClearUp~iphone.png new file mode 100644 index 0000000..8cd1f63 Binary files /dev/null and b/Mini vMac/Assets.xcassets/KBClearUp.imageset/KBClearUp~iphone.png differ diff --git a/Mini vMac/Assets.xcassets/KBClearUp.imageset/KBClearUp~iphone@3x.png b/Mini vMac/Assets.xcassets/KBClearUp.imageset/KBClearUp~iphone@3x.png new file mode 100644 index 0000000..b08a3c7 Binary files /dev/null and b/Mini vMac/Assets.xcassets/KBClearUp.imageset/KBClearUp~iphone@3x.png differ diff --git a/Mini vMac/Assets.xcassets/KBCommand.imageset/Contents.json b/Mini vMac/Assets.xcassets/KBCommand.imageset/Contents.json new file mode 100644 index 0000000..ed1d2ce --- /dev/null +++ b/Mini vMac/Assets.xcassets/KBCommand.imageset/Contents.json @@ -0,0 +1,32 @@ +{ + "images" : [ + { + "idiom" : "iphone", + "scale" : "1x" + }, + { + "idiom" : "iphone", + "filename" : "KBKeyCommand@2x.png", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "filename" : "KBKeyCommand@3x.png", + "scale" : "3x" + }, + { + "idiom" : "ipad", + "filename" : "KBCommand~ipad.png", + "scale" : "1x" + }, + { + "idiom" : "ipad", + "filename" : "KBCommand@2x~ipad.png", + "scale" : "2x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Mini vMac/Assets.xcassets/KBCommand.imageset/KBCommand@2x~ipad.png b/Mini vMac/Assets.xcassets/KBCommand.imageset/KBCommand@2x~ipad.png new file mode 100644 index 0000000..629a05f Binary files /dev/null and b/Mini vMac/Assets.xcassets/KBCommand.imageset/KBCommand@2x~ipad.png differ diff --git a/Mini vMac/Assets.xcassets/KBCommand.imageset/KBCommand~ipad.png b/Mini vMac/Assets.xcassets/KBCommand.imageset/KBCommand~ipad.png new file mode 100644 index 0000000..3cf7f7b Binary files /dev/null and b/Mini vMac/Assets.xcassets/KBCommand.imageset/KBCommand~ipad.png differ diff --git a/Mini vMac/Assets.xcassets/KBCommand.imageset/KBKeyCommand@2x.png b/Mini vMac/Assets.xcassets/KBCommand.imageset/KBKeyCommand@2x.png new file mode 100644 index 0000000..8480dcd Binary files /dev/null and b/Mini vMac/Assets.xcassets/KBCommand.imageset/KBKeyCommand@2x.png differ diff --git a/Mini vMac/Assets.xcassets/KBCommand.imageset/KBKeyCommand@3x.png b/Mini vMac/Assets.xcassets/KBCommand.imageset/KBKeyCommand@3x.png new file mode 100644 index 0000000..f8ab3ae Binary files /dev/null and b/Mini vMac/Assets.xcassets/KBCommand.imageset/KBKeyCommand@3x.png differ diff --git a/Mini vMac/Assets.xcassets/KBDeleteDown.imageset/Contents.json b/Mini vMac/Assets.xcassets/KBDeleteDown.imageset/Contents.json new file mode 100644 index 0000000..a201c9c --- /dev/null +++ b/Mini vMac/Assets.xcassets/KBDeleteDown.imageset/Contents.json @@ -0,0 +1,32 @@ +{ + "images" : [ + { + "idiom" : "iphone", + "scale" : "1x" + }, + { + "idiom" : "iphone", + "filename" : "KBDeleteDown~iphone@2x.png", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "filename" : "KBDeleteDown~iphone@3x.png", + "scale" : "3x" + }, + { + "idiom" : "ipad", + "filename" : "KBDeleteDown~ipad.png", + "scale" : "1x" + }, + { + "idiom" : "ipad", + "filename" : "KBDeleteDown~ipad@2x.png", + "scale" : "2x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Mini vMac/Assets.xcassets/KBDeleteDown.imageset/KBDeleteDown~ipad.png b/Mini vMac/Assets.xcassets/KBDeleteDown.imageset/KBDeleteDown~ipad.png new file mode 100644 index 0000000..49a4bbf Binary files /dev/null and b/Mini vMac/Assets.xcassets/KBDeleteDown.imageset/KBDeleteDown~ipad.png differ diff --git a/Mini vMac/Assets.xcassets/KBDeleteDown.imageset/KBDeleteDown~ipad@2x.png b/Mini vMac/Assets.xcassets/KBDeleteDown.imageset/KBDeleteDown~ipad@2x.png new file mode 100644 index 0000000..4ee72f6 Binary files /dev/null and b/Mini vMac/Assets.xcassets/KBDeleteDown.imageset/KBDeleteDown~ipad@2x.png differ diff --git a/Mini vMac/Assets.xcassets/KBDeleteDown.imageset/KBDeleteDown~iphone@2x.png b/Mini vMac/Assets.xcassets/KBDeleteDown.imageset/KBDeleteDown~iphone@2x.png new file mode 100644 index 0000000..d0e7eb9 Binary files /dev/null and b/Mini vMac/Assets.xcassets/KBDeleteDown.imageset/KBDeleteDown~iphone@2x.png differ diff --git a/Mini vMac/Assets.xcassets/KBDeleteDown.imageset/KBDeleteDown~iphone@3x.png b/Mini vMac/Assets.xcassets/KBDeleteDown.imageset/KBDeleteDown~iphone@3x.png new file mode 100644 index 0000000..2e22755 Binary files /dev/null and b/Mini vMac/Assets.xcassets/KBDeleteDown.imageset/KBDeleteDown~iphone@3x.png differ diff --git a/Mini vMac/Assets.xcassets/KBDeleteUp.imageset/Contents.json b/Mini vMac/Assets.xcassets/KBDeleteUp.imageset/Contents.json new file mode 100644 index 0000000..5d79b1a --- /dev/null +++ b/Mini vMac/Assets.xcassets/KBDeleteUp.imageset/Contents.json @@ -0,0 +1,32 @@ +{ + "images" : [ + { + "idiom" : "iphone", + "scale" : "1x" + }, + { + "idiom" : "iphone", + "filename" : "KBDeleteUp~iphone.png", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "filename" : "KBDeleteUp~iphone@3x.png", + "scale" : "3x" + }, + { + "idiom" : "ipad", + "filename" : "KBDeleteUp~ipad.png", + "scale" : "1x" + }, + { + "idiom" : "ipad", + "filename" : "KBDeleteUp~ipad@2x.png", + "scale" : "2x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Mini vMac/Assets.xcassets/KBDeleteUp.imageset/KBDeleteUp~ipad.png b/Mini vMac/Assets.xcassets/KBDeleteUp.imageset/KBDeleteUp~ipad.png new file mode 100644 index 0000000..fd49494 Binary files /dev/null and b/Mini vMac/Assets.xcassets/KBDeleteUp.imageset/KBDeleteUp~ipad.png differ diff --git a/Mini vMac/Assets.xcassets/KBDeleteUp.imageset/KBDeleteUp~ipad@2x.png b/Mini vMac/Assets.xcassets/KBDeleteUp.imageset/KBDeleteUp~ipad@2x.png new file mode 100644 index 0000000..ab4c7ef Binary files /dev/null and b/Mini vMac/Assets.xcassets/KBDeleteUp.imageset/KBDeleteUp~ipad@2x.png differ diff --git a/Mini vMac/Assets.xcassets/KBDeleteUp.imageset/KBDeleteUp~iphone.png b/Mini vMac/Assets.xcassets/KBDeleteUp.imageset/KBDeleteUp~iphone.png new file mode 100644 index 0000000..43d9059 Binary files /dev/null and b/Mini vMac/Assets.xcassets/KBDeleteUp.imageset/KBDeleteUp~iphone.png differ diff --git a/Mini vMac/Assets.xcassets/KBDeleteUp.imageset/KBDeleteUp~iphone@3x.png b/Mini vMac/Assets.xcassets/KBDeleteUp.imageset/KBDeleteUp~iphone@3x.png new file mode 100644 index 0000000..85ede96 Binary files /dev/null and b/Mini vMac/Assets.xcassets/KBDeleteUp.imageset/KBDeleteUp~iphone@3x.png differ diff --git a/Mini vMac/Assets.xcassets/KBForwardDeleteDown.imageset/Contents.json b/Mini vMac/Assets.xcassets/KBForwardDeleteDown.imageset/Contents.json new file mode 100644 index 0000000..4fccb24 --- /dev/null +++ b/Mini vMac/Assets.xcassets/KBForwardDeleteDown.imageset/Contents.json @@ -0,0 +1,32 @@ +{ + "images" : [ + { + "idiom" : "iphone", + "scale" : "1x" + }, + { + "idiom" : "iphone", + "filename" : "KBForwardDeleteDown~iphone@2x.png", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "filename" : "KBForwardDeleteDown~iphone@3x.png", + "scale" : "3x" + }, + { + "idiom" : "ipad", + "filename" : "KBForwardDeleteDown~ipad.png", + "scale" : "1x" + }, + { + "idiom" : "ipad", + "filename" : "KBForwardDeleteDown~ipad@2x.png", + "scale" : "2x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Mini vMac/Assets.xcassets/KBForwardDeleteDown.imageset/KBForwardDeleteDown~ipad.png b/Mini vMac/Assets.xcassets/KBForwardDeleteDown.imageset/KBForwardDeleteDown~ipad.png new file mode 100644 index 0000000..16baf7f Binary files /dev/null and b/Mini vMac/Assets.xcassets/KBForwardDeleteDown.imageset/KBForwardDeleteDown~ipad.png differ diff --git a/Mini vMac/Assets.xcassets/KBForwardDeleteDown.imageset/KBForwardDeleteDown~ipad@2x.png b/Mini vMac/Assets.xcassets/KBForwardDeleteDown.imageset/KBForwardDeleteDown~ipad@2x.png new file mode 100644 index 0000000..b3de016 Binary files /dev/null and b/Mini vMac/Assets.xcassets/KBForwardDeleteDown.imageset/KBForwardDeleteDown~ipad@2x.png differ diff --git a/Mini vMac/Assets.xcassets/KBForwardDeleteDown.imageset/KBForwardDeleteDown~iphone@2x.png b/Mini vMac/Assets.xcassets/KBForwardDeleteDown.imageset/KBForwardDeleteDown~iphone@2x.png new file mode 100644 index 0000000..94d8897 Binary files /dev/null and b/Mini vMac/Assets.xcassets/KBForwardDeleteDown.imageset/KBForwardDeleteDown~iphone@2x.png differ diff --git a/Mini vMac/Assets.xcassets/KBForwardDeleteDown.imageset/KBForwardDeleteDown~iphone@3x.png b/Mini vMac/Assets.xcassets/KBForwardDeleteDown.imageset/KBForwardDeleteDown~iphone@3x.png new file mode 100644 index 0000000..e282e07 Binary files /dev/null and b/Mini vMac/Assets.xcassets/KBForwardDeleteDown.imageset/KBForwardDeleteDown~iphone@3x.png differ diff --git a/Mini vMac/Assets.xcassets/KBForwardDeleteUp.imageset/Contents.json b/Mini vMac/Assets.xcassets/KBForwardDeleteUp.imageset/Contents.json new file mode 100644 index 0000000..9b6aa14 --- /dev/null +++ b/Mini vMac/Assets.xcassets/KBForwardDeleteUp.imageset/Contents.json @@ -0,0 +1,32 @@ +{ + "images" : [ + { + "idiom" : "iphone", + "scale" : "1x" + }, + { + "idiom" : "iphone", + "filename" : "KBForwardDeleteUp~iphone.png", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "filename" : "KBForwardDeleteUp~iphone@3x.png", + "scale" : "3x" + }, + { + "idiom" : "ipad", + "filename" : "KBForwardDeleteUp~ipad.png", + "scale" : "1x" + }, + { + "idiom" : "ipad", + "filename" : "KBForwardDeleteUp~ipad@2x.png", + "scale" : "2x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Mini vMac/Assets.xcassets/KBForwardDeleteUp.imageset/KBForwardDeleteUp~ipad.png b/Mini vMac/Assets.xcassets/KBForwardDeleteUp.imageset/KBForwardDeleteUp~ipad.png new file mode 100644 index 0000000..5227be6 Binary files /dev/null and b/Mini vMac/Assets.xcassets/KBForwardDeleteUp.imageset/KBForwardDeleteUp~ipad.png differ diff --git a/Mini vMac/Assets.xcassets/KBForwardDeleteUp.imageset/KBForwardDeleteUp~ipad@2x.png b/Mini vMac/Assets.xcassets/KBForwardDeleteUp.imageset/KBForwardDeleteUp~ipad@2x.png new file mode 100644 index 0000000..26644fd Binary files /dev/null and b/Mini vMac/Assets.xcassets/KBForwardDeleteUp.imageset/KBForwardDeleteUp~ipad@2x.png differ diff --git a/Mini vMac/Assets.xcassets/KBForwardDeleteUp.imageset/KBForwardDeleteUp~iphone.png b/Mini vMac/Assets.xcassets/KBForwardDeleteUp.imageset/KBForwardDeleteUp~iphone.png new file mode 100644 index 0000000..3c93b80 Binary files /dev/null and b/Mini vMac/Assets.xcassets/KBForwardDeleteUp.imageset/KBForwardDeleteUp~iphone.png differ diff --git a/Mini vMac/Assets.xcassets/KBForwardDeleteUp.imageset/KBForwardDeleteUp~iphone@3x.png b/Mini vMac/Assets.xcassets/KBForwardDeleteUp.imageset/KBForwardDeleteUp~iphone@3x.png new file mode 100644 index 0000000..b39aca3 Binary files /dev/null and b/Mini vMac/Assets.xcassets/KBForwardDeleteUp.imageset/KBForwardDeleteUp~iphone@3x.png differ diff --git a/Mini vMac/Assets.xcassets/KBHide.imageset/Contents.json b/Mini vMac/Assets.xcassets/KBHide.imageset/Contents.json new file mode 100644 index 0000000..c09f57b --- /dev/null +++ b/Mini vMac/Assets.xcassets/KBHide.imageset/Contents.json @@ -0,0 +1,32 @@ +{ + "images" : [ + { + "idiom" : "iphone", + "scale" : "1x" + }, + { + "idiom" : "iphone", + "filename" : "KBHide~iphone@2x.png", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "filename" : "KBHide~iphone@3x.png", + "scale" : "3x" + }, + { + "idiom" : "ipad", + "filename" : "KBHide~ipad.png", + "scale" : "1x" + }, + { + "idiom" : "ipad", + "filename" : "KBHide~ipad@2x.png", + "scale" : "2x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Mini vMac/Assets.xcassets/KBHide.imageset/KBHide~ipad.png b/Mini vMac/Assets.xcassets/KBHide.imageset/KBHide~ipad.png new file mode 100644 index 0000000..2c28bb8 Binary files /dev/null and b/Mini vMac/Assets.xcassets/KBHide.imageset/KBHide~ipad.png differ diff --git a/Mini vMac/Assets.xcassets/KBHide.imageset/KBHide~ipad@2x.png b/Mini vMac/Assets.xcassets/KBHide.imageset/KBHide~ipad@2x.png new file mode 100644 index 0000000..faa6196 Binary files /dev/null and b/Mini vMac/Assets.xcassets/KBHide.imageset/KBHide~ipad@2x.png differ diff --git a/Mini vMac/Assets.xcassets/KBHide.imageset/KBHide~iphone@2x.png b/Mini vMac/Assets.xcassets/KBHide.imageset/KBHide~iphone@2x.png new file mode 100644 index 0000000..6c5101b Binary files /dev/null and b/Mini vMac/Assets.xcassets/KBHide.imageset/KBHide~iphone@2x.png differ diff --git a/Mini vMac/Assets.xcassets/KBHide.imageset/KBHide~iphone@3x.png b/Mini vMac/Assets.xcassets/KBHide.imageset/KBHide~iphone@3x.png new file mode 100644 index 0000000..0dcafcb Binary files /dev/null and b/Mini vMac/Assets.xcassets/KBHide.imageset/KBHide~iphone@3x.png differ diff --git a/Mini vMac/Assets.xcassets/KBKey.imageset/Contents.json b/Mini vMac/Assets.xcassets/KBKey.imageset/Contents.json new file mode 100644 index 0000000..db12060 --- /dev/null +++ b/Mini vMac/Assets.xcassets/KBKey.imageset/Contents.json @@ -0,0 +1,103 @@ +{ + "images" : [ + { + "resizing" : { + "mode" : "9-part", + "center" : { + "mode" : "tile", + "width" : 1, + "height" : 1 + }, + "cap-insets" : { + "bottom" : 8, + "top" : 8, + "right" : 8, + "left" : 8 + } + }, + "idiom" : "iphone", + "filename" : "KBKey.png", + "scale" : "1x" + }, + { + "resizing" : { + "mode" : "9-part", + "center" : { + "mode" : "tile", + "width" : 2, + "height" : 2 + }, + "cap-insets" : { + "bottom" : 16, + "top" : 16, + "right" : 16, + "left" : 16 + } + }, + "idiom" : "iphone", + "filename" : "KBKey@2x.png", + "scale" : "2x" + }, + { + "resizing" : { + "mode" : "9-part", + "center" : { + "mode" : "tile", + "width" : 3, + "height" : 3 + }, + "cap-insets" : { + "bottom" : 24, + "top" : 24, + "right" : 24, + "left" : 24 + } + }, + "idiom" : "iphone", + "filename" : "KBKey@3x.png", + "scale" : "3x" + }, + { + "resizing" : { + "mode" : "9-part", + "center" : { + "mode" : "tile", + "width" : 1, + "height" : 1 + }, + "cap-insets" : { + "bottom" : 16, + "top" : 16, + "right" : 16, + "left" : 16 + } + }, + "idiom" : "ipad", + "filename" : "KBKey~ipad.png", + "scale" : "1x" + }, + { + "resizing" : { + "mode" : "9-part", + "center" : { + "mode" : "tile", + "width" : 2, + "height" : 2 + }, + "cap-insets" : { + "bottom" : 32, + "top" : 32, + "right" : 32, + "left" : 32 + } + }, + "idiom" : "ipad", + "filename" : "KBKey@2x~ipad.png", + "scale" : "2x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Mini vMac/Assets.xcassets/KBKey.imageset/KBKey.png b/Mini vMac/Assets.xcassets/KBKey.imageset/KBKey.png new file mode 100644 index 0000000..0ec11c4 Binary files /dev/null and b/Mini vMac/Assets.xcassets/KBKey.imageset/KBKey.png differ diff --git a/Mini vMac/Assets.xcassets/KBKey.imageset/KBKey@2x.png b/Mini vMac/Assets.xcassets/KBKey.imageset/KBKey@2x.png new file mode 100644 index 0000000..4f00746 Binary files /dev/null and b/Mini vMac/Assets.xcassets/KBKey.imageset/KBKey@2x.png differ diff --git a/Mini vMac/Assets.xcassets/KBKey.imageset/KBKey@2x~ipad.png b/Mini vMac/Assets.xcassets/KBKey.imageset/KBKey@2x~ipad.png new file mode 100644 index 0000000..9d43562 Binary files /dev/null and b/Mini vMac/Assets.xcassets/KBKey.imageset/KBKey@2x~ipad.png differ diff --git a/Mini vMac/Assets.xcassets/KBKey.imageset/KBKey@3x.png b/Mini vMac/Assets.xcassets/KBKey.imageset/KBKey@3x.png new file mode 100644 index 0000000..e95e4df Binary files /dev/null and b/Mini vMac/Assets.xcassets/KBKey.imageset/KBKey@3x.png differ diff --git a/Mini vMac/Assets.xcassets/KBKey.imageset/KBKey~ipad.png b/Mini vMac/Assets.xcassets/KBKey.imageset/KBKey~ipad.png new file mode 100644 index 0000000..ad36f2b Binary files /dev/null and b/Mini vMac/Assets.xcassets/KBKey.imageset/KBKey~ipad.png differ diff --git a/Mini vMac/Assets.xcassets/KBKeyDark.imageset/Contents.json b/Mini vMac/Assets.xcassets/KBKeyDark.imageset/Contents.json new file mode 100644 index 0000000..dff8b2e --- /dev/null +++ b/Mini vMac/Assets.xcassets/KBKeyDark.imageset/Contents.json @@ -0,0 +1,103 @@ +{ + "images" : [ + { + "resizing" : { + "mode" : "9-part", + "center" : { + "mode" : "tile", + "width" : 1, + "height" : 1 + }, + "cap-insets" : { + "bottom" : 8, + "top" : 8, + "right" : 8, + "left" : 8 + } + }, + "idiom" : "iphone", + "filename" : "KBKeyDark.png", + "scale" : "1x" + }, + { + "resizing" : { + "mode" : "9-part", + "center" : { + "mode" : "tile", + "width" : 2, + "height" : 2 + }, + "cap-insets" : { + "bottom" : 16, + "top" : 16, + "right" : 16, + "left" : 16 + } + }, + "idiom" : "iphone", + "filename" : "KBKeyDark@2x.png", + "scale" : "2x" + }, + { + "resizing" : { + "mode" : "9-part", + "center" : { + "mode" : "tile", + "width" : 3, + "height" : 3 + }, + "cap-insets" : { + "bottom" : 24, + "top" : 24, + "right" : 24, + "left" : 24 + } + }, + "idiom" : "iphone", + "filename" : "KBKeyDark@3x.png", + "scale" : "3x" + }, + { + "resizing" : { + "mode" : "9-part", + "center" : { + "mode" : "tile", + "width" : 1, + "height" : 1 + }, + "cap-insets" : { + "bottom" : 16, + "top" : 16, + "right" : 16, + "left" : 16 + } + }, + "idiom" : "ipad", + "filename" : "KBKeyDark~ipad.png", + "scale" : "1x" + }, + { + "resizing" : { + "mode" : "9-part", + "center" : { + "mode" : "tile", + "width" : 2, + "height" : 2 + }, + "cap-insets" : { + "bottom" : 32, + "top" : 32, + "right" : 32, + "left" : 32 + } + }, + "idiom" : "ipad", + "filename" : "KBKeyDark@2x~ipad.png", + "scale" : "2x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Mini vMac/Assets.xcassets/KBKeyDark.imageset/KBKeyDark.png b/Mini vMac/Assets.xcassets/KBKeyDark.imageset/KBKeyDark.png new file mode 100644 index 0000000..fa2c119 Binary files /dev/null and b/Mini vMac/Assets.xcassets/KBKeyDark.imageset/KBKeyDark.png differ diff --git a/Mini vMac/Assets.xcassets/KBKeyDark.imageset/KBKeyDark@2x.png b/Mini vMac/Assets.xcassets/KBKeyDark.imageset/KBKeyDark@2x.png new file mode 100644 index 0000000..e43fdf6 Binary files /dev/null and b/Mini vMac/Assets.xcassets/KBKeyDark.imageset/KBKeyDark@2x.png differ diff --git a/Mini vMac/Assets.xcassets/KBKeyDark.imageset/KBKeyDark@2x~ipad.png b/Mini vMac/Assets.xcassets/KBKeyDark.imageset/KBKeyDark@2x~ipad.png new file mode 100644 index 0000000..789f5b1 Binary files /dev/null and b/Mini vMac/Assets.xcassets/KBKeyDark.imageset/KBKeyDark@2x~ipad.png differ diff --git a/Mini vMac/Assets.xcassets/KBKeyDark.imageset/KBKeyDark@3x.png b/Mini vMac/Assets.xcassets/KBKeyDark.imageset/KBKeyDark@3x.png new file mode 100644 index 0000000..805487b Binary files /dev/null and b/Mini vMac/Assets.xcassets/KBKeyDark.imageset/KBKeyDark@3x.png differ diff --git a/Mini vMac/Assets.xcassets/KBKeyDark.imageset/KBKeyDark~ipad.png b/Mini vMac/Assets.xcassets/KBKeyDark.imageset/KBKeyDark~ipad.png new file mode 100644 index 0000000..2dc8470 Binary files /dev/null and b/Mini vMac/Assets.xcassets/KBKeyDark.imageset/KBKeyDark~ipad.png differ diff --git a/Mini vMac/Assets.xcassets/KBNumPad.imageset/Contents.json b/Mini vMac/Assets.xcassets/KBNumPad.imageset/Contents.json new file mode 100644 index 0000000..60d8cbd --- /dev/null +++ b/Mini vMac/Assets.xcassets/KBNumPad.imageset/Contents.json @@ -0,0 +1,32 @@ +{ + "images" : [ + { + "idiom" : "iphone", + "scale" : "1x" + }, + { + "idiom" : "iphone", + "filename" : "KBNumPad@2x.png", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "filename" : "KBNumPad@3x.png", + "scale" : "3x" + }, + { + "idiom" : "ipad", + "filename" : "KBNumPad~ipad.png", + "scale" : "1x" + }, + { + "idiom" : "ipad", + "filename" : "KBNumPad@2x~ipad.png", + "scale" : "2x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Mini vMac/Assets.xcassets/KBNumPad.imageset/KBNumPad@2x.png b/Mini vMac/Assets.xcassets/KBNumPad.imageset/KBNumPad@2x.png new file mode 100644 index 0000000..01bd962 Binary files /dev/null and b/Mini vMac/Assets.xcassets/KBNumPad.imageset/KBNumPad@2x.png differ diff --git a/Mini vMac/Assets.xcassets/KBNumPad.imageset/KBNumPad@2x~ipad.png b/Mini vMac/Assets.xcassets/KBNumPad.imageset/KBNumPad@2x~ipad.png new file mode 100644 index 0000000..332186c Binary files /dev/null and b/Mini vMac/Assets.xcassets/KBNumPad.imageset/KBNumPad@2x~ipad.png differ diff --git a/Mini vMac/Assets.xcassets/KBNumPad.imageset/KBNumPad@3x.png b/Mini vMac/Assets.xcassets/KBNumPad.imageset/KBNumPad@3x.png new file mode 100644 index 0000000..98f331f Binary files /dev/null and b/Mini vMac/Assets.xcassets/KBNumPad.imageset/KBNumPad@3x.png differ diff --git a/Mini vMac/Assets.xcassets/KBNumPad.imageset/KBNumPad~ipad.png b/Mini vMac/Assets.xcassets/KBNumPad.imageset/KBNumPad~ipad.png new file mode 100644 index 0000000..0722c85 Binary files /dev/null and b/Mini vMac/Assets.xcassets/KBNumPad.imageset/KBNumPad~ipad.png differ diff --git a/Mini vMac/Assets.xcassets/KBOption.imageset/Contents.json b/Mini vMac/Assets.xcassets/KBOption.imageset/Contents.json new file mode 100644 index 0000000..5b949a1 --- /dev/null +++ b/Mini vMac/Assets.xcassets/KBOption.imageset/Contents.json @@ -0,0 +1,32 @@ +{ + "images" : [ + { + "idiom" : "iphone", + "scale" : "1x" + }, + { + "idiom" : "iphone", + "filename" : "KBKeyOption@2x.png", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "filename" : "KBKeyOption@3x.png", + "scale" : "3x" + }, + { + "idiom" : "ipad", + "filename" : "KBOption~ipad.png", + "scale" : "1x" + }, + { + "idiom" : "ipad", + "filename" : "KBOption@2x~ipad.png", + "scale" : "2x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Mini vMac/Assets.xcassets/KBOption.imageset/KBKeyOption@2x.png b/Mini vMac/Assets.xcassets/KBOption.imageset/KBKeyOption@2x.png new file mode 100644 index 0000000..5bb885f Binary files /dev/null and b/Mini vMac/Assets.xcassets/KBOption.imageset/KBKeyOption@2x.png differ diff --git a/Mini vMac/Assets.xcassets/KBOption.imageset/KBKeyOption@3x.png b/Mini vMac/Assets.xcassets/KBOption.imageset/KBKeyOption@3x.png new file mode 100644 index 0000000..11d56c0 Binary files /dev/null and b/Mini vMac/Assets.xcassets/KBOption.imageset/KBKeyOption@3x.png differ diff --git a/Mini vMac/Assets.xcassets/KBOption.imageset/KBOption@2x~ipad.png b/Mini vMac/Assets.xcassets/KBOption.imageset/KBOption@2x~ipad.png new file mode 100644 index 0000000..3bc0e82 Binary files /dev/null and b/Mini vMac/Assets.xcassets/KBOption.imageset/KBOption@2x~ipad.png differ diff --git a/Mini vMac/Assets.xcassets/KBOption.imageset/KBOption~ipad.png b/Mini vMac/Assets.xcassets/KBOption.imageset/KBOption~ipad.png new file mode 100644 index 0000000..2b66046 Binary files /dev/null and b/Mini vMac/Assets.xcassets/KBOption.imageset/KBOption~ipad.png differ diff --git a/Mini vMac/Assets.xcassets/KBShiftDown.imageset/Contents.json b/Mini vMac/Assets.xcassets/KBShiftDown.imageset/Contents.json new file mode 100644 index 0000000..81045bd --- /dev/null +++ b/Mini vMac/Assets.xcassets/KBShiftDown.imageset/Contents.json @@ -0,0 +1,32 @@ +{ + "images" : [ + { + "idiom" : "iphone", + "scale" : "1x" + }, + { + "idiom" : "iphone", + "filename" : "KBShiftDown~iphone@2x.png", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "filename" : "KBShiftDown~iphone@3x.png", + "scale" : "3x" + }, + { + "idiom" : "ipad", + "filename" : "KBShiftDown~ipad.png", + "scale" : "1x" + }, + { + "idiom" : "ipad", + "filename" : "KBShiftDown~ipad@2x.png", + "scale" : "2x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Mini vMac/Assets.xcassets/KBShiftDown.imageset/KBShiftDown~ipad.png b/Mini vMac/Assets.xcassets/KBShiftDown.imageset/KBShiftDown~ipad.png new file mode 100644 index 0000000..c2eede9 Binary files /dev/null and b/Mini vMac/Assets.xcassets/KBShiftDown.imageset/KBShiftDown~ipad.png differ diff --git a/Mini vMac/Assets.xcassets/KBShiftDown.imageset/KBShiftDown~ipad@2x.png b/Mini vMac/Assets.xcassets/KBShiftDown.imageset/KBShiftDown~ipad@2x.png new file mode 100644 index 0000000..7f5a483 Binary files /dev/null and b/Mini vMac/Assets.xcassets/KBShiftDown.imageset/KBShiftDown~ipad@2x.png differ diff --git a/Mini vMac/Assets.xcassets/KBShiftDown.imageset/KBShiftDown~iphone@2x.png b/Mini vMac/Assets.xcassets/KBShiftDown.imageset/KBShiftDown~iphone@2x.png new file mode 100644 index 0000000..1807106 Binary files /dev/null and b/Mini vMac/Assets.xcassets/KBShiftDown.imageset/KBShiftDown~iphone@2x.png differ diff --git a/Mini vMac/Assets.xcassets/KBShiftDown.imageset/KBShiftDown~iphone@3x.png b/Mini vMac/Assets.xcassets/KBShiftDown.imageset/KBShiftDown~iphone@3x.png new file mode 100644 index 0000000..a23e507 Binary files /dev/null and b/Mini vMac/Assets.xcassets/KBShiftDown.imageset/KBShiftDown~iphone@3x.png differ diff --git a/Mini vMac/Assets.xcassets/KBShiftUp.imageset/Contents.json b/Mini vMac/Assets.xcassets/KBShiftUp.imageset/Contents.json new file mode 100644 index 0000000..ba0f658 --- /dev/null +++ b/Mini vMac/Assets.xcassets/KBShiftUp.imageset/Contents.json @@ -0,0 +1,32 @@ +{ + "images" : [ + { + "idiom" : "iphone", + "scale" : "1x" + }, + { + "idiom" : "iphone", + "filename" : "KBShiftUp~iphone@2x.png", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "filename" : "KBShiftUp~iphone@3x.png", + "scale" : "3x" + }, + { + "idiom" : "ipad", + "filename" : "KBShiftUp~ipad.png", + "scale" : "1x" + }, + { + "idiom" : "ipad", + "filename" : "KBShiftUp~ipad@2x.png", + "scale" : "2x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Mini vMac/Assets.xcassets/KBShiftUp.imageset/KBShiftUp~ipad.png b/Mini vMac/Assets.xcassets/KBShiftUp.imageset/KBShiftUp~ipad.png new file mode 100644 index 0000000..54d3467 Binary files /dev/null and b/Mini vMac/Assets.xcassets/KBShiftUp.imageset/KBShiftUp~ipad.png differ diff --git a/Mini vMac/Assets.xcassets/KBShiftUp.imageset/KBShiftUp~ipad@2x.png b/Mini vMac/Assets.xcassets/KBShiftUp.imageset/KBShiftUp~ipad@2x.png new file mode 100644 index 0000000..8ee7923 Binary files /dev/null and b/Mini vMac/Assets.xcassets/KBShiftUp.imageset/KBShiftUp~ipad@2x.png differ diff --git a/Mini vMac/Assets.xcassets/KBShiftUp.imageset/KBShiftUp~iphone@2x.png b/Mini vMac/Assets.xcassets/KBShiftUp.imageset/KBShiftUp~iphone@2x.png new file mode 100644 index 0000000..99e7927 Binary files /dev/null and b/Mini vMac/Assets.xcassets/KBShiftUp.imageset/KBShiftUp~iphone@2x.png differ diff --git a/Mini vMac/Assets.xcassets/KBShiftUp.imageset/KBShiftUp~iphone@3x.png b/Mini vMac/Assets.xcassets/KBShiftUp.imageset/KBShiftUp~iphone@3x.png new file mode 100644 index 0000000..b752735 Binary files /dev/null and b/Mini vMac/Assets.xcassets/KBShiftUp.imageset/KBShiftUp~iphone@3x.png differ diff --git a/Mini vMac/KBKey.h b/Mini vMac/KBKey.h new file mode 100644 index 0000000..4304968 --- /dev/null +++ b/Mini vMac/KBKey.h @@ -0,0 +1,33 @@ +// +// KBKey.h +// BasiliskII +// +// Created by Jesús A. Álvarez on 16/03/2014. +// Copyright (c) 2014 namedfork. All rights reserved. +// + +#import + +extern const NSUInteger KBKeyEventStickyKey; + +@interface KBKey : UIButton + +@property (nonatomic, copy, nullable) NSString *label; +@property (nonatomic, assign) int16_t scancode; +@property (nonatomic, assign) BOOL dark; + +@end + +@interface KBStickyKey : KBKey +@property (nonatomic, assign) BOOL down; +@end + +@interface KBHideKey : KBKey + +@end + +@interface KBShiftCapsKey : KBStickyKey + +@property (nonatomic, assign) BOOL capsLocked; + +@end diff --git a/Mini vMac/KBKey.m b/Mini vMac/KBKey.m new file mode 100644 index 0000000..0f16366 --- /dev/null +++ b/Mini vMac/KBKey.m @@ -0,0 +1,196 @@ +// +// KBKey.m +// BasiliskII +// +// Created by Jesús A. Álvarez on 16/03/2014. +// Copyright (c) 2014 namedfork. All rights reserved. +// + +#import "KBKey.h" + +const NSUInteger KBKeyControlStateCaps = 1 << 16; +const NSUInteger KBKeyEventStickyKey = 1 << 24; + +@implementation KBKey + +- (id)initWithFrame:(CGRect)frame { + if ((self = [super initWithFrame:frame])) { + self.dark = NO; + self.titleLabel.adjustsFontSizeToFitWidth = YES; + self.titleLabel.lineBreakMode = NSLineBreakByTruncatingTail; + self.titleLabel.minimumScaleFactor = 0.5; + self.titleEdgeInsets = UIEdgeInsetsMake(0, 2, 0, 2); + [self setTitleColor:[UIColor blackColor] forState:UIControlStateNormal]; + } + return self; +} + +- (void)awakeFromNib { + self.dark = NO; +} + +- (void)setDark:(BOOL)dark { + _dark = dark; + [self setBackgroundImage:[UIImage imageNamed:@"KBKey"] forState:dark ? UIControlStateHighlighted : UIControlStateNormal]; + [self setBackgroundImage:[UIImage imageNamed:@"KBKeyDark"] forState:dark ? UIControlStateNormal : UIControlStateHighlighted]; +} + +- (void)setLabel:(NSString *)label { + self.titleLabel.numberOfLines = [label containsString:@"\n"] ? 2 : 1; + [self setTitle:label forState:UIControlStateNormal]; +} + +- (NSString *)label { + return [self titleForState:UIControlStateNormal]; +} + +- (void)setTitle:(NSString *)title forState:(UIControlState)state { + if (title.length > 1 && [title hasPrefix:@"@"] && ![title containsString:@"\n"]) { + [super setTitle:nil forState:state]; + NSArray *components = [[title substringFromIndex:1] componentsSeparatedByString:@"/"]; + if (state == UIControlStateNormal) { + if (components.count == 3) { + [super setImage:[UIImage imageNamed:[components[0] stringByAppendingString:components[1]]] forState:UIControlStateNormal]; + [super setImage:[UIImage imageNamed:[components[0] stringByAppendingString:components[2]]] forState:UIControlStateHighlighted]; + } else if (components.count == 1) { + UIImage *image = [UIImage imageNamed:components.firstObject]; + [super setImage:image forState:UIControlStateNormal]; + [super setImage:image forState:UIControlStateHighlighted]; + } else { + NSLog(@"Can't set title for %@: %@", self, title); + } + } else { + [super setImage:[UIImage imageNamed:components.firstObject] forState:state]; + } + self.imageEdgeInsets = UIEdgeInsetsMake(-2, 0, 0, 0); + } else if ((id)title != [NSNull null]) { + [super setTitle:title forState:state]; + [super setImage:nil forState:state]; + } +} + +- (instancetype)_sameKey { + __block KBKey *otherKey = nil; + [self.superview.subviews enumerateObjectsUsingBlock:^(KBKey *obj, NSUInteger idx, BOOL *stop) { + if (obj != self && [obj isKindOfClass:[self class]] && obj.scancode == self.scancode) { + otherKey = obj; + *stop = YES; + } + }]; + return otherKey; +} + +@end + +@implementation KBHideKey + +@end + +@implementation KBStickyKey { + @protected + BOOL _down; +} + +- (id)initWithFrame:(CGRect)frame { + if ((self = [super initWithFrame:frame])) { + UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(tap:)]; + [self addGestureRecognizer:tap]; + } + return self; +} + +- (UIControlState)state { + return [super state] | (_down ? UIControlStateHighlighted : 0); +} + +- (void)setDown:(BOOL)down { + if (_down != down) { + _down = down; + [self sendActionsForControlEvents:KBKeyEventStickyKey]; + [self setNeedsLayout]; + + KBStickyKey *otherKey = [self _sameKey]; + if (otherKey != nil) { + otherKey->_down = down; + [otherKey setNeedsLayout]; + } + } +} + +- (void)tap:(UIGestureRecognizer *)gestureRecognizer { + if (gestureRecognizer.state == UIGestureRecognizerStateRecognized) { + self.down ^= YES; + } +} + +@end + +@implementation KBShiftCapsKey { + BOOL wasCapsLocked; +} + +- (id)initWithFrame:(CGRect)frame { + if ((self = [super initWithFrame:frame])) { + self.dark = YES; + [self setImage:[UIImage imageNamed:@"KBShiftUp"] forState:UIControlStateNormal]; + [self setImage:[UIImage imageNamed:@"KBShiftDown"] forState:UIControlStateHighlighted]; + [self setImage:[UIImage imageNamed:@"KBCapsLock"] forState:KBKeyControlStateCaps]; + [self setImage:[UIImage imageNamed:@"KBCapsLock"] forState:KBKeyControlStateCaps | UIControlStateHighlighted]; + [self setBackgroundImage:[UIImage imageNamed:@"KBKey"] forState:KBKeyControlStateCaps]; + [self setBackgroundImage:[UIImage imageNamed:@"KBKey"] forState:KBKeyControlStateCaps | UIControlStateHighlighted]; + + UITapGestureRecognizer *doubleTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(doubleTap:)]; + doubleTap.numberOfTapsRequired = 2; + [self addGestureRecognizer:doubleTap]; + } + return self; +} + +- (void)setTitle:(NSString *)title forState:(UIControlState)state { + // nothing here +} + +- (void)setDark:(BOOL)dark { + [super setDark:YES]; +} + +- (UIControlState)state { + return [super state] | (_capsLocked ? KBKeyControlStateCaps : 0); +} + +- (void)tap:(UIGestureRecognizer *)gestureRecognizer { + if (gestureRecognizer.state == UIGestureRecognizerStateRecognized) { + wasCapsLocked = self.capsLocked; + typeof(self) sameKey = [self _sameKey]; + if (sameKey != nil) { + sameKey->wasCapsLocked = wasCapsLocked; + sameKey.capsLocked = NO; + } + self.capsLocked = NO; + if (wasCapsLocked) { + _down = YES; + self.down = NO; + } else { + self.down = !self.down; + } + [[self _sameKey] setNeedsLayout]; + } +} + +- (void)doubleTap:(UIGestureRecognizer *)gestureRecognizer { + if (gestureRecognizer.state == UIGestureRecognizerStateRecognized) { + self.down = NO; + self.capsLocked = !wasCapsLocked; + typeof(self) sameKey = [self _sameKey]; + if (sameKey != nil) { + sameKey->wasCapsLocked = wasCapsLocked; + sameKey.capsLocked = self.capsLocked; + } + [self sendActionsForControlEvents:KBKeyEventStickyKey]; + [self setNeedsLayout]; + wasCapsLocked = YES; + [sameKey setNeedsLayout]; + } +} + +@end \ No newline at end of file diff --git a/Mini vMac/KBKeyboardLayout.h b/Mini vMac/KBKeyboardLayout.h new file mode 100644 index 0000000..6ad40c3 --- /dev/null +++ b/Mini vMac/KBKeyboardLayout.h @@ -0,0 +1,26 @@ +// +// KBKeyboardLayout.h +// BasiliskII +// +// Created by Jesús A. Álvarez on 09/04/2016. +// Copyright © 2016 namedfork. All rights reserved. +// + +#import + +#define VKC_SHIFT_CAPS -127 +#define VKC_HIDE -128 + +@interface KBKeyboardLayout : NSObject + +@property (nonatomic, readonly) NSString *identifier; +@property (nonatomic, readonly) NSString *name; +@property (nonatomic, readonly) uint8_t type; +@property (nonatomic, readonly) NSUInteger numberOfKeyPlanes; +@property (nonatomic, readonly) NSArray *availableSizes; + +- (instancetype)initWithContentsOfFile:(NSString*)path; +- (NSString*)labelForScanCode:(NSInteger)scanCode; +- (BOOL)enumerateKeysForSize:(CGSize)size plane:(NSUInteger)plane transform:(CGAffineTransform)transform usingBlock:(void(^)(int8_t scancode, CGRect frame, CGFloat fontScale, BOOL dark, BOOL sticky))block; + +@end diff --git a/Mini vMac/KBKeyboardLayout.m b/Mini vMac/KBKeyboardLayout.m new file mode 100644 index 0000000..34b00f5 --- /dev/null +++ b/Mini vMac/KBKeyboardLayout.m @@ -0,0 +1,433 @@ +// +// KBKeyboardLayout.m +// BasiliskII +// +// Created by Jesús A. Álvarez on 09/04/2016. +// Copyright © 2016 namedfork. All rights reserved. +// + +#import "KBKeyboardLayout.h" + +#if defined(CGFLOAT_IS_DOUBLE) && CGFLOAT_IS_DOUBLE +#define CGFloatValue doubleValue +#else +#define CGFloatValue floatValue +#endif + +@interface KBKeyDescriptor : NSObject +{ + @public + CGRect frame; + CGFloat fontScale; + int8_t scancode; + BOOL dark, sticky; +} +@end + +@interface KBKeyboardLayoutBinaryReader : NSObject +{ + NSData *data; + const void *ptr; +} + +@property (nonatomic, assign) NSUInteger position; + ++ (BOOL)validBinaryHeader:(NSData*)data; +- (instancetype)initWithData:(NSData*)layoutData; +- (NSString*)readString; +- (uint8_t)readUInt8; +- (int8_t)readInt8; +- (uint16_t)readUInt16; +- (int16_t)readInt16; +- (uint32_t)readUInt32; +- (CGFloat)readFloat; +- (CGRect)readFrameOfSize:(NSUInteger)size withLastFrame:(CGRect)lastFrame; +- (NSArray*)readStrings:(NSUInteger)count emptyStringMarker:(id)emptyStringMarker; + +@end + +typedef NSArray KBKeyPlane; +typedef NSMutableArray KBMutableKeyPlane; +typedef NSArray KBKeyMap; +typedef NSMutableArray KBMutableKeyMap; + +@implementation KBKeyboardLayout +{ + NSMutableDictionary *labels; + NSArray *keyPlaneLabels; + NSMutableDictionary *keyMaps; +} + +- (instancetype)initWithContentsOfFile:(NSString *)path { + NSData *layoutData = [NSData dataWithContentsOfFile:path]; + if ([KBKeyboardLayoutBinaryReader validBinaryHeader:layoutData]) { + return [self initWithBinaryRepresentation:layoutData]; + } else if (layoutData.length > 1 && memcmp(layoutData.bytes, "{", 1) == 0) { + // possibly JSON + NSError *err = nil; + NSDictionary *layoutDictionary = [NSJSONSerialization JSONObjectWithData:layoutData options:0 error:&err]; + return [self initWithDictionaryRepresentation:layoutDictionary]; + } + return nil; +} + +- (NSUInteger)numberOfKeyPlanes { + return keyPlaneLabels.count; +} + +- (NSArray *)availableSizes { + return keyMaps.allKeys; +} + +- (NSString *)labelForScanCode:(NSInteger)scanCode { + if (scanCode == VKC_HIDE) { + return @"@KBHide"; + } else if (scanCode < 0 && -scanCode <= keyPlaneLabels.count) { + // switch keyplane + return keyPlaneLabels[-scanCode-1]; + } + return labels[@(scanCode)]; +} + +- (BOOL)enumerateKeysForSize:(CGSize)size plane:(NSUInteger)plane transform:(CGAffineTransform)transform usingBlock:(void (^)(int8_t, CGRect, CGFloat, BOOL, BOOL))block { + NSValue *sizeValue = [NSValue valueWithCGSize:size]; + KBKeyPlane *keyPlane = keyMaps[sizeValue][plane]; + for (KBKeyDescriptor *keyDescriptor in keyPlane) { + block(keyDescriptor->scancode, CGRectApplyAffineTransform(keyDescriptor->frame, transform), keyDescriptor->fontScale, keyDescriptor->dark, keyDescriptor->sticky); + } + return keyPlane != nil; +} + +#pragma mark - Binary Reading + +- (instancetype)initWithBinaryRepresentation:(NSData *)layoutData { + if (![KBKeyboardLayoutBinaryReader validBinaryHeader:layoutData]) { + return nil; + } + if ((self = [super init])) { + KBKeyboardLayoutBinaryReader *reader = [[KBKeyboardLayoutBinaryReader alloc] initWithData:layoutData]; + + // read header + _identifier = [reader readString]; + _name = [reader readString]; + _type = [reader readUInt8]; + + // read 128 labels + labels = [NSMutableDictionary dictionaryWithCapacity:128]; + for (int scancode=0; scancode < 128; scancode++) { + NSString *label = [reader readString]; + if (label != nil) { + labels[@(scancode)] = label; + } + } + + // read keyplane names + NSUInteger numberOfKeyPlanes = [reader readUInt8]; + keyPlaneLabels = [reader readStrings:numberOfKeyPlanes emptyStringMarker:@""]; + + // read map index + NSUInteger numberOfMaps = [reader readUInt8]; + NSMutableDictionary *mapIndex = [NSMutableDictionary dictionaryWithCapacity:numberOfMaps]; + NSMutableArray *mapIDs = [NSMutableArray arrayWithCapacity:numberOfMaps]; + for (NSUInteger i=0; i < numberOfMaps; i++) { + uint32_t mapID = [reader readUInt32]; + uint16_t mapOffset = [reader readUInt16]; + mapIndex[@(mapID)] = @(mapOffset); + [mapIDs addObject:@(mapID)]; + } + + // read maps + keyMaps = [NSMutableDictionary dictionaryWithCapacity:numberOfMaps]; + NSMutableDictionary *mapsByID = [NSMutableDictionary dictionaryWithCapacity:numberOfMaps]; + for (NSNumber *mapID in mapIDs) { + CGSize mapSize = CGSizeMake((mapID.integerValue >> 16), (mapID.integerValue & 0x7FFF)); + reader.position = mapIndex[mapID].integerValue; + // read keyplanes + KBMutableKeyMap *keyMap = [KBMutableKeyMap arrayWithCapacity:numberOfKeyPlanes]; + for (NSUInteger planeNumber = 0; planeNumber < numberOfKeyPlanes; planeNumber++) { + NSUInteger numberOfKeys = [reader readUInt8]; + if (numberOfKeys == 0) { + [keyMap addObject:@[]]; + continue; + } + // read keys + KBMutableKeyPlane *keyPlane = [KBMutableKeyPlane arrayWithCapacity:numberOfKeys]; + CGRect lastFrame = CGRectZero; + for (NSUInteger keyNumber = 0; keyNumber < numberOfKeys; keyNumber++) { + uint8_t flags = [reader readUInt8]; + if ((flags & 0xC0) == 0x00) { + // key + KBKeyDescriptor *key = [KBKeyDescriptor new]; + key->dark = (flags & 0x20) == 0x20; + key->sticky = (flags & 0x10) == 0x10; + key->fontScale = (((flags & 0x0C) >> 2) + 1) * 0.25; + key->scancode = [reader readInt8]; + key->frame = [reader readFrameOfSize:(flags & 0x03) + 1 withLastFrame:lastFrame]; + lastFrame = key->frame; + + [keyPlane addObject:key]; + } else if ((flags & 0xC0) == 0x40) { + // include + NSUInteger includePlaneNumber = flags & 0x0F; + uint32_t includeMapNumber = [reader readUInt32]; + CGAffineTransform includeTransform = CGAffineTransformIdentity; + if ((flags & 0x20) == 0x20) { + CGFloat scaleX = [reader readFloat]; + CGFloat scaleY = [reader readFloat]; + includeTransform = CGAffineTransformScale(includeTransform, scaleX, scaleY); + } + if ((flags & 0x10) == 0x10) { + CGFloat translateX = [reader readInt16]; + CGFloat translateY = [reader readInt16]; + includeTransform = CGAffineTransformTranslate(includeTransform, translateX, translateY); + } + NSUInteger numberOfSkips = [reader readUInt8]; + NSMutableSet *skipKeys = [NSMutableSet setWithCapacity:numberOfSkips]; + for (NSUInteger i=0; i < numberOfSkips; i++) { + [skipKeys addObject:@([reader readInt8])]; + } + + KBKeyMap *includeKeyMap = mapsByID[@(includeMapNumber)]; + if (includeKeyMap.count < includePlaneNumber) { + continue; + } + KBKeyPlane *includeKeyPlane = includeKeyMap[includePlaneNumber]; + [includeKeyPlane enumerateObjectsUsingBlock:^(KBKeyDescriptor * _Nonnull oldKey, NSUInteger idx, BOOL * _Nonnull stop) { + if ([skipKeys containsObject:@(oldKey->scancode)]) { + return; + } + KBKeyDescriptor *key = [KBKeyDescriptor new]; + key->dark = oldKey->dark; + key->sticky = oldKey->sticky; + key->frame = CGRectIntegral(CGRectApplyAffineTransform(oldKey->frame, includeTransform)); + key->fontScale = oldKey->fontScale; + key->scancode = oldKey->scancode; + [keyPlane addObject:key]; + }]; + } + } + [keyMap addObject:keyPlane]; + } + mapsByID[mapID] = keyMap; + if ((mapID.integerValue & 0x7FFF0000) != 0) { + // valid size + keyMaps[[NSValue valueWithCGSize:mapSize]] = keyMap; + } + } + } + return self; +} + +#pragma mark - Dictionary Reading + +- (instancetype)initWithDictionaryRepresentation:(NSDictionary *)layoutDictionary { + if ((self = [super init])) { + _identifier = layoutDictionary[@"id"]; + _name = layoutDictionary[@"name"]; + _type = (uint8_t)[layoutDictionary[@"adbType"] integerValue]; + + // read labels + NSDictionary *layoutLabels = layoutDictionary[@"labels"]; + labels = [NSMutableDictionary dictionaryWithCapacity:100]; + [layoutLabels enumerateKeysAndObjectsUsingBlock:^(NSString * _Nonnull key, NSString * _Nonnull obj, BOOL * _Nonnull stop) { + if (key.integerValue != 0 || [key isEqualToString:@"0"]) { + labels[@(key.integerValue)] = obj; + } + }]; + + // get keyplane labels + NSArray *keyPlaneIDs = [[labels.allKeys filteredArrayUsingPredicate:[NSPredicate predicateWithBlock:^BOOL(id _Nonnull evaluatedObject, NSDictionary * _Nullable bindings) { + return [evaluatedObject integerValue] < 0; + }]] sortedArrayUsingDescriptors:@[[NSSortDescriptor sortDescriptorWithKey:@"self" ascending:NO]]]; + keyPlaneLabels = [labels objectsForKeys:keyPlaneIDs notFoundMarker:@""]; + [labels removeObjectsForKeys:keyPlaneIDs]; + + // read sizes + NSMutableArray *sizes = [layoutDictionary.allKeys filteredArrayUsingPredicate:[NSPredicate predicateWithBlock:^BOOL(id _Nonnull evaluatedObject, NSDictionary * _Nullable bindings) { + CGSize size = CGSizeFromString(evaluatedObject); + return !CGSizeEqualToSize(size, CGSizeZero); + }]].mutableCopy; + NSMutableDictionary *sizeToKey = [NSMutableDictionary dictionaryWithCapacity:sizes.count]; + for(NSUInteger i=0; i < sizes.count; i++) { + CGSize size = CGSizeFromString(sizes[i]); + NSValue *sizeValue = [NSValue valueWithCGSize:size]; + sizeToKey[sizeValue] = sizes[i]; + sizes[i] = sizeValue; + } + + // read layouts + keyMaps = [NSMutableDictionary dictionaryWithCapacity:sizes.count]; + for (NSValue *sizeValue in sizes) { + KBMutableKeyMap *keyMap = [NSMutableArray arrayWithCapacity:self.numberOfKeyPlanes]; + for (NSArray *keyPlane in layoutDictionary[sizeToKey[sizeValue]]) { + [keyMap addObject:[self _loadKeys:keyPlane fromDictionary:layoutDictionary withTransform:CGAffineTransformIdentity skip:nil]]; + } + keyMaps[sizeValue] = keyMap; + } + } + return self; +} + +- (KBKeyPlane*)_loadKeys:(NSArray *)keys fromDictionary:(NSDictionary*)layoutDictionary withTransform:(CGAffineTransform)keyTransform skip:(NSSet*)skipKeys { + NSMutableArray *keyPlane = [NSMutableArray arrayWithCapacity:keys.count]; + CGRect frame = CGRectZero; + for (NSDictionary *keyDict in keys) { + // include + NSArray *includeArgs = keyDict[@"include"]; + if ([includeArgs isKindOfClass:[NSArray class]] && includeArgs.count >= 2) { + CGAffineTransform includeTransform = keyTransform; + NSArray *scaleArgs = keyDict[@"scale"]; + if ([scaleArgs isKindOfClass:[NSArray class]] && scaleArgs.count == 2) { + includeTransform = CGAffineTransformScale(includeTransform, scaleArgs[0].CGFloatValue, scaleArgs[1].CGFloatValue); + } + NSArray *translateArgs = keyDict[@"translate"]; + if ([translateArgs isKindOfClass:[NSArray class]] && translateArgs.count == 2) { + includeTransform = CGAffineTransformTranslate(includeTransform, translateArgs[0].CGFloatValue, translateArgs[1].CGFloatValue); + } + NSArray *skipArgs = keyDict[@"skip"]; + + NSString *layoutKey = includeArgs[0]; + NSNumber *planeNumber = includeArgs[1]; + NSArray *addKeys = [self _loadKeys:layoutDictionary[layoutKey][planeNumber.integerValue] fromDictionary:layoutDictionary withTransform:includeTransform skip:skipArgs ? [NSSet setWithArray:skipArgs] : nil]; + [keyPlane addObjectsFromArray:addKeys]; + } + + // frame + NSArray *kvFrame = keyDict[@"frame"]; + frame.origin.x = [kvFrame[0] CGFloatValue]; + if (kvFrame.count > 1 && kvFrame[1] != [NSNull null]) { + frame.origin.y = [kvFrame[1] CGFloatValue]; + } + if (kvFrame.count > 2 && kvFrame[2] != [NSNull null]) { + frame.size.width = [kvFrame[2] CGFloatValue]; + } + if (kvFrame.count > 3 && kvFrame[3] != [NSNull null]) { + frame.size.height = [kvFrame[3] CGFloatValue]; + } + + // key + id scancode = keyDict[@"key"]; + if ([skipKeys containsObject:scancode]) { + continue; + } + KBKeyDescriptor *kd = [KBKeyDescriptor new]; + if ([scancode isEqual:@"hide"]) { + kd->scancode = VKC_HIDE; + } else if ([scancode isEqual:@"shift/caps"]) { + kd->scancode = VKC_SHIFT_CAPS; + } else { + kd->scancode = (int8_t)[scancode integerValue]; + } + kd->sticky = [keyDict[@"sticky"] boolValue]; + kd->dark = [keyDict[@"dark"] boolValue]; + kd->frame = CGRectIntegral(CGRectApplyAffineTransform(frame, keyTransform)); + kd->fontScale = keyDict[@"fontScale"] ? [keyDict[@"fontScale"] CGFloatValue] : 1.0; + + [keyPlane addObject:kd]; + } + + return keyPlane; +} + +@end + +@implementation KBKeyDescriptor + +@end + +@implementation KBKeyboardLayoutBinaryReader + +- (instancetype)initWithData:(NSData *)layoutData { + if ((self = [super init])) { + data = layoutData; + ptr = data.bytes + 12; + } + return self; +} + ++ (BOOL)validBinaryHeader:(NSData*)data { + return data.length > 12 && memcmp(data.bytes, "NFKeyboard\x01\x00", 12) == 0; +} + +- (void)_checkReadableBytes:(NSUInteger)size { + if (ptr + size > data.bytes + data.length) { + @throw [NSException exceptionWithName:NSRangeException reason:nil userInfo:@{@"pos": @(ptr - data.bytes), @"read": @(size), @"length": @(data.length)}]; + } +} + +- (NSUInteger)position { + return ptr - data.bytes; +} + +- (void)setPosition:(NSUInteger)position { + ptr = data.bytes + position; +} + +- (NSString*)readString { + uint8_t stringLength = [self readUInt8]; + if (stringLength == 0) { + return nil; + } + [self _checkReadableBytes:stringLength]; + NSString *string = [[NSString alloc] initWithBytes:ptr length:stringLength encoding:NSUTF8StringEncoding]; + ptr += stringLength; + return string; +} + +- (uint8_t)readUInt8 { + [self _checkReadableBytes:1]; + return *(uint8_t*)ptr++; +} + +- (int8_t)readInt8 { + [self _checkReadableBytes:1]; + return *(int8_t*)ptr++; +} + +- (uint16_t)readUInt16 { + [self _checkReadableBytes:2]; + uint16_t value = OSReadLittleInt16(ptr, 0); + ptr += 2; + return value; +} + +- (int16_t)readInt16 { + [self _checkReadableBytes:2]; + int16_t value = OSReadLittleInt16(ptr, 0); + ptr += 2; + return value; +} + +- (uint32_t)readUInt32 { + [self _checkReadableBytes:4]; + uint32_t value = OSReadLittleInt32(ptr, 0); + ptr += 4; + return value; +} + +- (CGFloat)readFloat { + uint32_t value = [self readUInt32]; + return *(float*)&value; +} + +- (CGRect)readFrameOfSize:(NSUInteger)size withLastFrame:(CGRect)lastFrame { + CGRect frame = lastFrame; + CGFloat *output[4] = {&frame.origin.x, &frame.origin.y, &frame.size.width, &frame.size.height}; + for (int i = 0; i < size; i++) { + uint16_t value = [self readUInt16]; + if (value != 0x7FFF) { + *output[i] = (CGFloat)value; + } + } + return frame; +} + +- (NSArray*)readStrings:(NSUInteger)count emptyStringMarker:(id)emptyStringMarker { + NSMutableArray *strings = [NSMutableArray arrayWithCapacity:count]; + while (count--) { + [strings addObject:[self readString] ?: emptyStringMarker]; + } + return strings; +} + +@end \ No newline at end of file diff --git a/Mini vMac/KBKeyboardView.h b/Mini vMac/KBKeyboardView.h new file mode 100644 index 0000000..3eb0006 --- /dev/null +++ b/Mini vMac/KBKeyboardView.h @@ -0,0 +1,29 @@ +// +// KBKeyboardView.h +// BasiliskII +// +// Created by Jesús A. Álvarez on 22/03/2014. +// Copyright (c) 2014 namedfork. All rights reserved. +// + +#import +#import "KBKeyboardLayout.h" + +@class KBKey; + +@protocol KBKeyboardViewDelegate +- (void)keyDown:(int)scancode; +- (void)keyUp:(int)scancode; +@optional +- (void)hideKeyboard:(nullable id)sender; +@end + +@interface KBKeyboardView : UIView + +@property (weak, nonatomic, nullable) id delegate; +@property (nonatomic, strong, nullable) KBKeyboardLayout *layout; + +@property (nonatomic, readonly, nonnull) NSArray* keys; +@property (nonatomic, readonly, nonnull) NSArray* stickyKeys; + +@end diff --git a/Mini vMac/KBKeyboardView.m b/Mini vMac/KBKeyboardView.m new file mode 100644 index 0000000..cabbf31 --- /dev/null +++ b/Mini vMac/KBKeyboardView.m @@ -0,0 +1,217 @@ +// +// KBKeyboardView.m +// BasiliskII +// +// Created by Jesús A. Álvarez on 22/03/2014. +// Copyright (c) 2014 namedfork. All rights reserved. +// + +#import "KBKeyboardView.h" +#import "KBKey.h" + +#define KC_COMMAND 55 +#define KC_SHIFT 56 +#define KC_CAPSLOCK 57 +#define KC_OPTION 58 +#define KC_CONTROL 59 + +@implementation KBKeyboardView { + NSMutableArray *keyPlanes; + NSMutableSet *modifiers; + NSMutableIndexSet *keysDown; + CGAffineTransform defaultKeyTransform; + CGFloat fontSize; + CGSize selectedSize; +} + +- (id)initWithFrame:(CGRect)frame { + self = [super initWithFrame:frame]; + if (self) { + self.backgroundColor = [UIColor colorWithRed:0xEB / 255.0 green:0xF0 / 255.0 blue:0xF7 / 255.0 alpha:0.9]; + modifiers = [NSMutableSet setWithCapacity:4]; + keysDown = [NSMutableIndexSet indexSet]; + } + return self; +} + +- (void)setLayout:(KBKeyboardLayout *)layout { + if ([_layout isEqual:layout]) { + return; + } + _layout = layout; + + // find preferred size (same width or smaller) + CGFloat frameWidth = self.frame.size.width; + CGFloat preferredWidth = frameWidth; + selectedSize = CGSizeZero; + for (NSValue *key in layout.availableSizes) { + CGSize size = key.CGSizeValue; + if (!CGSizeEqualToSize(size, CGSizeZero) && size.width > selectedSize.width && size.width <= preferredWidth) { + selectedSize = size; + } + } + + // try sideways + if (CGSizeEqualToSize(selectedSize, CGSizeZero)) { + preferredWidth = self.frame.size.height; + for (NSValue *key in layout.availableSizes) { + CGSize size = key.CGSizeValue; + if (!CGSizeEqualToSize(size, CGSizeZero) && size.width > selectedSize.width && size.width <= preferredWidth) { + selectedSize = size; + } + } + } + + // still not found + if (CGSizeEqualToSize(selectedSize, CGSizeZero)) { + return; + } + + defaultKeyTransform = CGAffineTransformIdentity; + fontSize = [UIDevice currentDevice].userInterfaceIdiom == UIUserInterfaceIdiomPhone ? 22.0 : 30.0; + if (preferredWidth != selectedSize.width || preferredWidth != frameWidth) { + // adjust width + if (frameWidth / selectedSize.width > 2 || frameWidth / selectedSize.width < 0.5) { + // iphone keyboard on ipad? + defaultKeyTransform = CGAffineTransformMakeScale(frameWidth / selectedSize.width, frameWidth / selectedSize.width); + } else if (frameWidth < selectedSize.width) { + // shrink keyboard + defaultKeyTransform = CGAffineTransformMakeScale(frameWidth / selectedSize.width, 1.33333); + } else { + // iPhone keyboard on bigger phone + CGFloat wScale = self.frame.size.width / selectedSize.width; + defaultKeyTransform = CGAffineTransformMakeScale(wScale, 1.0); + } + } + self.frame = CGRectMake(0, 0, self.frame.size.width, selectedSize.height * defaultKeyTransform.d); + + // init keyplanes array + NSUInteger numberOfKeyPlanes = layout.numberOfKeyPlanes; + keyPlanes = [NSMutableArray arrayWithCapacity:numberOfKeyPlanes]; + for (int i = 0; i < numberOfKeyPlanes; i++) { + [keyPlanes addObject:[NSNull null]]; + } + + [self switchToKeyPlane:0]; +} + +- (NSArray *)_loadKeyPlane:(NSUInteger)plane { + NSMutableArray *keyPlane = [NSMutableArray arrayWithCapacity:64]; + [_layout enumerateKeysForSize:selectedSize plane:plane transform:defaultKeyTransform usingBlock:^(int8_t scancode, CGRect keyFrame, CGFloat fontScale, BOOL dark, BOOL sticky) { + KBKey *key = nil; + if (scancode == VKC_HIDE) { + key = [[KBHideKey alloc] initWithFrame:keyFrame]; + [key addTarget:self action:@selector(hideKeyboard:) forControlEvents:UIControlEventTouchUpInside]; + } else if (scancode == VKC_SHIFT_CAPS) { + key = [[KBShiftCapsKey alloc] initWithFrame:keyFrame]; + key.scancode = KC_SHIFT; + [key addTarget:self action:@selector(capsKey:) forControlEvents:KBKeyEventStickyKey]; + } else if (sticky) { + key = [[KBStickyKey alloc] initWithFrame:keyFrame]; + key.scancode = scancode; + [key addTarget:self action:@selector(stickyKey:) forControlEvents:KBKeyEventStickyKey]; + } else { + key = [[KBKey alloc] initWithFrame:keyFrame]; + key.scancode = scancode; + [key addTarget:self action:@selector(keyDown:) forControlEvents:UIControlEventTouchDown]; + [key addTarget:self action:@selector(keyUp:) forControlEvents:UIControlEventTouchUpInside | UIControlEventTouchDragExit | UIControlEventTouchCancel]; + } + key.dark = dark; + NSString *label = [_layout labelForScanCode:scancode]; + if ([label containsString:@"\n"]) { + fontScale *= [UIDevice currentDevice].userInterfaceIdiom == UIUserInterfaceIdiomPhone ? 0.6 : 0.65; + } + key.label = label; + key.titleLabel.font = [UIFont systemFontOfSize:fontSize * fontScale weight:UIFontWeightRegular]; + [keyPlane addObject:key]; + }]; + return keyPlane; +} + +- (NSArray *)keys { + return [self.subviews filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:@"self isKindOfClass: %@", [KBKey class]]]; +} + +- (NSArray *)stickyKeys { + return [self.subviews filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:@"self isKindOfClass: %@", [KBStickyKey class]]]; +} + +- (void)switchToKeyPlane:(NSInteger)idx { + if (idx < 0 || idx >= keyPlanes.count) { + return; + } + + // remove previous keys + [self.keys makeObjectsPerformSelector:@selector(removeFromSuperview)]; + + // load keyplane + if (keyPlanes[idx] == [NSNull null]) { + keyPlanes[idx] = [self _loadKeyPlane:idx]; + } + + // add keys + for (KBKey *key in keyPlanes[idx]) { + if ([key isKindOfClass:[KBStickyKey class]]) { + // match modifiers + KBStickyKey *stickyKey = (KBStickyKey *)key; + stickyKey.down = [keysDown containsIndex:key.scancode]; + if ([key isKindOfClass:[KBShiftCapsKey class]]) { + KBShiftCapsKey *shiftCapsKey = (KBShiftCapsKey *)key; + shiftCapsKey.capsLocked = [keysDown containsIndex:KC_CAPSLOCK]; + } + } + [self addSubview:key]; + } +} + +- (void)keyDown:(KBKey *)key { + int16_t scancode = key.scancode; + if (scancode >= 0 && ![keysDown containsIndex:scancode]) { + [keysDown addIndex:scancode]; + [self.delegate keyDown:scancode]; + } else if (scancode < 0) { + [self switchToKeyPlane:(-scancode) - 1]; + } +} + +- (void)keyUp:(KBKey *)key { + int16_t scancode = key.scancode; + if (scancode >= 0 && [keysDown containsIndex:scancode]) { + [keysDown removeIndex:scancode]; + [self.delegate keyUp:scancode]; + // up sticky keys + [self.stickyKeys setValue:@NO forKey:@"down"]; + } +} + +- (void)hideKeyboard:(KBHideKey *)key { + if ([self.delegate respondsToSelector:@selector(hideKeyboard:)]) { + [self.delegate hideKeyboard:key]; + } else { + self.hidden = YES; + } +} + +- (void)stickyKey:(KBStickyKey *)key { + if (key.down && ![keysDown containsIndex:key.scancode]) { + [keysDown addIndex:key.scancode]; + [self.delegate keyDown:key.scancode]; + } else if (!key.down && [keysDown containsIndex:key.scancode]) { + [keysDown removeIndex:key.scancode]; + [self.delegate keyUp:key.scancode]; + } +} + +- (void)capsKey:(KBShiftCapsKey *)key { + if (key.capsLocked && ![keysDown containsIndex:KC_CAPSLOCK]) { + [keysDown addIndex:KC_CAPSLOCK]; + [self.delegate keyDown:KC_CAPSLOCK]; + } else if ([keysDown containsIndex:KC_CAPSLOCK]) { + [keysDown removeIndex:KC_CAPSLOCK]; + [self.delegate keyUp:KC_CAPSLOCK]; + } else { + [self stickyKey:key]; + } +} + +@end diff --git a/Mini vMac/Keyboard Layouts/British.nfkeyboardlayout b/Mini vMac/Keyboard Layouts/British.nfkeyboardlayout new file mode 100644 index 0000000..b8ea204 Binary files /dev/null and b/Mini vMac/Keyboard Layouts/British.nfkeyboardlayout differ diff --git a/Mini vMac/Keyboard Layouts/Spanish (ISO).nfkeyboardlayout b/Mini vMac/Keyboard Layouts/Spanish (ISO).nfkeyboardlayout new file mode 100644 index 0000000..a93fd5d Binary files /dev/null and b/Mini vMac/Keyboard Layouts/Spanish (ISO).nfkeyboardlayout differ diff --git a/Mini vMac/Keyboard Layouts/Spanish.nfkeyboardlayout b/Mini vMac/Keyboard Layouts/Spanish.nfkeyboardlayout new file mode 100644 index 0000000..271f406 Binary files /dev/null and b/Mini vMac/Keyboard Layouts/Spanish.nfkeyboardlayout differ diff --git a/Mini vMac/Keyboard Layouts/US.nfkeyboardlayout b/Mini vMac/Keyboard Layouts/US.nfkeyboardlayout new file mode 100644 index 0000000..ca54a93 Binary files /dev/null and b/Mini vMac/Keyboard Layouts/US.nfkeyboardlayout differ diff --git a/Mini vMac/MYOSGLUE.m b/Mini vMac/MYOSGLUE.m index 78420f9..a4325d2 100644 --- a/Mini vMac/MYOSGLUE.m +++ b/Mini vMac/MYOSGLUE.m @@ -835,7 +835,13 @@ GLOBALPROC SetMouseDelta(ui4r dh, ui4r dv) { MyMousePositionSetDelta(dh, dv); } -#pragma mark - video out +#pragma mark - Keyboard + +GLOBALPROC SetKeyState(int key, blnr down) { + Keyboard_UpdateKeyMap(key, down); +} + +#pragma mark - Video Out LOCALPROC HaveChangedScreenBuff(ui4r top, ui4r left, ui4r bottom, ui4r right) { size_t bitsPerPixel = 1 << vMacScreenDepth; diff --git a/Mini vMac/ViewController.h b/Mini vMac/ViewController.h index d0e1c6d..1f3c65b 100644 --- a/Mini vMac/ViewController.h +++ b/Mini vMac/ViewController.h @@ -8,10 +8,12 @@ #import #import "ScreenView.h" +#import "KBKeyboardView.h" -@interface ViewController : UIViewController +@interface ViewController : UIViewController @property (weak, nonatomic) IBOutlet ScreenView *screenView; +@property (nonatomic, getter=isKeyboardVisible) BOOL keyboardVisible; @end diff --git a/Mini vMac/ViewController.m b/Mini vMac/ViewController.m index 741144a..8bf6379 100644 --- a/Mini vMac/ViewController.m +++ b/Mini vMac/ViewController.m @@ -9,6 +9,8 @@ #import "ViewController.h" #import "TouchScreen.h" #import "AppDelegate.h" +#import "KBKeyboardView.h" +#import "KBKeyboardLayout.h" @interface ViewController () @@ -16,9 +18,16 @@ @implementation ViewController { + KBKeyboardView *keyboardView; + UISwipeGestureRecognizer *showKeyboardGesture, *hideKeyboardGesture; UIControl *pointingDeviceView; } +- (void)viewDidLoad { + [super viewDidLoad]; + [self installKeyboardGestures]; +} + - (BOOL)prefersStatusBarHidden { return YES; } @@ -26,6 +35,11 @@ - (void)viewDidAppear:(BOOL)animated { [super viewDidAppear:animated]; [self setUpPointingDevice]; + [[NSUserDefaults standardUserDefaults] addObserver:self forKeyPath:@"trackpad" options:0 context:NULL]; +} + +- (void)viewDidDisappear:(BOOL)animated { + [[NSUserDefaults standardUserDefaults] removeObserver:self forKeyPath:@"trackpad"]; } - (void)setUpPointingDevice { @@ -44,4 +58,133 @@ } } +- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context { + if (object == [NSUserDefaults standardUserDefaults]) { + if ([keyPath isEqualToString:@"keyboardLayout"] && keyboardView != nil) { + BOOL keyboardWasVisible = self.keyboardVisible; + [self setKeyboardVisible:NO animated:NO]; + [keyboardView removeFromSuperview]; + keyboardView = nil; + if (keyboardWasVisible) { + [self setKeyboardVisible:YES animated:NO]; + } + } else if ([keyPath isEqualToString:@"trackpad"]) { + [self setUpPointingDevice]; + } + } +} + +- (void)viewWillTransitionToSize:(CGSize)size withTransitionCoordinator:(id)coordinator { + [super viewWillTransitionToSize:size withTransitionCoordinator:coordinator]; + if (self.keyboardVisible) { + [self setKeyboardVisible:NO animated:NO]; + [coordinator animateAlongsideTransition:nil completion:^(id _Nonnull context) { + [self setKeyboardVisible:YES animated:YES]; + }]; + } +} + +#pragma mark - Keyboard + +- (void)installKeyboardGestures { + showKeyboardGesture = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:@selector(showKeyboard:)]; + showKeyboardGesture.direction = UISwipeGestureRecognizerDirectionUp; + showKeyboardGesture.numberOfTouchesRequired = 2; + [self.view addGestureRecognizer:showKeyboardGesture]; + + hideKeyboardGesture = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:@selector(hideKeyboard:)]; + hideKeyboardGesture.direction = UISwipeGestureRecognizerDirectionDown; + hideKeyboardGesture.numberOfTouchesRequired = 2; + [self.view addGestureRecognizer:hideKeyboardGesture]; +} + +- (BOOL)isKeyboardVisible { + return keyboardView != nil && CGRectIntersectsRect(keyboardView.frame, self.view.bounds) && !keyboardView.hidden; +} + +- (void)setKeyboardVisible:(BOOL)keyboardVisible { + [self setKeyboardVisible:keyboardVisible animated:YES]; +} + +- (void)showKeyboard:(id)sender { + [self setKeyboardVisible:YES animated:YES]; +} + +- (void)hideKeyboard:(id)sender { + [self setKeyboardVisible:NO animated:YES]; +} + +- (void)setKeyboardVisible:(BOOL)visible animated:(BOOL)animated { + if (self.keyboardVisible == visible) { + return; + } + + if (visible) { + [[NSUserDefaults standardUserDefaults] addObserver:self forKeyPath:@"keyboardLayout" options:0 context:NULL]; + [self loadKeyboardView]; + if (keyboardView.layout == nil) { + [keyboardView removeFromSuperview]; + return; + } + [self.view addSubview:keyboardView]; + keyboardView.hidden = NO; + CGRect finalFrame = CGRectMake(0.0, self.view.bounds.size.height - keyboardView.bounds.size.height, keyboardView.bounds.size.width, keyboardView.bounds.size.height); + if (animated) { + keyboardView.frame = CGRectOffset(finalFrame, 0.0, finalFrame.size.height); + [UIView animateWithDuration:0.3 delay:0.0 options:UIViewAnimationOptionCurveEaseOut animations:^{ + keyboardView.frame = finalFrame; + } completion:nil]; + } else { + keyboardView.frame = finalFrame; + } + } else { + [[NSUserDefaults standardUserDefaults] removeObserver:self forKeyPath:@"keyboardLayout"]; + if (animated) { + CGRect finalFrame = CGRectMake(0.0, self.view.bounds.size.height, keyboardView.bounds.size.width, keyboardView.bounds.size.height); + [UIView animateWithDuration:0.3 delay:0.0 options:UIViewAnimationOptionCurveEaseOut animations:^{ + keyboardView.frame = finalFrame; + } completion:^(BOOL finished) { + if (finished) { + keyboardView.hidden = YES; + } + }]; + } else { + keyboardView.hidden = YES; + } + } + +} + +- (void)loadKeyboardView { + if (keyboardView != nil && keyboardView.bounds.size.width != self.view.bounds.size.width) { + // keyboard needs resizing + [keyboardView removeFromSuperview]; + keyboardView = nil; + } + + if (keyboardView == nil) { + keyboardView = [[KBKeyboardView alloc] initWithFrame:self.view.bounds]; + keyboardView.layout = [self keyboardLayout]; + keyboardView.delegate = self; + } +} + +- (KBKeyboardLayout*)keyboardLayout { + NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; + NSString *layoutName = [defaults stringForKey:@"keyboardLayout"]; + NSString *layoutPath = [[NSBundle mainBundle] pathForResource:layoutName ofType:nil inDirectory:@"Keyboard Layouts"]; + if (layoutPath == nil) { + NSLog(@"Layout not found: %@", layoutPath); + } + return layoutPath ? [[KBKeyboardLayout alloc] initWithContentsOfFile:layoutPath] : nil; +} + +- (void)keyDown:(int)scancode { + [[AppDelegate sharedInstance] keyDown:scancode]; +} + +- (void)keyUp:(int)scancode { + [[AppDelegate sharedInstance] keyUp:scancode]; +} + @end