add emulated keyboard UI

This commit is contained in:
Jesús A. Álvarez 2016-05-14 13:01:02 +02:00
parent 6ad6dc59c9
commit 9ee5f012ca
93 changed files with 1774 additions and 4 deletions

View File

@ -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 = "<group>"; };
28848B631CDE97E900B86C45 /* SettingsViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SettingsViewController.h; sourceTree = "<group>"; };
28848B641CDE97E900B86C45 /* SettingsViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SettingsViewController.m; sourceTree = "<group>"; };
28BA89741CE7315400A98104 /* KBKey.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = KBKey.h; sourceTree = "<group>"; };
28BA89751CE7315400A98104 /* KBKey.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = KBKey.m; sourceTree = "<group>"; };
28BA89761CE7315400A98104 /* KBKeyboardLayout.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = KBKeyboardLayout.h; sourceTree = "<group>"; };
28BA89771CE7315400A98104 /* KBKeyboardLayout.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = KBKeyboardLayout.m; sourceTree = "<group>"; };
28BA89781CE7315400A98104 /* KBKeyboardView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = KBKeyboardView.h; sourceTree = "<group>"; };
28BA89791CE7315400A98104 /* KBKeyboardView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = KBKeyboardView.m; sourceTree = "<group>"; };
28BA89811CE7336500A98104 /* Keyboard Layouts */ = {isa = PBXFileReference; lastKnownFileType = folder; path = "Keyboard Layouts"; sourceTree = "<group>"; };
28CE8E881CD4C33E00FE25A8 /* CNFGGLOB.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CNFGGLOB.h; sourceTree = "<group>"; };
28CE8E891CD4C33E00FE25A8 /* CNFGRAPI.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CNFGRAPI.h; sourceTree = "<group>"; };
28CE8E8A1CD4C33E00FE25A8 /* EMCONFIG.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = EMCONFIG.h; sourceTree = "<group>"; };
@ -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 = "<group>";
};
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 */,

View File

@ -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;

View File

@ -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 {

View File

@ -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"
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 236 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 317 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 302 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 366 B

View File

@ -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"
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 258 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 401 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 315 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 451 B

View File

@ -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"
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 345 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 563 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 414 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 576 B

View File

@ -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"
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 586 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 683 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 981 B

View File

@ -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"
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 313 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 526 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 374 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 560 B

View File

@ -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"
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 435 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 726 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 493 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 668 B

View File

@ -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"
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 312 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 526 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 375 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 557 B

View File

@ -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"
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 433 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 718 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 492 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 664 B

View File

@ -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"
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 242 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 438 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 300 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 478 B

View File

@ -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"
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 202 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 354 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 574 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 497 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 342 B

View File

@ -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"
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 214 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 377 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 579 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 531 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 339 B

View File

@ -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"
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 138 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 178 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 223 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 136 B

View File

@ -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"
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 172 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 203 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 365 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 263 B

View File

@ -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"
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 211 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 274 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 257 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 314 B

View File

@ -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"
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 305 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 467 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 341 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 580 B

33
Mini vMac/KBKey.h Normal file
View File

@ -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 <UIKit/UIKit.h>
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

196
Mini vMac/KBKey.m Normal file
View File

@ -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<NSString *> *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

View File

@ -0,0 +1,26 @@
//
// KBKeyboardLayout.h
// BasiliskII
//
// Created by Jesús A. Álvarez on 09/04/2016.
// Copyright © 2016 namedfork. All rights reserved.
//
#import <UIKit/UIKit.h>
#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<NSValue*> *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

View File

@ -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<NSString*>*)readStrings:(NSUInteger)count emptyStringMarker:(id)emptyStringMarker;
@end
typedef NSArray<KBKeyDescriptor*> KBKeyPlane;
typedef NSMutableArray<KBKeyDescriptor*> KBMutableKeyPlane;
typedef NSArray<KBKeyPlane*> KBKeyMap;
typedef NSMutableArray<KBKeyPlane*> KBMutableKeyMap;
@implementation KBKeyboardLayout
{
NSMutableDictionary<NSNumber*,NSString*> *labels;
NSArray<NSString*> *keyPlaneLabels;
NSMutableDictionary<NSValue*, KBKeyMap*> *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<NSValue *> *)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<NSNumber*,NSNumber*> *mapIndex = [NSMutableDictionary dictionaryWithCapacity:numberOfMaps];
NSMutableArray<NSNumber*> *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<NSNumber*,KBKeyMap*> *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<NSNumber*> *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<NSString*,NSString*> *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<NSString *,id> * _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<NSString *,id> * _Nullable bindings) {
CGSize size = CGSizeFromString(evaluatedObject);
return !CGSizeEqualToSize(size, CGSizeZero);
}]].mutableCopy;
NSMutableDictionary<NSValue*,NSString*> *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<NSNumber*> *scaleArgs = keyDict[@"scale"];
if ([scaleArgs isKindOfClass:[NSArray class]] && scaleArgs.count == 2) {
includeTransform = CGAffineTransformScale(includeTransform, scaleArgs[0].CGFloatValue, scaleArgs[1].CGFloatValue);
}
NSArray<NSNumber*> *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<NSString*>*)readStrings:(NSUInteger)count emptyStringMarker:(id)emptyStringMarker {
NSMutableArray *strings = [NSMutableArray arrayWithCapacity:count];
while (count--) {
[strings addObject:[self readString] ?: emptyStringMarker];
}
return strings;
}
@end

View File

@ -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 <UIKit/UIKit.h>
#import "KBKeyboardLayout.h"
@class KBKey;
@protocol KBKeyboardViewDelegate <NSObject>
- (void)keyDown:(int)scancode;
- (void)keyUp:(int)scancode;
@optional
- (void)hideKeyboard:(nullable id)sender;
@end
@interface KBKeyboardView : UIView
@property (weak, nonatomic, nullable) id<KBKeyboardViewDelegate> delegate;
@property (nonatomic, strong, nullable) KBKeyboardLayout *layout;
@property (nonatomic, readonly, nonnull) NSArray<KBKey*>* keys;
@property (nonatomic, readonly, nonnull) NSArray<KBKey*>* stickyKeys;
@end

217
Mini vMac/KBKeyboardView.m Normal file
View File

@ -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<KBKey *> *)keys {
return [self.subviews filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:@"self isKindOfClass: %@", [KBKey class]]];
}
- (NSArray<KBKey *> *)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

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -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;

View File

@ -8,10 +8,12 @@
#import <UIKit/UIKit.h>
#import "ScreenView.h"
#import "KBKeyboardView.h"
@interface ViewController : UIViewController
@interface ViewController : UIViewController <KBKeyboardViewDelegate>
@property (weak, nonatomic) IBOutlet ScreenView *screenView;
@property (nonatomic, getter=isKeyboardVisible) BOOL keyboardVisible;
@end

View File

@ -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<NSString *,id> *)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<UIViewControllerTransitionCoordinator>)coordinator {
[super viewWillTransitionToSize:size withTransitionCoordinator:coordinator];
if (self.keyboardVisible) {
[self setKeyboardVisible:NO animated:NO];
[coordinator animateAlongsideTransition:nil completion:^(id<UIViewControllerTransitionCoordinatorContext> _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