forked from Hammerspoon/hammerspoon
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
cededda
commit c1d33c7
Showing
10 changed files
with
1,081 additions
and
1 deletion.
There are no files selected for viewing
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,81 @@ | ||
// | ||
// HSSpeedEditorDevice.h | ||
// Hammerspoon | ||
// | ||
// Created by Chris Jones on 06/09/2017. | ||
// Copyright © 2017 Hammerspoon. All rights reserved. | ||
// | ||
|
||
@import Foundation; | ||
@import Cocoa; | ||
@import IOKit; | ||
@import IOKit.hid; | ||
@import LuaSkin; | ||
|
||
|
||
/* | ||
#import "NSImage+BMP.h" | ||
#import "NSImage+JPEG.h" | ||
#import "NSImage+Rotated.h" | ||
#import "NSImage+Flipped.h" | ||
*/ | ||
|
||
#import "speededitor.h" | ||
|
||
|
||
typedef enum : NSUInteger { | ||
STREAMDECK_CODEC_UNKNOWN, | ||
STREAMDECK_CODEC_BMP, | ||
STREAMDECK_CODEC_JPEG, | ||
} HSStreamDeckImageCodec; | ||
|
||
@interface HSSpeedEditorDevice : NSObject { | ||
NSString *serialNumberCache; | ||
} | ||
@property (nonatomic) IOHIDDeviceRef device; | ||
@property (nonatomic) id manager; | ||
@property (nonatomic) int selfRefCount; | ||
@property (nonatomic) int buttonCallbackRef; | ||
@property (nonatomic) BOOL isValid; | ||
|
||
@property (nonatomic) NSString *deckType; | ||
@property (nonatomic, readonly, getter=getKeyCount) int keyCount; | ||
@property (nonatomic) int keyColumns; | ||
@property (nonatomic) int keyRows; | ||
@property (nonatomic) int imageWidth; | ||
@property (nonatomic) int imageHeight; | ||
@property (nonatomic) HSStreamDeckImageCodec imageCodec; | ||
@property (nonatomic) BOOL imageFlipX; | ||
@property (nonatomic) BOOL imageFlipY; | ||
@property (nonatomic) int imageAngle; | ||
@property (nonatomic) int simpleReportLength; | ||
@property (nonatomic) int reportLength; | ||
@property (nonatomic) int reportHeaderLength; | ||
@property (nonatomic) int dataKeyOffset; | ||
|
||
@property (nonatomic) NSMutableArray *buttonStateCache; | ||
@property (nonatomic, readonly, getter=getSerialNumber) NSString *serialNumber; | ||
|
||
- (id)initWithDevice:(IOHIDDeviceRef)device manager:(id)manager; | ||
- (void)invalidate; | ||
- (void)initialiseCaches; | ||
|
||
- (IOReturn)deviceWriteSimpleReport:(uint8_t *)report reportLen:(int)reportLen; | ||
- (IOReturn)deviceWrite:(NSData *)report; | ||
- (void)deviceWriteImage:(NSData *)data button:(int)button; | ||
- (NSData *)deviceRead:(int)resultLength reportID:(CFIndex)reportID; | ||
|
||
- (int)transformKeyIndex:(int)sourceKey; | ||
- (void)deviceDidSendInput:(NSArray*)newButtonStates; | ||
- (BOOL)setBrightness:(int)brightness; | ||
- (void)reset; | ||
|
||
- (NSString *)cacheSerialNumber; | ||
- (NSString *)firmwareVersion; | ||
- (int)getKeyCount; | ||
|
||
- (void)clearImage:(int)button; | ||
- (void)setColor:(NSColor*)color forButton:(int)button; | ||
//- (void)setImage:(NSImage*)image forButton:(int)button; | ||
|
||
@end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,193 @@ | ||
// | ||
// HSSpeedEditorDevice.m | ||
// Hammerspoon | ||
// | ||
// Created by Chris Jones on 06/09/2017. | ||
// Copyright © 2017 Hammerspoon. All rights reserved. | ||
// | ||
|
||
#import "HSSpeedEditorDevice.h" | ||
|
||
@interface HSSpeedEditorDevice () | ||
@property (nonatomic, copy) NSString *serialNumber; | ||
@end | ||
|
||
@implementation HSSpeedEditorDevice | ||
- (id)initWithDevice:(IOHIDDeviceRef)device manager:(id)manager { | ||
self = [super init]; | ||
if (self) { | ||
self.device = device; | ||
self.isValid = YES; | ||
self.manager = manager; | ||
self.buttonCallbackRef = LUA_NOREF; | ||
self.selfRefCount = 0; | ||
|
||
self.buttonStateCache = [[NSMutableArray alloc] init]; | ||
|
||
// These defaults are not necessary, all base classes will override them, but if we miss something, these are chosen to try and provoke a crash where possible, so we notice the lack of an override. | ||
self.imageCodec = STREAMDECK_CODEC_UNKNOWN; | ||
self.deckType = @"Unknown"; | ||
self.keyColumns = -1; | ||
self.keyRows = -1; | ||
self.imageFlipX = NO; | ||
self.imageFlipY = NO; | ||
self.imageAngle = 0; | ||
self.simpleReportLength = 0; | ||
self.reportLength = 0; | ||
self.reportHeaderLength = 0; | ||
|
||
self.dataKeyOffset = 0; | ||
|
||
serialNumberCache = nil; | ||
//NSLog(@"Added new Stream Deck device %p with IOKit device %p from manager %p", (__bridge void *)self, (void*)self.device, (__bridge void *)self.manager); | ||
} | ||
return self; | ||
} | ||
|
||
- (void)invalidate { | ||
self.isValid = NO; | ||
} | ||
|
||
- (void)initialiseCaches { | ||
for (int i = 0; i <= self.keyCount; i++) { | ||
[self.buttonStateCache setObject:@0 atIndexedSubscript:i]; | ||
} | ||
[self cacheSerialNumber]; | ||
} | ||
|
||
- (IOReturn)deviceWriteSimpleReport:(uint8_t[])report reportLen:(int)reportLen { | ||
if (self.simpleReportLength == 0) { | ||
[LuaSkin logError:@"Initialising Stream Deck device with no simple report length defined"]; | ||
return kIOReturnInternalError; | ||
} | ||
NSMutableData *reportData = [NSMutableData dataWithLength:self.simpleReportLength]; | ||
[reportData replaceBytesInRange:NSMakeRange(0, reportLen) withBytes:report]; | ||
return [self deviceWrite:reportData]; | ||
} | ||
|
||
- (IOReturn)deviceWrite:(NSData *)report { | ||
const uint8_t *rawBytes = (const uint8_t*)report.bytes; | ||
return IOHIDDeviceSetReport(self.device, kIOHIDReportTypeFeature, rawBytes[0], rawBytes, report.length); | ||
} | ||
|
||
- (NSData *)deviceRead:(int)resultLength reportID:(CFIndex)reportID { | ||
CFIndex reportLength = resultLength + 5; | ||
uint8_t *report = malloc(reportLength); | ||
|
||
//NSLog(@"deviceRead: expecting resultLength %d, calculated report length %ld", resultLength, (long)reportLength); | ||
|
||
IOHIDDeviceGetReport(self.device, kIOHIDReportTypeFeature, reportID, report, &reportLength); | ||
char *c_data = (char *)(report + 5); | ||
NSData *data = [NSData dataWithBytes:c_data length:resultLength]; | ||
free(report); | ||
|
||
return data; | ||
} | ||
|
||
- (int)transformKeyIndex:(int)sourceKey { | ||
//NSLog(@"transformKeyIndex: returning %d unmodified", sourceKey); | ||
return sourceKey; | ||
} | ||
|
||
- (void)deviceDidSendInput:(NSArray*)newButtonStates { | ||
//NSLog(@"Got an input event from device: %p: button:%@ isDown:%@", (__bridge void*)self, button, isDown); | ||
|
||
if (!self.isValid) { | ||
return; | ||
} | ||
|
||
LuaSkin *skin = [LuaSkin sharedWithState:NULL]; | ||
_lua_stackguard_entry(skin.L); | ||
if (self.buttonCallbackRef == LUA_NOREF || self.buttonCallbackRef == LUA_REFNIL) { | ||
[skin logError:@"hs.streamdeck received a button input, but no callback has been set. See hs.streamdeck:buttonCallback()"]; | ||
return; | ||
} | ||
|
||
//NSLog(@"buttonStateCache: %@", self.buttonStateCache); | ||
//NSLog(@"newButtonStates: %@", newButtonStates); | ||
|
||
for (int button=1; button <= self.keyCount; button++) { | ||
if (![self.buttonStateCache[button] isEqual:newButtonStates[button]]) { | ||
[skin pushLuaRef:speedEditorRefTable ref:self.buttonCallbackRef]; | ||
[skin pushNSObject:self]; | ||
lua_pushinteger(skin.L, button); | ||
lua_pushboolean(skin.L, ((NSNumber*)(newButtonStates[button])).boolValue); | ||
[skin protectedCallAndError:@"hs.streamdeck:buttonCallback" nargs:3 nresults:0]; | ||
self.buttonStateCache[button] = newButtonStates[button]; | ||
} | ||
} | ||
|
||
_lua_stackguard_exit(skin.L); | ||
} | ||
|
||
- (BOOL)setBrightness:(int)brightness { | ||
NSException *exception = [NSException exceptionWithName:@"HSSpeedEditorDeviceUnimplemented" | ||
reason:@"setBrightness method not implemented" | ||
userInfo:nil]; | ||
[exception raise]; | ||
return NO; | ||
} | ||
|
||
- (void)reset { | ||
NSException *exception = [NSException exceptionWithName:@"HSSpeedEditorDeviceUnimplemented" | ||
reason:@"reset method not implemented" | ||
userInfo:nil]; | ||
[exception raise]; | ||
} | ||
|
||
- (NSString*)getSerialNumber { | ||
#pragma clang diagnostic push | ||
#pragma clang diagnostic ignored "-Wdirect-ivar-access" | ||
|
||
if (!serialNumberCache) { | ||
// This shouldn't be necessary, since we cache the serial number when the device is initialised, but just in case | ||
serialNumberCache = [self cacheSerialNumber]; | ||
} | ||
|
||
return serialNumberCache; | ||
#pragma clang diagnostic pop | ||
} | ||
|
||
- (NSString *)cacheSerialNumber { | ||
NSException *exception = [NSException exceptionWithName:@"HSSpeedEditorDeviceUnimplemented" | ||
reason:@"cacheSerialNumber method not implemented" | ||
userInfo:nil]; | ||
[exception raise]; | ||
return nil; | ||
} | ||
|
||
- (NSString*)firmwareVersion { | ||
NSException *exception = [NSException exceptionWithName:@"HSSpeedEditorDeviceUnimplemented" | ||
reason:@"firmwareVersion method not implemented" | ||
userInfo:nil]; | ||
[exception raise]; | ||
return nil; | ||
} | ||
|
||
- (int)getKeyCount { | ||
return self.keyColumns * self.keyRows; | ||
} | ||
|
||
- (void)clearImage:(int)button { | ||
[self setColor:[NSColor blackColor] forButton:button]; | ||
} | ||
|
||
- (void)setColor:(NSColor *)color forButton:(int)button { | ||
if (!self.isValid) { | ||
return; | ||
} | ||
|
||
NSImage *image = [[NSImage alloc] initWithSize:NSMakeSize(self.imageWidth, self.imageHeight)]; | ||
[image lockFocus]; | ||
[color drawSwatchInRect:NSMakeRect(0, 0, self.imageWidth, self.imageHeight)]; | ||
[image unlockFocus]; | ||
//[self setImage:image forButton:button]; | ||
} | ||
|
||
- (void)deviceWriteImage:(NSData *)data button:(int)button { | ||
NSException *exception = [NSException exceptionWithName:@"HSSpeedEditorDeviceUnimplemented" | ||
reason:@"deviceWriteImage method not implemented" | ||
userInfo:nil]; | ||
[exception raise]; | ||
} | ||
@end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
// | ||
// HSSpeedEditorManager.h | ||
// Hammerspoon | ||
// | ||
// Created by Chris Jones on 06/09/2017. | ||
// Copyright © 2017 Hammerspoon. All rights reserved. | ||
// | ||
|
||
@import Foundation; | ||
@import IOKit; | ||
@import IOKit.hid; | ||
|
||
@import LuaSkin; | ||
|
||
//#import "HSSpeedEditorDevice.h" | ||
#import "speededitor.h" | ||
|
||
@interface HSSpeedEditorManager : NSObject | ||
@property (nonatomic, strong) id ioHIDManager; | ||
@property (nonatomic, strong) NSMutableArray *devices; | ||
@property (nonatomic) int discoveryCallbackRef; | ||
|
||
- (id)init; | ||
- (void)doGC; | ||
- (BOOL)startHIDManager; | ||
- (BOOL)stopHIDManager; | ||
//- (HSSpeedEditorDevice*)deviceDidConnect:(IOHIDDeviceRef)device; | ||
- (void)deviceDidDisconnect:(IOHIDDeviceRef)device; | ||
|
||
@end |
Oops, something went wrong.