Skip to content

Commit

Permalink
Add bluetooth keyboard support for appstore
Browse files Browse the repository at this point in the history
By using private APIs, we have a perfect keyboard support
(see DosPadUIApplication). However, that's not allowed in
appstore.

By using an invisible text input, we can capture external keyboard
events and translate to emulator key events.
However, it's only good for text input, not game control.

We also support arrows, ctrl-?, alt-?, pageup/down, ...
  • Loading branch information
Chaoji Li committed Oct 17, 2020
1 parent 0e72821 commit ca16f91
Show file tree
Hide file tree
Showing 15 changed files with 351 additions and 975 deletions.
4 changes: 2 additions & 2 deletions SDL/src/video/uikit/keyinfotable.h
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,8 @@ static UIKitKeyInfo unicharToUIKeyInfoTable[] = {
/* 6 */ { SDL_SCANCODE_UNKNOWN, 0 },
/* 7 */ { SDL_SCANCODE_UNKNOWN, 0 },
/* 8 */ { SDL_SCANCODE_UNKNOWN, 0 },
/* 9 */ { SDL_SCANCODE_UNKNOWN, 0 },
/* 10 */ { SDL_SCANCODE_UNKNOWN, 0 },
/* 9 */ { SDL_SCANCODE_TAB, 0 },
/* 10 */ { SDL_SCANCODE_RETURN, 0 },
/* 11 */ { SDL_SCANCODE_UNKNOWN, 0 },
/* 12 */ { SDL_SCANCODE_UNKNOWN, 0 },
/* 13 */ { SDL_SCANCODE_UNKNOWN, 0 },
Expand Down
19 changes: 7 additions & 12 deletions dospad.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@
2A4546F917D2809F00D18563 /* CoreMIDI.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E7F2A9CD12CD99EC0091B859 /* CoreMIDI.framework */; };
2A4546FA17D2812100D18563 /* PianoKeyboard.m in Sources */ = {isa = PBXBuildFile; fileRef = E794F3FE12DB4F0E00427836 /* PianoKeyboard.m */; };
9222DD561CC44A9F00B321B9 /* GameController.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9222DD551CC44A9F00B321B9 /* GameController.framework */; };
E70836B92539EEB200B9321F /* KeyboardSpy.m in Sources */ = {isa = PBXBuildFile; fileRef = E70836B82539EEB200B9321F /* KeyboardSpy.m */; };
E70C044112A4B43F00AC178F /* AVFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E70C044012A4B43F00AC178F /* AVFoundation.framework */; };
E7107154129A8E5A00B21291 /* cpuwindow.png in Resources */ = {isa = PBXBuildFile; fileRef = E7107147129A8E5A00B21291 /* cpuwindow.png */; };
E7107155129A8E5A00B21291 /* exitfull.png in Resources */ = {isa = PBXBuildFile; fileRef = E7107148129A8E5A00B21291 /* exitfull.png */; };
Expand Down Expand Up @@ -384,7 +385,6 @@
E778B2CB123919ED008AF49A /* SDLnetsys.h in Headers */ = {isa = PBXBuildFile; fileRef = E778B2C5123919ED008AF49A /* SDLnetsys.h */; };
E778B2CC123919ED008AF49A /* SDLnetTCP.c in Sources */ = {isa = PBXBuildFile; fileRef = E778B2C6123919ED008AF49A /* SDLnetTCP.c */; };
E778B2CD123919ED008AF49A /* SDLnetUDP.c in Sources */ = {isa = PBXBuildFile; fileRef = E778B2C7123919ED008AF49A /* SDLnetUDP.c */; };
E7A01EE51CC927760036A4CF /* UIExtendedTextField.m in Sources */ = {isa = PBXBuildFile; fileRef = E7A01EE11CC927370036A4CF /* UIExtendedTextField.m */; };
E7A01EE71CC9277E0036A4CF /* ColorTheme.m in Sources */ = {isa = PBXBuildFile; fileRef = E7A01EDD1CC927370036A4CF /* ColorTheme.m */; };
E7A01EF41CC9A5480036A4CF /* CoreAudio.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FDB9E40C0DEB81970027A75A /* CoreAudio.framework */; };
E7A01EF71CC9C1AB0036A4CF /* gift.png in Resources */ = {isa = PBXBuildFile; fileRef = E7A01EE81CC92F0C0036A4CF /* gift.png */; };
Expand Down Expand Up @@ -447,7 +447,6 @@
E7BE12FC128BF31A0046990B /* FloatingView.m in Sources */ = {isa = PBXBuildFile; fileRef = E799706312422D6800502015 /* FloatingView.m */; };
E7BE12FD128BF31A0046990B /* SliderView.m in Sources */ = {isa = PBXBuildFile; fileRef = E70EA4111242F83200528C9D /* SliderView.m */; };
E7BE12FF128BF31A0046990B /* GamePadView.m in Sources */ = {isa = PBXBuildFile; fileRef = E7A94CDC127D68B7006509E1 /* GamePadView.m */; };
E7BE1301128BF31A0046990B /* VKView.m in Sources */ = {isa = PBXBuildFile; fileRef = E723F0C51286A1680009E3DA /* VKView.m */; };
E7BE1305128BF31A0046990B /* libSDLiPhoneOS.a in Frameworks */ = {isa = PBXBuildFile; fileRef = FD6526630DE8FCCB002AD96B /* libSDLiPhoneOS.a */; };
E7BE1306128BF31A0046990B /* libdosbox.a in Frameworks */ = {isa = PBXBuildFile; fileRef = E71E60EB11B5506800EC5A05 /* libdosbox.a */; };
E7BE1307128BF31A0046990B /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1D3623EB0D0F72F000981E51 /* CoreGraphics.framework */; };
Expand Down Expand Up @@ -711,6 +710,8 @@
1D3623EB0D0F72F000981E51 /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = System/Library/Frameworks/CoreGraphics.framework; sourceTree = SDKROOT; };
1DF5F4DF0D08C38300B7A737 /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; };
9222DD551CC44A9F00B321B9 /* GameController.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = GameController.framework; path = System/Library/Frameworks/GameController.framework; sourceTree = SDKROOT; };
E70836B72539EEB200B9321F /* KeyboardSpy.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = KeyboardSpy.h; sourceTree = "<group>"; };
E70836B82539EEB200B9321F /* KeyboardSpy.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = KeyboardSpy.m; sourceTree = "<group>"; };
E70C044012A4B43F00AC178F /* AVFoundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AVFoundation.framework; path = System/Library/Frameworks/AVFoundation.framework; sourceTree = SDKROOT; };
E70EA4101242F83200528C9D /* SliderView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SliderView.h; path = ../iPad/SliderView.h; sourceTree = "<group>"; };
E70EA4111242F83200528C9D /* SliderView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = SliderView.m; path = ../iPad/SliderView.m; sourceTree = "<group>"; };
Expand Down Expand Up @@ -982,8 +983,6 @@
E71E61F511B550FD00EC5A05 /* shell_batch.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = shell_batch.cpp; sourceTree = "<group>"; };
E71E61F611B550FD00EC5A05 /* shell_cmds.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = shell_cmds.cpp; sourceTree = "<group>"; };
E71E61F711B550FD00EC5A05 /* shell_misc.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = shell_misc.cpp; sourceTree = "<group>"; };
E723F0C41286A1680009E3DA /* VKView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = VKView.h; sourceTree = "<group>"; };
E723F0C51286A1680009E3DA /* VKView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = VKView.m; sourceTree = "<group>"; };
E729BDF0129B506E002B05B2 /* cpuwindow~ipad.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "cpuwindow~ipad.png"; sourceTree = "<group>"; };
E729BDF1129B506E002B05B2 /* exitfull~ipad.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "exitfull~ipad.png"; sourceTree = "<group>"; };
E729BDF2129B506E002B05B2 /* modejoy~ipad.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "modejoy~ipad.png"; sourceTree = "<group>"; };
Expand Down Expand Up @@ -1115,8 +1114,6 @@
E79E4A0011EC6BF400DEAA7B /* libc.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libc.dylib; path = usr/lib/libc.dylib; sourceTree = SDKROOT; };
E7A01EDC1CC927370036A4CF /* ColorTheme.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ColorTheme.h; path = Shared/ColorTheme.h; sourceTree = "<group>"; };
E7A01EDD1CC927370036A4CF /* ColorTheme.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = ColorTheme.m; path = Shared/ColorTheme.m; sourceTree = "<group>"; };
E7A01EE01CC927370036A4CF /* UIExtendedTextField.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = UIExtendedTextField.h; sourceTree = "<group>"; };
E7A01EE11CC927370036A4CF /* UIExtendedTextField.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = UIExtendedTextField.m; sourceTree = "<group>"; };
E7A01EE81CC92F0C0036A4CF /* gift.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = gift.png; path = "misc-res/gift.png"; sourceTree = "<group>"; };
E7A01EE91CC92F0C0036A4CF /* kbd.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = kbd.png; path = "misc-res/kbd.png"; sourceTree = "<group>"; };
E7A01EF01CC92F450036A4CF /* button.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = button.png; path = "gamepad-res/button.png"; sourceTree = "<group>"; };
Expand Down Expand Up @@ -2061,8 +2058,6 @@
E7D214C511E45BD000D9654E /* keys.h */,
E7D214C711E45BDE00D9654E /* keys.m */,
E77DAFC411B5D83600B78E69 /* main.m */,
E7A01EE01CC927370036A4CF /* UIExtendedTextField.h */,
E7A01EE11CC927370036A4CF /* UIExtendedTextField.m */,
E73A56692534979900E3B3FB /* MfiGamepadConfiguration.h */,
E73A566A2534979900E3B3FB /* MfiGamepadConfiguration.m */,
E73A566C2534A49000E3B3FB /* MfiGamepadManager.h */,
Expand Down Expand Up @@ -2196,8 +2191,8 @@
E70EA4111242F83200528C9D /* SliderView.m */,
E7996FAB1241C0A800502015 /* TipView.h */,
E7996FAC1241C0A800502015 /* TipView.m */,
E723F0C41286A1680009E3DA /* VKView.h */,
E723F0C51286A1680009E3DA /* VKView.m */,
E70836B72539EEB200B9321F /* KeyboardSpy.h */,
E70836B82539EEB200B9321F /* KeyboardSpy.m */,
);
name = Views;
path = Shared;
Expand Down Expand Up @@ -3308,7 +3303,6 @@
E7BE12EA128BF31A0046990B /* DosPadViewController.m in Sources */,
E7BE12EB128BF31A0046990B /* main.m in Sources */,
E7BE12F3128BF31A0046990B /* keys.m in Sources */,
E7A01EE51CC927760036A4CF /* UIExtendedTextField.m in Sources */,
E7BE12F6128BF31A0046990B /* HoldIndicator.m in Sources */,
E73A566B2534979900E3B3FB /* MfiGamepadConfiguration.m in Sources */,
E7BE12F7128BF31A0046990B /* FrameskipIndicator.m in Sources */,
Expand All @@ -3319,7 +3313,6 @@
E7BE12FC128BF31A0046990B /* FloatingView.m in Sources */,
E7BE12FD128BF31A0046990B /* SliderView.m in Sources */,
E7BE12FF128BF31A0046990B /* GamePadView.m in Sources */,
E7BE1301128BF31A0046990B /* VKView.m in Sources */,
E7EF4372128FCE470014D060 /* AlertPrompt.m in Sources */,
E72BE69712911096009DC46A /* DosPadViewController_iPhone.m in Sources */,
E7A01EE71CC9277E0036A4CF /* ColorTheme.m in Sources */,
Expand All @@ -3333,6 +3326,7 @@
E72BE6EF12911B5C009DC46A /* ZipArchive.m in Sources */,
E715B35B1293B7750098D437 /* DOSPadBaseViewController.m in Sources */,
E76C49381299490200901B69 /* FloatPanel.m in Sources */,
E70836B92539EEB200B9321F /* KeyboardSpy.m in Sources */,
E74BB2B715C93DBC005EC552 /* DosPadUIApplication.m in Sources */,
2A4546FA17D2812100D18563 /* PianoKeyboard.m in Sources */,
);
Expand Down Expand Up @@ -3808,6 +3802,7 @@
DEBUG,
IDOS,
IPHONEOS,
APPSTORE,
);
GCC_VERSION = com.apple.compilers.llvm.clang.1_0;
INFOPLIST_FILE = "Resources/iDOS-Info.plist";
Expand Down
5 changes: 2 additions & 3 deletions dospad/Shared/DOSPadBaseViewController.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,11 +25,11 @@
#import "GamePadView.h"
#import "PianoKeyboard.h"
#import "DOSPadEmulator.h"
#import "KeyboardSpy.h"

typedef enum {
InputSource_PCKeyboard = 0,
InputSource_MouseButtons,
InputSource_iOSKeyboard,
InputSource_NumPad,
InputSource_GamePad,
InputSource_Joystick,
Expand All @@ -51,8 +51,6 @@ typedef enum {
SDL_uikitopenglview *screenView;
HoldIndicator *holdIndicator;

// Input Devices
//VKView *vk; // Background, conflicts with iOS keyboard
GamePadView *gamepad;
GamePadView *joystick;
KeyboardView *kbd;
Expand All @@ -64,6 +62,7 @@ typedef enum {

@property (nonatomic, assign) BOOL autoExit;
@property (nonatomic, strong) SDL_uikitopenglview *screenView;
@property (nonatomic, strong) KeyboardSpy *kbdspy;

+ (DOSPadBaseViewController*)dospadController;

Expand Down
91 changes: 12 additions & 79 deletions dospad/Shared/DOSPadBaseViewController.m
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,12 @@ - (void)viewWillAppear:(BOOL)animated
screenView.alpha = 1; // Try to fix reboot problem on iPad 3.2.x
dospad_resume();
[self.navigationController setNavigationBarHidden:YES animated:NO];

if (self.kbdspy)
{
[self.kbdspy becomeFirstResponder];
[self.view bringSubviewToFront:self.kbdspy];
}
}

- (void)viewWillDisappear:(BOOL)animated
Expand All @@ -171,54 +177,13 @@ - (void)viewDidLoad
//holdIndicator.transform = CGAffineTransformMakeScale(1.5, 1.5);
// [self.view addSubview:holdIndicator];

/* TODO: LITCHIE commented out by TVD
vk = [[VKView alloc] initWithFrame:CGRectMake(0,0,1,1)];
vk.alpha = 0;
[self.view addSubview:vk];
*/

//---------------------------------------------------
// Remap controls
//---------------------------------------------------
#if 0
remappingOnLabel = [[UILabel alloc] initWithFrame:CGRectZero];
remappingOnLabel.text = @"Remapping Controls ON";
remappingOnLabel.textColor = [UIColor redColor];
remappingOnLabel.translatesAutoresizingMaskIntoConstraints = NO;
[self.view addSubview:remappingOnLabel];
[self.view addConstraint:[NSLayoutConstraint constraintWithItem:remappingOnLabel attribute:NSLayoutAttributeCenterX relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeCenterX multiplier:1.0f constant:0.0f]];
[self.view addConstraint:[NSLayoutConstraint constraintWithItem:remappingOnLabel attribute:NSLayoutAttributeCenterY relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeCenterY multiplier:0.5f constant:0.0f]];
remappingOnLabel.backgroundColor = [UIColor blackColor];
remappingOnLabel.alpha = 0.6f;
remappingOnLabel.hidden = YES;

resetMappingsButton = [[UIButton alloc] initWithFrame:CGRectZero];
[resetMappingsButton setTitle:@"Reset Mappings" forState:UIControlStateNormal];
[resetMappingsButton setTitleColor:[UIColor redColor] forState:UIControlStateNormal];
[resetMappingsButton setTintColor:[UIColor redColor]];
resetMappingsButton.translatesAutoresizingMaskIntoConstraints = NO;
[resetMappingsButton addTarget:self action:@selector(resetMappingsButtonTapped:) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:resetMappingsButton];
[self.view addConstraint:[NSLayoutConstraint constraintWithItem:resetMappingsButton attribute:NSLayoutAttributeCenterX relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeCenterX multiplier:1.0f constant:0.0f]];
[self.view addConstraint:[NSLayoutConstraint constraintWithItem:resetMappingsButton attribute:NSLayoutAttributeCenterY relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeCenterY multiplier:0.75f constant:0.0f]];
resetMappingsButton.contentEdgeInsets = UIEdgeInsetsMake(4.0f, 10.0f, 4.0f, 10.0f);
resetMappingsButton.backgroundColor = [UIColor blackColor];
resetMappingsButton.alpha = 0.6f;
resetMappingsButton.layer.borderWidth = 1.0f;
resetMappingsButton.layer.borderColor = [[UIColor redColor] CGColor];
resetMappingsButton.hidden = YES;
#ifdef APPSTORE
// For non appstore builds, we should use private API to support
// external keyboard.
self.kbdspy = [[KeyboardSpy alloc] initWithFrame:CGRectMake(0,0,60,40)];
[self.view addSubview:self.kbdspy];
#endif

self.keyMapper = [[KeyMapper alloc] init];
[self.keyMapper loadFromDefaults];
self.mfiHandler = [[MfiGameControllerHandler alloc] init];
self.mfiInputHandler = [[MfiControllerInputHandler alloc] init];
self.mfiInputHandler.keyMapper = self.keyMapper;
[self.mfiHandler discoverController:^(GCController *gameController) {
[self.mfiInputHandler setupControllerInputsForController:gameController];
} disconnectedCallback:^{

}];
#endif
}


Expand Down Expand Up @@ -250,9 +215,6 @@ - (NSUInteger)supportedInterfaceOrientations

- (void)dealloc {
[self removeAllInputSources];

//TODO LITCHIE commented out by TVD
//[vk release];
}

- (void)onLaunchExit
Expand Down Expand Up @@ -411,30 +373,6 @@ - (BOOL)prefersStatusBarHidden {
return YES;
}

- (void)removeiOSKeyboard
{
//TODO: Litchie commented out by tvd
/*
if (vk.useNativeKeyboard != YES)
return;
// Hide the virtual native keyboard
// However, we are still listening to external keyboard input
vk.active = NO;
vk.useNativeKeyboard=NO;
vk.active = YES;
*/
}

- (void)createiOSKeyboard
{
//TODO: Litchie commented out by tvd
/*
if (vk.active)
vk.active = NO;
vk.useNativeKeyboard = YES;
vk.active = YES;*/
}

- (void)NOT_IMPLEMENTED(createPCKeyboard);
- (void)NOT_IMPLEMENTED(createNumpad);
- (void)NOT_IMPLEMENTED(createGamepad);
Expand Down Expand Up @@ -531,11 +469,6 @@ - (void)removeInputSource:(InputSourceType)type
}
break;
}
case InputSource_iOSKeyboard:
{
[self removeiOSKeyboard];
break;
}
case InputSource_GamePad:
{
if (gamepad)
Expand Down
2 changes: 2 additions & 0 deletions dospad/Shared/DOSPadEmulator.h
Original file line number Diff line number Diff line change
Expand Up @@ -43,5 +43,7 @@
- (void)sendCommand:(NSString *)cmd;
- (void)updateJoystick:(NSInteger)index x:(float)x y:(float)y;
- (void)joystickButton:(NSInteger)buttonIndex pressed:(BOOL)pressed joystickIndex:(NSInteger)index;
- (void)sendKey:(int)scancode pressed:(BOOL)pressed;
- (void)sendKey:(int)scancode;

@end
15 changes: 14 additions & 1 deletion dospad/Shared/DOSPadEmulator.m
Original file line number Diff line number Diff line change
Expand Up @@ -50,10 +50,11 @@
extern int SDL_main(int argc, char *argv[]);
static DOSPadEmulator* _sharedInstance;

#define MAX_PENDING_KEY_EVENTS 1000

@interface DOSPadEmulator ()
{
SDL_Joystick *_joystick[4];

}
@end

Expand Down Expand Up @@ -216,6 +217,18 @@ - (void)sendCommand:(NSString *)cmd

}

- (void)sendKey:(int)scancode pressed:(BOOL)pressed
{
SDL_SendKeyboardKey( 0, pressed?SDL_PRESSED:SDL_RELEASED, scancode);
}

- (void)sendKey:(int)scancode
{
SDL_SendKeyboardKey( 0, SDL_PRESSED, scancode);
[NSThread sleepForTimeInterval:0.05]; // Very very important
SDL_SendKeyboardKey( 0, SDL_RELEASED, scancode);
}

- (BOOL)ensureJoystick:(NSInteger)index
{
if (!_joystick[index])
Expand Down
16 changes: 16 additions & 0 deletions dospad/Shared/KeyboardSpy.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
//
// KeyboardSpy.h
//
// Listening on external keyboard input.
// SDL has an implementation but that's tightly coupled with the
// screen view, and it's not a great solution for iDOS.
//
#import <UIKit/UIKit.h>

NS_ASSUME_NONNULL_BEGIN

@interface KeyboardSpy : UIView<UIKeyInput>
@property (nonatomic, assign) BOOL active;
@end

NS_ASSUME_NONNULL_END
Loading

0 comments on commit ca16f91

Please sign in to comment.