diff --git a/KompleteSynthesia/AppDelegate.m b/KompleteSynthesia/AppDelegate.m index 3e86d6e..315cc2a 100644 --- a/KompleteSynthesia/AppDelegate.m +++ b/KompleteSynthesia/AppDelegate.m @@ -442,6 +442,12 @@ - (void)synthesiaStateUpdate:(NSString*)status { if (self.statusMenu.itemArray.count > 1) { NSMenuItem* item = self.statusMenu.itemArray[1]; + if ([item.title compare:status] == NSOrderedSame) { + // Lets avoid useless further UI and controller updates as we are receiving + // a lot of state updates for Synthesia. + // FIXME: Seems weird that we get flooded by state updates. + return; + } item.title = status; } [self updateButtonStates]; diff --git a/KompleteSynthesia/FuzzingWindowController.h b/KompleteSynthesia/FuzzingWindowController.h index 5fc0790..70cd133 100644 --- a/KompleteSynthesia/FuzzingWindowController.h +++ b/KompleteSynthesia/FuzzingWindowController.h @@ -12,18 +12,23 @@ NS_ASSUME_NONNULL_BEGIN @class HIDController; @protocol PreferencesDelegate; -@interface FuzzingWindowController : NSWindowController +@interface FuzzingWindowController : NSWindowController @property (nonatomic, weak) IBOutlet NSTextField* initialCommand; @property (nonatomic, weak) IBOutlet NSTextField* currentControlCommand; @property (nonatomic, weak) IBOutlet NSSliderCell* delaySlider; +@property (nonatomic, weak) IBOutlet NSButton* pauseButton; +@property (nonatomic, weak) IBOutlet NSButton* stopButton; +@property (nonatomic, weak) IBOutlet NSButton* startButton; + @property (nonatomic, weak) HIDController* hidController; @property (nonatomic, weak) id delegate; - (IBAction)start:(id)sender; - (IBAction)stop:(id)sender; +- (IBAction)pause:(id)sender; @end diff --git a/KompleteSynthesia/FuzzingWindowController.m b/KompleteSynthesia/FuzzingWindowController.m index d210355..fcc4927 100644 --- a/KompleteSynthesia/FuzzingWindowController.m +++ b/KompleteSynthesia/FuzzingWindowController.m @@ -20,6 +20,7 @@ @interface FuzzingWindowController () @implementation FuzzingWindowController { NSTimer* commandUpdateTimer; NSTimer* fuzzTimer; + BOOL paused; } - (NSString*)hexStringFromBinaryData:(unsigned char*)data withLength:(size_t)length @@ -34,14 +35,26 @@ - (NSString*)hexStringFromBinaryData:(unsigned char*)data withLength:(size_t)len return output; } +- (void)binaryDataFromHexString:(NSString*)input withData:(unsigned char*)data withLength:(size_t)length +{ + NSArray* hexStringBytes = [input componentsSeparatedByString:@" "]; + size_t byteCount = MIN(length, hexStringBytes.count); + for (size_t i = 0; i < byteCount; i++) { + NSString* hex = hexStringBytes[i]; + const char* chars = [hex UTF8String]; + data[i] = strtoul(chars, NULL, 16); + } +} + - (void)windowDidLoad { [super windowDidLoad]; - [_delegate preferencesUpdatedKeyState:0x00 forKeyIndex:0]; - _initialCommand.stringValue = [self hexStringFromBinaryData:_hidController.initialCommand withLength:_hidController.initialCommandLength]; + _initialCommand.delegate = self; + + [_delegate preferencesUpdatedKeyState:0x00 forKeyIndex:0]; commandUpdateTimer = [NSTimer scheduledTimerWithTimeInterval:kCommandUpdateTimerDelay @@ -51,20 +64,62 @@ - (void)windowDidLoad [self hexStringFromBinaryData:self->_hidController.lightGuideUpdateMessage withLength:self->_hidController.lightGuideUpdateMessageSize]; }]; + paused = NO; + [self updateButtonStates]; } -- (IBAction)stop:(id)sender +- (void)controlTextDidEndEditing:(NSNotification*)notification +{ + NSTextField* textField = [notification object]; + if (textField != _initialCommand) { + return; + } + [self binaryDataFromHexString:textField.stringValue + withData:_hidController.initialCommand + withLength:_hidController.initialCommandLength]; +} + +- (void)updateButtonStates +{ + if (paused) { + _startButton.enabled = NO; + _pauseButton.enabled = YES; + _stopButton.enabled = YES; + } else { + _startButton.enabled = fuzzTimer == nil; + _stopButton.enabled = fuzzTimer != nil; + _pauseButton.enabled = fuzzTimer != nil; + } +} + +- (void)stopTimer { if (fuzzTimer != nil) { [fuzzTimer invalidate]; } + fuzzTimer = nil; } -- (IBAction)start:(id)sender +- (IBAction)stop:(id)sender { - self->_hidController.lightGuideUpdateMessage[0] = 0x01; - [_delegate preferencesUpdatedKeyState:0x06 forKeyIndex:0]; + [self stopTimer]; + paused = NO; + [self updateButtonStates]; +} + +- (IBAction)pause:(id)sender +{ + if (fuzzTimer != nil) { + paused = YES; + [self stopTimer]; + } else { + paused = NO; + [self startTimer]; + } +} +- (void)startTimer +{ if (fuzzTimer != nil) { [fuzzTimer invalidate]; } @@ -83,4 +138,14 @@ - (IBAction)start:(id)sender }]; } +- (IBAction)start:(id)sender +{ + _hidController.lightGuideUpdateMessage[0] = 0x01; + [_delegate preferencesUpdatedKeyState:0x06 forKeyIndex:0]; + + [self startTimer]; + paused = NO; + [self updateButtonStates]; +} + @end diff --git a/KompleteSynthesia/FuzzingWindowController.xib b/KompleteSynthesia/FuzzingWindowController.xib index 7682de8..654126d 100644 --- a/KompleteSynthesia/FuzzingWindowController.xib +++ b/KompleteSynthesia/FuzzingWindowController.xib @@ -11,6 +11,9 @@ + + + @@ -47,7 +50,7 @@ - + @@ -72,7 +75,7 @@ + - + - + - + - + diff --git a/KompleteSynthesia/HIDController.m b/KompleteSynthesia/HIDController.m index 6e07ff6..3f54811 100644 --- a/KompleteSynthesia/HIDController.m +++ b/KompleteSynthesia/HIDController.m @@ -38,7 +38,7 @@ // Confirmed that this is the way KompleteKontrol initializes the controller by capturing // the USB traffic. const uint8_t kCommandInit = 0xA0; -const uint8_t kKompleteKontrolInit[] = {kCommandInit, 0x00, 0x00}; +uint8_t kKompleteKontrolInit[] = {kCommandInit, 0x00, 0x00}; /* // FIXME: This likely is not be enough to get the MK3 controller fully initialized. It is what @@ -314,10 +314,14 @@ - (void)receivedReport:(unsigned char*)report length:(int)length for (int i = 0; i < length; i++) { [hex appendFormat:@"%02x ", report[i]]; } - NSLog(@"hid report: %@", hex); - [log logLine:[NSString stringWithFormat:@"hid report: %@", hex]]; + NSString* trail = @""; + if (report[0] != 0x01) { + NSLog(@"ignoring report %02Xh", report[0]); + trail = [trail stringByAppendingString:@" (ignored!)"]; + } + [log logLine:[NSString stringWithFormat:@"hid report: %@%@", hex, trail]]; #endif - + NSLog(@"hid report: %@", hex); if (report[0] != 0x01) { NSLog(@"ignoring report %02Xh", report[0]); return; diff --git a/KompleteSynthesia/SynthesiaController.m b/KompleteSynthesia/SynthesiaController.m index b655b2f..2263acc 100644 --- a/KompleteSynthesia/SynthesiaController.m +++ b/KompleteSynthesia/SynthesiaController.m @@ -103,15 +103,15 @@ - (id)initWithLogViewController:(LogViewController*)logViewController delegate:( dataFormatExpected = NO; needsConfigurationPatch = YES; - [[[NSWorkspace sharedWorkspace] notificationCenter] addObserver:self - selector:@selector(synthesiaMayHaveChangedStatus:) - name:NSWorkspaceDidActivateApplicationNotification - object:nil]; - - [[[NSWorkspace sharedWorkspace] notificationCenter] addObserver:self - selector:@selector(synthesiaMayHaveChangedStatus:) - name:NSWorkspaceDidTerminateApplicationNotification - object:nil]; + NSWorkspace* workspace = [NSWorkspace sharedWorkspace]; + [[workspace notificationCenter] addObserver:self + selector:@selector(synthesiaMayHaveChangedStatus:) + name:NSWorkspaceDidActivateApplicationNotification + object:nil]; + [[workspace notificationCenter] addObserver:self + selector:@selector(synthesiaMayHaveChangedStatus:) + name:NSWorkspaceDidTerminateApplicationNotification + object:nil]; } return self; }