mirror of
https://github.com/keymanapp/keyman.git
synced 2026-09-29 11:07:41 +00:00
800 lines
41 KiB
Objective-C
800 lines
41 KiB
Objective-C
//
|
|
// OSKView.m
|
|
// KeymanEngine4Mac
|
|
//
|
|
// Created by Serkan Kurt on 7/11/2014.
|
|
// Copyright (c) 2017 SIL International. All rights reserved.
|
|
//
|
|
|
|
#import "OSKView.h"
|
|
#import "OSKKey.h"
|
|
#import "KeyView.h"
|
|
#import "MacVKCodes.h"
|
|
#import "WindowsVKCodes.h"
|
|
#import "NKey.h"
|
|
#import "CoreHelper.h"
|
|
|
|
#include <Carbon/Carbon.h>
|
|
#import "KMELogs.h"
|
|
|
|
const int64_t OSK_EVENT_FLAG = 0x8000000000000000;
|
|
const int64_t OSK_EVENT_MODIFIER_MASK = 0x00000000FFFFFFFF;
|
|
|
|
@interface OSKView()
|
|
@property (nonatomic, strong) NSArray *oskLayout;
|
|
@property (nonatomic, strong) NSArray *oskDefaultNKeys;
|
|
@property (nonatomic, assign) BOOL physicalShiftState;
|
|
@property (nonatomic, assign) BOOL oskShiftState;
|
|
@property (nonatomic, assign) BOOL physicalOptionState;
|
|
@property (nonatomic, assign) BOOL oskOptionState;
|
|
@property (nonatomic, assign) BOOL physicalControlState;
|
|
@property (nonatomic, assign) BOOL oskControlState;
|
|
@end
|
|
|
|
@implementation OSKView
|
|
@synthesize tag;
|
|
|
|
/**
|
|
* Check the kCGEventSourceUserData field of the event and determine whether the event was
|
|
* generated by the OSK.
|
|
*/
|
|
+ (BOOL)isOskKeyDownEvent:(CGEventRef)event {
|
|
// check to see if this event was generated by the OSK
|
|
int64_t eventUserData = CGEventGetIntegerValueField(event, kCGEventSourceUserData);
|
|
return ((eventUserData & OSK_EVENT_FLAG) == OSK_EVENT_FLAG);
|
|
}
|
|
|
|
/**
|
|
* If the event was generated by the OSK, then return the modifier flags stored in the kCGEventSourceUserData
|
|
* field at the time the event was generated
|
|
*/
|
|
+ (NSEventModifierFlags)extractModifierFlagsFromOskEvent:(CGEventRef)event {
|
|
NSEventModifierFlags modifierFlags = 0;
|
|
int64_t eventUserData = CGEventGetIntegerValueField(event, kCGEventSourceUserData);
|
|
if ([OSKView isOskKeyDownEvent:event]) {
|
|
modifierFlags = (NSEventModifierFlags) eventUserData & OSK_EVENT_MODIFIER_MASK;
|
|
}
|
|
return modifierFlags;
|
|
}
|
|
|
|
- (id)initWithFrame:(NSRect)frame {
|
|
os_log_debug([KMELogs oskLog], "OSKView initWithFrame: %{public}@", NSStringFromRect(frame));
|
|
self = [super initWithFrame:frame];
|
|
if (self) {
|
|
// Custom initialization
|
|
[self initOSKKeys];
|
|
}
|
|
|
|
return self;
|
|
}
|
|
|
|
- (NSString *)description {
|
|
NSString *format = @"<shiftState:%d oskShiftState:%d optionState:%d oskOptionState:%d controlState:%d oskControlState:%d>";
|
|
NSString *str = [NSString stringWithFormat:format, _physicalShiftState, _oskShiftState, _physicalOptionState, _oskOptionState, _physicalControlState, _oskControlState];
|
|
return str;
|
|
}
|
|
|
|
- (void)drawRect:(NSRect)rect {
|
|
os_log_debug([KMELogs oskLog], "OSKView drawRect: %{public}@", NSStringFromRect(rect));
|
|
|
|
CGContextRef context = (CGContextRef)[[NSGraphicsContext currentContext] CGContext];
|
|
CGContextSetLineJoin(context, kCGLineJoinRound);
|
|
CGContextSetLineWidth(context, 1.0);
|
|
CGColorRef cgClearColor = CGColorGetConstantColor(kCGColorClear);
|
|
CGContextSetStrokeColorWithColor(context, cgClearColor);
|
|
CGContextSetFillColorWithColor(context, cgClearColor);
|
|
|
|
CGContextBeginPath(context);
|
|
CGContextAddRect(context, CGRectMake(1.0, 1.0, rect.size.width-1.0, rect.size.height-1.0));
|
|
CGContextDrawPath(context, kCGPathStroke);
|
|
|
|
CGContextBeginPath(context);
|
|
CGContextAddRect(context, CGRectMake(1.0, 1.0, rect.size.width-1.0, rect.size.height-1.0));
|
|
CGContextClip(context);
|
|
|
|
//TODO: gradient from clear to clear -- what does this do?
|
|
NSColor *bgColor = [NSColor clearColor]; //[NSColor colorWithWhite:0.7 alpha:1.0];
|
|
NSColor *bgColor2 = [NSColor clearColor]; //[NSColor colorWithWhite:0.5 alpha:1.0];
|
|
|
|
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
|
|
NSArray *gradientColors = [NSArray arrayWithObjects:(id)bgColor.CGColor, bgColor2.CGColor, nil];
|
|
CGFloat gradientLocations[] = {0, 1};
|
|
CGGradientRef gradient = CGGradientCreateWithColors(colorSpace, (__bridge CFArrayRef)gradientColors, gradientLocations);
|
|
CGPoint startPoint = CGPointMake(CGRectGetMidX(rect), CGRectGetMinY(rect));
|
|
CGPoint endPoint = CGPointMake(CGRectGetMidX(rect), CGRectGetMaxY(rect));
|
|
CGContextDrawLinearGradient(context, gradient, startPoint, endPoint, 0);
|
|
CGGradientRelease(gradient);
|
|
CGColorSpaceRelease(colorSpace);
|
|
}
|
|
|
|
- (BOOL)isFlipped {
|
|
return YES;
|
|
}
|
|
|
|
// Returns TRUE for ISO keyboards or when the .kvk file requests the 102nd key
|
|
// to right of the Left Shift key.
|
|
- (BOOL)use102ndKey {
|
|
/*
|
|
Note: LMGetKbdType() does not appear to work reliably; it seems to always
|
|
return ANSI even when there is a European keyboard plugged in to my Macbook.
|
|
We'll use it anyway in case better results are found for Macs with native
|
|
ISO keyboards.
|
|
*/
|
|
UInt8 kbdType = LMGetKbdType();
|
|
PhysicalKeyboardLayoutType kbdLayoutType = KBGetLayoutType(kbdType);
|
|
switch(kbdLayoutType) {
|
|
case kKeyboardANSI: return _kvk != nil && _kvk.flags & KVKH_102;
|
|
case kKeyboardJIS:
|
|
case kKeyboardISO: return YES;
|
|
}
|
|
// We don't know what the keyboard is, so let's err on the side of
|
|
// more keys, not fewer
|
|
return YES;
|
|
}
|
|
|
|
- (void)setKvk:(KVKFile *)kvk {
|
|
os_log_debug([KMELogs oskLog], "OSKView setKvk, forces keyboard to re-layout");
|
|
_kvk = kvk;
|
|
|
|
// Force the keyboard to re-layout
|
|
_oskLayout = nil;
|
|
_oskDefaultNKeys = nil;
|
|
|
|
[self updateKeyLabelsForCurrentLayer];
|
|
}
|
|
|
|
- (void)initOSKKeys {
|
|
os_log_debug([KMELogs oskLog], "OSKView initOSKKeys");
|
|
CGFloat viewWidth = self.frame.size.width;
|
|
CGFloat viewHeight = self.frame.size.height;
|
|
CGFloat margin = 2.0;
|
|
CGFloat keyHeight = (viewHeight - margin*2)/self.oskLayout.count;
|
|
CGFloat keyWidth = (viewWidth - margin*2)/14.5;
|
|
CGFloat px;
|
|
CGFloat py = margin;
|
|
for (NSArray *row in self.oskLayout) {
|
|
px = margin;
|
|
NSUInteger len = [row count];
|
|
for (int i = 0; i < len; i++) {
|
|
OSKKey *key = (OSKKey *)[row objectAtIndex:i];
|
|
CGFloat width = keyWidth * key.scale;
|
|
if ((i+1) == len && (px + width + margin) < viewWidth)
|
|
width += (viewWidth - (px + width + margin));
|
|
NSRect rect = NSInsetRect(NSMakeRect(px, py, width, keyHeight), 2, 2);
|
|
KeyView *keyView = [[KeyView alloc] initWithFrame:rect];;
|
|
[keyView setKey:key];
|
|
[keyView setTarget:self];
|
|
if (self.oskShiftState && (keyView.key.keyCode == MVK_LEFT_SHIFT || keyView.key.keyCode == MVK_RIGHT_SHIFT))
|
|
[keyView setKeyPressed:YES];
|
|
else if (self.oskOptionState && (keyView.key.keyCode == MVK_LEFT_ALT || keyView.key.keyCode == MVK_RIGHT_ALT))
|
|
[keyView setKeyPressed:YES];
|
|
[self addSubview:keyView];
|
|
px += width;
|
|
}
|
|
py += keyHeight;
|
|
}
|
|
|
|
[self updateKeyLabelsForCurrentLayer];
|
|
}
|
|
|
|
- (NSArray *)oskLayout {
|
|
if (_oskLayout == nil) {
|
|
os_log_debug([KMELogs oskLog], "oskLayout -> creating new arrays of OSKKey objects");
|
|
NSArray *row1 = [NSArray arrayWithObjects:
|
|
[[OSKKey alloc] initWithKeyCode:MVK_GRAVE caption:@"`" scale:1.0],
|
|
[[OSKKey alloc] initWithKeyCode:MVK_1 caption:@"1" scale:1.0],
|
|
[[OSKKey alloc] initWithKeyCode:MVK_2 caption:@"2" scale:1.0],
|
|
[[OSKKey alloc] initWithKeyCode:MVK_3 caption:@"3" scale:1.0],
|
|
[[OSKKey alloc] initWithKeyCode:MVK_4 caption:@"4" scale:1.0],
|
|
[[OSKKey alloc] initWithKeyCode:MVK_5 caption:@"5" scale:1.0],
|
|
[[OSKKey alloc] initWithKeyCode:MVK_6 caption:@"6" scale:1.0],
|
|
[[OSKKey alloc] initWithKeyCode:MVK_7 caption:@"7" scale:1.0],
|
|
[[OSKKey alloc] initWithKeyCode:MVK_8 caption:@"8" scale:1.0],
|
|
[[OSKKey alloc] initWithKeyCode:MVK_9 caption:@"9" scale:1.0],
|
|
[[OSKKey alloc] initWithKeyCode:MVK_0 caption:@"0" scale:1.0],
|
|
[[OSKKey alloc] initWithKeyCode:MVK_MINUS caption:@"-" scale:1.0],
|
|
[[OSKKey alloc] initWithKeyCode:MVK_EQUAL caption:@"=" scale:1.0],
|
|
[[OSKKey alloc] initWithKeyCode:MVK_BACKSPACE caption:@"⬅︎" scale:1.5], nil];
|
|
|
|
NSArray *row2 = [NSArray arrayWithObjects:
|
|
[[OSKKey alloc] initWithKeyCode:MVK_TAB caption:@"↹" scale:1.5],
|
|
[[OSKKey alloc] initWithKeyCode:MVK_Q caption:@"Q" scale:1.0],
|
|
[[OSKKey alloc] initWithKeyCode:MVK_W caption:@"W" scale:1.0],
|
|
[[OSKKey alloc] initWithKeyCode:MVK_E caption:@"E" scale:1.0],
|
|
[[OSKKey alloc] initWithKeyCode:MVK_R caption:@"R" scale:1.0],
|
|
[[OSKKey alloc] initWithKeyCode:MVK_T caption:@"T" scale:1.0],
|
|
[[OSKKey alloc] initWithKeyCode:MVK_Y caption:@"Y" scale:1.0],
|
|
[[OSKKey alloc] initWithKeyCode:MVK_U caption:@"U" scale:1.0],
|
|
[[OSKKey alloc] initWithKeyCode:MVK_I caption:@"I" scale:1.0],
|
|
[[OSKKey alloc] initWithKeyCode:MVK_O caption:@"O" scale:1.0],
|
|
[[OSKKey alloc] initWithKeyCode:MVK_P caption:@"P" scale:1.0],
|
|
[[OSKKey alloc] initWithKeyCode:MVK_LEFT_BRACKET caption:@"[" scale:1.0],
|
|
[[OSKKey alloc] initWithKeyCode:MVK_RIGHT_BRACKET caption:@"]" scale:1.0],
|
|
[[OSKKey alloc] initWithKeyCode:MVK_BACKSLASH caption:@"\\" scale:1.0], nil];
|
|
|
|
NSArray *row3 = [NSArray arrayWithObjects:
|
|
[[OSKKey alloc] initWithKeyCode:MVK_CAPS_LOCK caption:@"Caps Lock" scale:1.75],
|
|
[[OSKKey alloc] initWithKeyCode:MVK_A caption:@"A" scale:1.0],
|
|
[[OSKKey alloc] initWithKeyCode:MVK_S caption:@"S" scale:1.0],
|
|
[[OSKKey alloc] initWithKeyCode:MVK_D caption:@"D" scale:1.0],
|
|
[[OSKKey alloc] initWithKeyCode:MVK_F caption:@"F" scale:1.0],
|
|
[[OSKKey alloc] initWithKeyCode:MVK_G caption:@"G" scale:1.0],
|
|
[[OSKKey alloc] initWithKeyCode:MVK_H caption:@"H" scale:1.0],
|
|
[[OSKKey alloc] initWithKeyCode:MVK_J caption:@"J" scale:1.0],
|
|
[[OSKKey alloc] initWithKeyCode:MVK_K caption:@"K" scale:1.0],
|
|
[[OSKKey alloc] initWithKeyCode:MVK_L caption:@"L" scale:1.0],
|
|
[[OSKKey alloc] initWithKeyCode:MVK_SEMICOLON caption:@";" scale:1.0],
|
|
[[OSKKey alloc] initWithKeyCode:MVK_QUOTE caption:@"'" scale:1.0],
|
|
[[OSKKey alloc] initWithKeyCode:MVK_ENTER caption:@"↵" scale:1.75], nil];
|
|
|
|
NSArray *row4a = [self use102ndKey] ?
|
|
[NSArray arrayWithObjects:
|
|
[[OSKKey alloc] initWithKeyCode:MVK_LEFT_SHIFT caption:@"⇧" scale:1.25],
|
|
[[OSKKey alloc] initWithKeyCode:MVK_OEM102 caption:@"\\" scale:1.0], nil] :
|
|
[NSArray arrayWithObjects:
|
|
[[OSKKey alloc] initWithKeyCode:MVK_LEFT_SHIFT caption:@"⇧" scale:2.25], nil];
|
|
|
|
NSArray *row4b = [NSArray arrayWithObjects:
|
|
[[OSKKey alloc] initWithKeyCode:MVK_Z caption:@"Z" scale:1.0],
|
|
[[OSKKey alloc] initWithKeyCode:MVK_X caption:@"X" scale:1.0],
|
|
[[OSKKey alloc] initWithKeyCode:MVK_C caption:@"C" scale:1.0],
|
|
[[OSKKey alloc] initWithKeyCode:MVK_V caption:@"V" scale:1.0],
|
|
[[OSKKey alloc] initWithKeyCode:MVK_B caption:@"B" scale:1.0],
|
|
[[OSKKey alloc] initWithKeyCode:MVK_N caption:@"N" scale:1.0],
|
|
[[OSKKey alloc] initWithKeyCode:MVK_M caption:@"M" scale:1.0],
|
|
[[OSKKey alloc] initWithKeyCode:MVK_COMMA caption:@"," scale:1.0],
|
|
[[OSKKey alloc] initWithKeyCode:MVK_PERIOD caption:@"." scale:1.0],
|
|
[[OSKKey alloc] initWithKeyCode:MVK_SLASH caption:@"/" scale:1.0],
|
|
[[OSKKey alloc] initWithKeyCode:MVK_RIGHT_SHIFT caption:@"⇧" scale:2.25], nil];
|
|
|
|
NSArray *row4 = [row4a arrayByAddingObjectsFromArray:row4b];
|
|
|
|
NSArray *row5 = [NSArray arrayWithObjects:
|
|
[[OSKKey alloc] initWithKeyCode:MVK_LEFT_CTRL caption:@"Ctrl" scale:1.75],
|
|
[[OSKKey alloc] initWithKeyCode:MVK_LEFT_ALT caption:@"Alt" scale:1.5],
|
|
[[OSKKey alloc] initWithKeyCode:MVK_SPACE caption:@"" scale:8.0],
|
|
[[OSKKey alloc] initWithKeyCode:MVK_RIGHT_ALT caption:@"Alt" scale:1.5],
|
|
[[OSKKey alloc] initWithKeyCode:MVK_RIGHT_CTRL caption:@"Ctrl" scale:1.75], nil];
|
|
|
|
_oskLayout = [NSArray arrayWithObjects:row1, row2, row3, row4, row5, nil];
|
|
}
|
|
|
|
return _oskLayout;
|
|
}
|
|
|
|
- (NSArray *)oskDefaultNKeys {
|
|
if (_oskDefaultNKeys == nil) {
|
|
os_log_debug([KMELogs oskLog], "oskDefaultNKeys -> creating new arrays of default number OSKKey objects");
|
|
NSMutableArray *defNKeys = [[NSMutableArray alloc] initWithCapacity:0];
|
|
|
|
// row 1
|
|
NKey *nkey1 = [[NKey alloc] init]; nkey1.typeFlags = 2; nkey1.modifierFlags = 0; nkey1.keyCode = VK_GRAVE; nkey1.text = @"`"; nkey1.bitmap = nil;
|
|
NKey *nkey2 = [[NKey alloc] init]; nkey2.typeFlags = 2; nkey2.modifierFlags = 1; nkey2.keyCode = VK_GRAVE; nkey2.text = @"~"; nkey2.bitmap = nil;
|
|
[defNKeys addObjectsFromArray:@[nkey1, nkey2]];
|
|
nkey1 = [[NKey alloc] init]; nkey1.typeFlags = 2; nkey1.modifierFlags = 0; nkey1.keyCode = VK_KEY_1; nkey1.text = @"1"; nkey1.bitmap = nil;
|
|
nkey2 = [[NKey alloc] init]; nkey2.typeFlags = 2; nkey2.modifierFlags = 1; nkey2.keyCode = VK_KEY_1; nkey2.text = @"!"; nkey2.bitmap = nil;
|
|
[defNKeys addObjectsFromArray:@[nkey1, nkey2]];
|
|
nkey1 = [[NKey alloc] init]; nkey1.typeFlags = 2; nkey1.modifierFlags = 0; nkey1.keyCode = VK_KEY_2; nkey1.text = @"2"; nkey1.bitmap = nil;
|
|
nkey2 = [[NKey alloc] init]; nkey2.typeFlags = 2; nkey2.modifierFlags = 1; nkey2.keyCode = VK_KEY_2; nkey2.text = @"@"; nkey2.bitmap = nil;
|
|
[defNKeys addObjectsFromArray:@[nkey1, nkey2]];
|
|
nkey1 = [[NKey alloc] init]; nkey1.typeFlags = 2; nkey1.modifierFlags = 0; nkey1.keyCode = VK_KEY_3; nkey1.text = @"3"; nkey1.bitmap = nil;
|
|
nkey2 = [[NKey alloc] init]; nkey2.typeFlags = 2; nkey2.modifierFlags = 1; nkey2.keyCode = VK_KEY_3; nkey2.text = @"#"; nkey2.bitmap = nil;
|
|
[defNKeys addObjectsFromArray:@[nkey1, nkey2]];
|
|
nkey1 = [[NKey alloc] init]; nkey1.typeFlags = 2; nkey1.modifierFlags = 0; nkey1.keyCode = VK_KEY_4; nkey1.text = @"4"; nkey1.bitmap = nil;
|
|
nkey2 = [[NKey alloc] init]; nkey2.typeFlags = 2; nkey2.modifierFlags = 1; nkey2.keyCode = VK_KEY_4; nkey2.text = @"$"; nkey2.bitmap = nil;
|
|
[defNKeys addObjectsFromArray:@[nkey1, nkey2]];
|
|
nkey1 = [[NKey alloc] init]; nkey1.typeFlags = 2; nkey1.modifierFlags = 0; nkey1.keyCode = VK_KEY_5; nkey1.text = @"5"; nkey1.bitmap = nil;
|
|
nkey2 = [[NKey alloc] init]; nkey2.typeFlags = 2; nkey2.modifierFlags = 1; nkey2.keyCode = VK_KEY_5; nkey2.text = @"%"; nkey2.bitmap = nil;
|
|
[defNKeys addObjectsFromArray:@[nkey1, nkey2]];
|
|
nkey1 = [[NKey alloc] init]; nkey1.typeFlags = 2; nkey1.modifierFlags = 0; nkey1.keyCode = VK_KEY_6; nkey1.text = @"6"; nkey1.bitmap = nil;
|
|
nkey2 = [[NKey alloc] init]; nkey2.typeFlags = 2; nkey2.modifierFlags = 1; nkey2.keyCode = VK_KEY_6; nkey2.text = @"^"; nkey2.bitmap = nil;
|
|
[defNKeys addObjectsFromArray:@[nkey1, nkey2]];
|
|
nkey1 = [[NKey alloc] init]; nkey1.typeFlags = 2; nkey1.modifierFlags = 0; nkey1.keyCode = VK_KEY_7; nkey1.text = @"7"; nkey1.bitmap = nil;
|
|
nkey2 = [[NKey alloc] init]; nkey2.typeFlags = 2; nkey2.modifierFlags = 1; nkey2.keyCode = VK_KEY_7; nkey2.text = @"&"; nkey2.bitmap = nil;
|
|
[defNKeys addObjectsFromArray:@[nkey1, nkey2]];
|
|
nkey1 = [[NKey alloc] init]; nkey1.typeFlags = 2; nkey1.modifierFlags = 0; nkey1.keyCode = VK_KEY_8; nkey1.text = @"8"; nkey1.bitmap = nil;
|
|
nkey2 = [[NKey alloc] init]; nkey2.typeFlags = 2; nkey2.modifierFlags = 1; nkey2.keyCode = VK_KEY_8; nkey2.text = @"*"; nkey2.bitmap = nil;
|
|
[defNKeys addObjectsFromArray:@[nkey1, nkey2]];
|
|
nkey1 = [[NKey alloc] init]; nkey1.typeFlags = 2; nkey1.modifierFlags = 0; nkey1.keyCode = VK_KEY_9; nkey1.text = @"9"; nkey1.bitmap = nil;
|
|
nkey2 = [[NKey alloc] init]; nkey2.typeFlags = 2; nkey2.modifierFlags = 1; nkey2.keyCode = VK_KEY_9; nkey2.text = @"("; nkey2.bitmap = nil;
|
|
[defNKeys addObjectsFromArray:@[nkey1, nkey2]];
|
|
nkey1 = [[NKey alloc] init]; nkey1.typeFlags = 2; nkey1.modifierFlags = 0; nkey1.keyCode = VK_KEY_0; nkey1.text = @"0"; nkey1.bitmap = nil;
|
|
nkey2 = [[NKey alloc] init]; nkey2.typeFlags = 2; nkey2.modifierFlags = 1; nkey2.keyCode = VK_KEY_0; nkey2.text = @")"; nkey2.bitmap = nil;
|
|
[defNKeys addObjectsFromArray:@[nkey1, nkey2]];
|
|
nkey1 = [[NKey alloc] init]; nkey1.typeFlags = 2; nkey1.modifierFlags = 0; nkey1.keyCode = VK_MINUS; nkey1.text = @"-"; nkey1.bitmap = nil;
|
|
nkey2 = [[NKey alloc] init]; nkey2.typeFlags = 2; nkey2.modifierFlags = 1; nkey2.keyCode = VK_MINUS; nkey2.text = @"_"; nkey2.bitmap = nil;
|
|
[defNKeys addObjectsFromArray:@[nkey1, nkey2]];
|
|
nkey1 = [[NKey alloc] init]; nkey1.typeFlags = 2; nkey1.modifierFlags = 0; nkey1.keyCode = VK_EQUAL; nkey1.text = @"="; nkey1.bitmap = nil;
|
|
nkey2 = [[NKey alloc] init]; nkey2.typeFlags = 2; nkey2.modifierFlags = 1; nkey2.keyCode = VK_EQUAL; nkey2.text = @"+"; nkey2.bitmap = nil;
|
|
[defNKeys addObjectsFromArray:@[nkey1, nkey2]];
|
|
|
|
// row 2
|
|
nkey1 = [[NKey alloc] init]; nkey1.typeFlags = 2; nkey1.modifierFlags = 0; nkey1.keyCode = VK_KEY_Q; nkey1.text = @"q"; nkey1.bitmap = nil;
|
|
nkey2 = [[NKey alloc] init]; nkey2.typeFlags = 2; nkey2.modifierFlags = 1; nkey2.keyCode = VK_KEY_Q; nkey2.text = @"Q"; nkey2.bitmap = nil;
|
|
[defNKeys addObjectsFromArray:@[nkey1, nkey2]];
|
|
nkey1 = [[NKey alloc] init]; nkey1.typeFlags = 2; nkey1.modifierFlags = 0; nkey1.keyCode = VK_KEY_W; nkey1.text = @"w"; nkey1.bitmap = nil;
|
|
nkey2 = [[NKey alloc] init]; nkey2.typeFlags = 2; nkey2.modifierFlags = 1; nkey2.keyCode = VK_KEY_W; nkey2.text = @"W"; nkey2.bitmap = nil;
|
|
[defNKeys addObjectsFromArray:@[nkey1, nkey2]];
|
|
nkey1 = [[NKey alloc] init]; nkey1.typeFlags = 2; nkey1.modifierFlags = 0; nkey1.keyCode = VK_KEY_E; nkey1.text = @"e"; nkey1.bitmap = nil;
|
|
nkey2 = [[NKey alloc] init]; nkey2.typeFlags = 2; nkey2.modifierFlags = 1; nkey2.keyCode = VK_KEY_E; nkey2.text = @"E"; nkey2.bitmap = nil;
|
|
[defNKeys addObjectsFromArray:@[nkey1, nkey2]];
|
|
nkey1 = [[NKey alloc] init]; nkey1.typeFlags = 2; nkey1.modifierFlags = 0; nkey1.keyCode = VK_KEY_R; nkey1.text = @"r"; nkey1.bitmap = nil;
|
|
nkey2 = [[NKey alloc] init]; nkey2.typeFlags = 2; nkey2.modifierFlags = 1; nkey2.keyCode = VK_KEY_R; nkey2.text = @"R"; nkey2.bitmap = nil;
|
|
[defNKeys addObjectsFromArray:@[nkey1, nkey2]];
|
|
nkey1 = [[NKey alloc] init]; nkey1.typeFlags = 2; nkey1.modifierFlags = 0; nkey1.keyCode = VK_KEY_T; nkey1.text = @"t"; nkey1.bitmap = nil;
|
|
nkey2 = [[NKey alloc] init]; nkey2.typeFlags = 2; nkey2.modifierFlags = 1; nkey2.keyCode = VK_KEY_T; nkey2.text = @"T"; nkey2.bitmap = nil;
|
|
[defNKeys addObjectsFromArray:@[nkey1, nkey2]];
|
|
nkey1 = [[NKey alloc] init]; nkey1.typeFlags = 2; nkey1.modifierFlags = 0; nkey1.keyCode = VK_KEY_Y; nkey1.text = @"y"; nkey1.bitmap = nil;
|
|
nkey2 = [[NKey alloc] init]; nkey2.typeFlags = 2; nkey2.modifierFlags = 1; nkey2.keyCode = VK_KEY_Y; nkey2.text = @"Y"; nkey2.bitmap = nil;
|
|
[defNKeys addObjectsFromArray:@[nkey1, nkey2]];
|
|
nkey1 = [[NKey alloc] init]; nkey1.typeFlags = 2; nkey1.modifierFlags = 0; nkey1.keyCode = VK_KEY_U; nkey1.text = @"u"; nkey1.bitmap = nil;
|
|
nkey2 = [[NKey alloc] init]; nkey2.typeFlags = 2; nkey2.modifierFlags = 1; nkey2.keyCode = VK_KEY_U; nkey2.text = @"U"; nkey2.bitmap = nil;
|
|
[defNKeys addObjectsFromArray:@[nkey1, nkey2]];
|
|
nkey1 = [[NKey alloc] init]; nkey1.typeFlags = 2; nkey1.modifierFlags = 0; nkey1.keyCode = VK_KEY_I; nkey1.text = @"i"; nkey1.bitmap = nil;
|
|
nkey2 = [[NKey alloc] init]; nkey2.typeFlags = 2; nkey2.modifierFlags = 1; nkey2.keyCode = VK_KEY_I; nkey2.text = @"I"; nkey2.bitmap = nil;
|
|
[defNKeys addObjectsFromArray:@[nkey1, nkey2]];
|
|
nkey1 = [[NKey alloc] init]; nkey1.typeFlags = 2; nkey1.modifierFlags = 0; nkey1.keyCode = VK_KEY_O; nkey1.text = @"o"; nkey1.bitmap = nil;
|
|
nkey2 = [[NKey alloc] init]; nkey2.typeFlags = 2; nkey2.modifierFlags = 1; nkey2.keyCode = VK_KEY_O; nkey2.text = @"O"; nkey2.bitmap = nil;
|
|
[defNKeys addObjectsFromArray:@[nkey1, nkey2]];
|
|
nkey1 = [[NKey alloc] init]; nkey1.typeFlags = 2; nkey1.modifierFlags = 0; nkey1.keyCode = VK_KEY_P; nkey1.text = @"p"; nkey1.bitmap = nil;
|
|
nkey2 = [[NKey alloc] init]; nkey2.typeFlags = 2; nkey2.modifierFlags = 1; nkey2.keyCode = VK_KEY_P; nkey2.text = @"P"; nkey2.bitmap = nil;
|
|
[defNKeys addObjectsFromArray:@[nkey1, nkey2]];
|
|
nkey1 = [[NKey alloc] init]; nkey1.typeFlags = 2; nkey1.modifierFlags = 0; nkey1.keyCode = VK_LEFT_BRACKET; nkey1.text = @"["; nkey1.bitmap = nil;
|
|
nkey2 = [[NKey alloc] init]; nkey2.typeFlags = 2; nkey2.modifierFlags = 1; nkey2.keyCode = VK_LEFT_BRACKET; nkey2.text = @"{"; nkey2.bitmap = nil;
|
|
[defNKeys addObjectsFromArray:@[nkey1, nkey2]];
|
|
nkey1 = [[NKey alloc] init]; nkey1.typeFlags = 2; nkey1.modifierFlags = 0; nkey1.keyCode = VK_RIGHT_BRACKET; nkey1.text = @"]"; nkey1.bitmap = nil;
|
|
nkey2 = [[NKey alloc] init]; nkey2.typeFlags = 2; nkey2.modifierFlags = 1; nkey2.keyCode = VK_RIGHT_BRACKET; nkey2.text = @"}"; nkey2.bitmap = nil;
|
|
[defNKeys addObjectsFromArray:@[nkey1, nkey2]];
|
|
nkey1 = [[NKey alloc] init]; nkey1.typeFlags = 2; nkey1.modifierFlags = 0; nkey1.keyCode = VK_BACKSLASH; nkey1.text = @"\\"; nkey1.bitmap = nil;
|
|
nkey2 = [[NKey alloc] init]; nkey2.typeFlags = 2; nkey2.modifierFlags = 1; nkey2.keyCode = VK_BACKSLASH; nkey2.text = @"|"; nkey2.bitmap = nil;
|
|
[defNKeys addObjectsFromArray:@[nkey1, nkey2]];
|
|
|
|
// row 3
|
|
nkey1 = [[NKey alloc] init]; nkey1.typeFlags = 2; nkey1.modifierFlags = 0; nkey1.keyCode = VK_KEY_A; nkey1.text = @"a"; nkey1.bitmap = nil;
|
|
nkey2 = [[NKey alloc] init]; nkey2.typeFlags = 2; nkey2.modifierFlags = 1; nkey2.keyCode = VK_KEY_A; nkey2.text = @"A"; nkey2.bitmap = nil;
|
|
[defNKeys addObjectsFromArray:@[nkey1, nkey2]];
|
|
nkey1 = [[NKey alloc] init]; nkey1.typeFlags = 2; nkey1.modifierFlags = 0; nkey1.keyCode = VK_KEY_S; nkey1.text = @"s"; nkey1.bitmap = nil;
|
|
nkey2 = [[NKey alloc] init]; nkey2.typeFlags = 2; nkey2.modifierFlags = 1; nkey2.keyCode = VK_KEY_S; nkey2.text = @"S"; nkey2.bitmap = nil;
|
|
[defNKeys addObjectsFromArray:@[nkey1, nkey2]];
|
|
nkey1 = [[NKey alloc] init]; nkey1.typeFlags = 2; nkey1.modifierFlags = 0; nkey1.keyCode = VK_KEY_D; nkey1.text = @"d"; nkey1.bitmap = nil;
|
|
nkey2 = [[NKey alloc] init]; nkey2.typeFlags = 2; nkey2.modifierFlags = 1; nkey2.keyCode = VK_KEY_D; nkey2.text = @"D"; nkey2.bitmap = nil;
|
|
[defNKeys addObjectsFromArray:@[nkey1, nkey2]];
|
|
nkey1 = [[NKey alloc] init]; nkey1.typeFlags = 2; nkey1.modifierFlags = 0; nkey1.keyCode = VK_KEY_F; nkey1.text = @"f"; nkey1.bitmap = nil;
|
|
nkey2 = [[NKey alloc] init]; nkey2.typeFlags = 2; nkey2.modifierFlags = 1; nkey2.keyCode = VK_KEY_F; nkey2.text = @"F"; nkey2.bitmap = nil;
|
|
[defNKeys addObjectsFromArray:@[nkey1, nkey2]];
|
|
nkey1 = [[NKey alloc] init]; nkey1.typeFlags = 2; nkey1.modifierFlags = 0; nkey1.keyCode = VK_KEY_G; nkey1.text = @"g"; nkey1.bitmap = nil;
|
|
nkey2 = [[NKey alloc] init]; nkey2.typeFlags = 2; nkey2.modifierFlags = 1; nkey2.keyCode = VK_KEY_G; nkey2.text = @"G"; nkey2.bitmap = nil;
|
|
[defNKeys addObjectsFromArray:@[nkey1, nkey2]];
|
|
nkey1 = [[NKey alloc] init]; nkey1.typeFlags = 2; nkey1.modifierFlags = 0; nkey1.keyCode = VK_KEY_H; nkey1.text = @"h"; nkey1.bitmap = nil;
|
|
nkey2 = [[NKey alloc] init]; nkey2.typeFlags = 2; nkey2.modifierFlags = 1; nkey2.keyCode = VK_KEY_H; nkey2.text = @"H"; nkey2.bitmap = nil;
|
|
[defNKeys addObjectsFromArray:@[nkey1, nkey2]];
|
|
nkey1 = [[NKey alloc] init]; nkey1.typeFlags = 2; nkey1.modifierFlags = 0; nkey1.keyCode = VK_KEY_J; nkey1.text = @"j"; nkey1.bitmap = nil;
|
|
nkey2 = [[NKey alloc] init]; nkey2.typeFlags = 2; nkey2.modifierFlags = 1; nkey2.keyCode = VK_KEY_J; nkey2.text = @"J"; nkey2.bitmap = nil;
|
|
[defNKeys addObjectsFromArray:@[nkey1, nkey2]];
|
|
nkey1 = [[NKey alloc] init]; nkey1.typeFlags = 2; nkey1.modifierFlags = 0; nkey1.keyCode = VK_KEY_K; nkey1.text = @"k"; nkey1.bitmap = nil;
|
|
nkey2 = [[NKey alloc] init]; nkey2.typeFlags = 2; nkey2.modifierFlags = 1; nkey2.keyCode = VK_KEY_K; nkey2.text = @"K"; nkey2.bitmap = nil;
|
|
[defNKeys addObjectsFromArray:@[nkey1, nkey2]];
|
|
nkey1 = [[NKey alloc] init]; nkey1.typeFlags = 2; nkey1.modifierFlags = 0; nkey1.keyCode = VK_KEY_L; nkey1.text = @"l"; nkey1.bitmap = nil;
|
|
nkey2 = [[NKey alloc] init]; nkey2.typeFlags = 2; nkey2.modifierFlags = 1; nkey2.keyCode = VK_KEY_L; nkey2.text = @"L"; nkey2.bitmap = nil;
|
|
[defNKeys addObjectsFromArray:@[nkey1, nkey2]];
|
|
nkey1 = [[NKey alloc] init]; nkey1.typeFlags = 2; nkey1.modifierFlags = 0; nkey1.keyCode = VK_SEMICOLON; nkey1.text = @";"; nkey1.bitmap = nil;
|
|
nkey2 = [[NKey alloc] init]; nkey2.typeFlags = 2; nkey2.modifierFlags = 1; nkey2.keyCode = VK_SEMICOLON; nkey2.text = @":"; nkey2.bitmap = nil;
|
|
[defNKeys addObjectsFromArray:@[nkey1, nkey2]];
|
|
nkey1 = [[NKey alloc] init]; nkey1.typeFlags = 2; nkey1.modifierFlags = 0; nkey1.keyCode = VK_QUOTE; nkey1.text = @"'"; nkey1.bitmap = nil;
|
|
nkey2 = [[NKey alloc] init]; nkey2.typeFlags = 2; nkey2.modifierFlags = 1; nkey2.keyCode = VK_QUOTE; nkey2.text = @"\""; nkey2.bitmap = nil;
|
|
[defNKeys addObjectsFromArray:@[nkey1, nkey2]];
|
|
|
|
if([self use102ndKey]) {
|
|
nkey1 = [[NKey alloc] init]; nkey1.typeFlags = 2; nkey1.modifierFlags = 0; nkey1.keyCode = VK_OEM_102; nkey1.text = @"\\"; nkey1.bitmap = nil;
|
|
nkey2 = [[NKey alloc] init]; nkey2.typeFlags = 2; nkey2.modifierFlags = 1; nkey2.keyCode = VK_OEM_102; nkey2.text = @"|"; nkey2.bitmap = nil;
|
|
[defNKeys addObjectsFromArray:@[nkey1, nkey2]];
|
|
}
|
|
// row 4
|
|
nkey1 = [[NKey alloc] init]; nkey1.typeFlags = 2; nkey1.modifierFlags = 0; nkey1.keyCode = VK_KEY_Z; nkey1.text = @"z"; nkey1.bitmap = nil;
|
|
nkey2 = [[NKey alloc] init]; nkey2.typeFlags = 2; nkey2.modifierFlags = 1; nkey2.keyCode = VK_KEY_Z; nkey2.text = @"Z"; nkey2.bitmap = nil;
|
|
[defNKeys addObjectsFromArray:@[nkey1, nkey2]];
|
|
nkey1 = [[NKey alloc] init]; nkey1.typeFlags = 2; nkey1.modifierFlags = 0; nkey1.keyCode = VK_KEY_X; nkey1.text = @"x"; nkey1.bitmap = nil;
|
|
nkey2 = [[NKey alloc] init]; nkey2.typeFlags = 2; nkey2.modifierFlags = 1; nkey2.keyCode = VK_KEY_X; nkey2.text = @"X"; nkey2.bitmap = nil;
|
|
[defNKeys addObjectsFromArray:@[nkey1, nkey2]];
|
|
nkey1 = [[NKey alloc] init]; nkey1.typeFlags = 2; nkey1.modifierFlags = 0; nkey1.keyCode = VK_KEY_C; nkey1.text = @"c"; nkey1.bitmap = nil;
|
|
nkey2 = [[NKey alloc] init]; nkey2.typeFlags = 2; nkey2.modifierFlags = 1; nkey2.keyCode = VK_KEY_C; nkey2.text = @"C"; nkey2.bitmap = nil;
|
|
[defNKeys addObjectsFromArray:@[nkey1, nkey2]];
|
|
nkey1 = [[NKey alloc] init]; nkey1.typeFlags = 2; nkey1.modifierFlags = 0; nkey1.keyCode = VK_KEY_V; nkey1.text = @"v"; nkey1.bitmap = nil;
|
|
nkey2 = [[NKey alloc] init]; nkey2.typeFlags = 2; nkey2.modifierFlags = 1; nkey2.keyCode = VK_KEY_V; nkey2.text = @"V"; nkey2.bitmap = nil;
|
|
[defNKeys addObjectsFromArray:@[nkey1, nkey2]];
|
|
nkey1 = [[NKey alloc] init]; nkey1.typeFlags = 2; nkey1.modifierFlags = 0; nkey1.keyCode = VK_KEY_B; nkey1.text = @"b"; nkey1.bitmap = nil;
|
|
nkey2 = [[NKey alloc] init]; nkey2.typeFlags = 2; nkey2.modifierFlags = 1; nkey2.keyCode = VK_KEY_B; nkey2.text = @"B"; nkey2.bitmap = nil;
|
|
[defNKeys addObjectsFromArray:@[nkey1, nkey2]];
|
|
nkey1 = [[NKey alloc] init]; nkey1.typeFlags = 2; nkey1.modifierFlags = 0; nkey1.keyCode = VK_KEY_N; nkey1.text = @"n"; nkey1.bitmap = nil;
|
|
nkey2 = [[NKey alloc] init]; nkey2.typeFlags = 2; nkey2.modifierFlags = 1; nkey2.keyCode = VK_KEY_N; nkey2.text = @"N"; nkey2.bitmap = nil;
|
|
[defNKeys addObjectsFromArray:@[nkey1, nkey2]];
|
|
nkey1 = [[NKey alloc] init]; nkey1.typeFlags = 2; nkey1.modifierFlags = 0; nkey1.keyCode = VK_KEY_M; nkey1.text = @"m"; nkey1.bitmap = nil;
|
|
nkey2 = [[NKey alloc] init]; nkey2.typeFlags = 2; nkey2.modifierFlags = 1; nkey2.keyCode = VK_KEY_M; nkey2.text = @"M"; nkey2.bitmap = nil;
|
|
[defNKeys addObjectsFromArray:@[nkey1, nkey2]];
|
|
nkey1 = [[NKey alloc] init]; nkey1.typeFlags = 2; nkey1.modifierFlags = 0; nkey1.keyCode = VK_COMMA; nkey1.text = @","; nkey1.bitmap = nil;
|
|
nkey2 = [[NKey alloc] init]; nkey2.typeFlags = 2; nkey2.modifierFlags = 1; nkey2.keyCode = VK_COMMA; nkey2.text = @"<"; nkey2.bitmap = nil;
|
|
[defNKeys addObjectsFromArray:@[nkey1, nkey2]];
|
|
nkey1 = [[NKey alloc] init]; nkey1.typeFlags = 2; nkey1.modifierFlags = 0; nkey1.keyCode = VK_PERIOD; nkey1.text = @"."; nkey1.bitmap = nil;
|
|
nkey2 = [[NKey alloc] init]; nkey2.typeFlags = 2; nkey2.modifierFlags = 1; nkey2.keyCode = VK_PERIOD; nkey2.text = @">"; nkey2.bitmap = nil;
|
|
[defNKeys addObjectsFromArray:@[nkey1, nkey2]];
|
|
nkey1 = [[NKey alloc] init]; nkey1.typeFlags = 2; nkey1.modifierFlags = 0; nkey1.keyCode = VK_SLASH; nkey1.text = @"/"; nkey1.bitmap = nil;
|
|
nkey2 = [[NKey alloc] init]; nkey2.typeFlags = 2; nkey2.modifierFlags = 1; nkey2.keyCode = VK_SLASH; nkey2.text = @"?"; nkey2.bitmap = nil;
|
|
[defNKeys addObjectsFromArray:@[nkey1, nkey2]];
|
|
|
|
_oskDefaultNKeys = [[NSArray alloc] initWithArray:defNKeys];
|
|
}
|
|
|
|
return _oskDefaultNKeys;
|
|
}
|
|
|
|
/**
|
|
* called when closing the OSK
|
|
* when the OSK is not visible then modifier state is determined solely by the physical keyboard
|
|
*/
|
|
- (void)clearOskModifiers {
|
|
_oskShiftState = NO;
|
|
_oskOptionState = NO;
|
|
_oskControlState = NO;
|
|
[self updateModifierKeysForState];
|
|
[self updateKeyLabelsForCurrentLayer];
|
|
}
|
|
|
|
- (void)resetOSK {
|
|
[self setOskShiftState:NO];
|
|
[self setOskOptionState:NO];
|
|
[self.subviews makeObjectsPerformSelector:@selector(removeFromSuperview)];
|
|
[self initOSKKeys];
|
|
}
|
|
|
|
- (void)resizeOSKLayout {
|
|
os_log_debug([KMELogs oskLog], "OSKView resizeOSKLayout, removing all superviews");
|
|
[self.subviews makeObjectsPerformSelector:@selector(removeFromSuperview)];
|
|
[self initOSKKeys];
|
|
}
|
|
|
|
- (void)keyAction:(id)sender {
|
|
KeyView *keyView = (KeyView *)sender;
|
|
NSUInteger keyCode = [keyView.key keyCode];
|
|
os_log_debug([KMELogs oskLog], "OSKView keyAction, self: %{public}@, keyView: %{public}@", self, keyView);
|
|
if (keyCode < 0x100) {
|
|
NSRunningApplication *app = NSWorkspace.sharedWorkspace.frontmostApplication;
|
|
pid_t processId = app.processIdentifier;
|
|
CGEventSourceRef source = CGEventSourceCreate(kCGEventSourceStatePrivate);
|
|
CGEventRef keyDownEvent = CGEventCreateKeyboardEvent(source, (CGKeyCode)keyCode, true);
|
|
CGEventRef keyUpEvent = CGEventCreateKeyboardEvent(source, (CGKeyCode)keyCode, false);
|
|
|
|
CGEventSetIntegerValueField(keyDownEvent, kCGEventSourceUserData, [self createOskEventUserData]);
|
|
|
|
os_log_debug([KMELogs oskLog], "OSKView keyAction, keyDownEvent: %{public}@, modifier flags: 0x%llX", keyDownEvent, CGEventGetFlags(keyDownEvent));
|
|
|
|
CGEventPostToPid(processId, keyDownEvent);
|
|
CGEventPostToPid(processId, keyUpEvent);
|
|
CFRelease(keyDownEvent);
|
|
CFRelease(keyUpEvent);
|
|
|
|
CFRelease(source);
|
|
}
|
|
else {
|
|
if (keyCode == MVK_LEFT_SHIFT || keyCode == MVK_RIGHT_SHIFT) {
|
|
[self setOskShiftState:!self.oskShiftState];
|
|
}
|
|
else if (keyCode == MVK_LEFT_ALT || keyCode == MVK_RIGHT_ALT) {
|
|
[self setOskOptionState:!self.oskOptionState];
|
|
}
|
|
else if (keyCode == MVK_LEFT_CTRL || keyCode == MVK_RIGHT_CTRL) {
|
|
[self setOskControlState:!self.oskControlState];
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* get the event modifier flags representing the current state of the osk modifiers
|
|
*/
|
|
- (NSEventModifierFlags)getOskEventModifierFlags {
|
|
return [self getEventModifierFlags:self.oskShiftState optionFlag:self.oskOptionState controlFlag:self.oskControlState];
|
|
}
|
|
|
|
/**
|
|
* get the event modifier flags that represent the combined state of the physical and osk modifiers
|
|
*/
|
|
- (NSEventModifierFlags) getCombinedEventModifierFlags {
|
|
BOOL shift = self.physicalShiftState | self.oskShiftState;
|
|
BOOL option = self.physicalOptionState | self.oskOptionState;
|
|
BOOL control = self.physicalControlState | self.oskControlState;
|
|
|
|
return [self getEventModifierFlags:shift optionFlag:option controlFlag:control];
|
|
}
|
|
|
|
/**
|
|
* get the NSEventModifierFlags value that corresponds to the specified modifier states
|
|
*/
|
|
- (NSEventModifierFlags)getEventModifierFlags:(BOOL)shift optionFlag:(BOOL)option controlFlag:(BOOL)control {
|
|
NSEventModifierFlags modifierFlags = 0;
|
|
|
|
if (shift) {
|
|
modifierFlags = modifierFlags | NSEventModifierFlagShift;
|
|
}
|
|
/**
|
|
* Both left and right option keys on the OSK cause oskOptionState to be true without distinction of left or right.
|
|
* However, the generated event is a right alt so that it will trigger the right alt rules in the Keyman keyboard.
|
|
*/
|
|
if (option) {
|
|
modifierFlags = modifierFlags | MK_RIGHT_ALT_MASK;
|
|
}
|
|
if (control) {
|
|
modifierFlags = modifierFlags | NSEventModifierFlagControl;
|
|
}
|
|
|
|
return modifierFlags;
|
|
}
|
|
|
|
/**
|
|
* Create the 64-bit value to pass in the kCGEventSourceUserData field of the generated CGEvent
|
|
* The upper-most bit is set to distinguish it from the default value of zero, and the lower 32 bits
|
|
* store the modifier state of the OSK at the time that the keydown event was generated.
|
|
* This data is safely conveys the modifier information to the eventTap function.
|
|
* If the modifiers themselves were instead set by calling the function `CGEventSetFlags`
|
|
* directly on the generated CGEvent, then there would be no way to distinguish between the left
|
|
* and right option keys.
|
|
*
|
|
*/
|
|
- (int64_t) createOskEventUserData {
|
|
// set bit to identify this user data as originating from the OSK
|
|
int64_t oskEventData = OSK_EVENT_FLAG;
|
|
NSEventModifierFlags eventModifierFlags = [self getCombinedEventModifierFlags];
|
|
|
|
return oskEventData | eventModifierFlags;
|
|
}
|
|
|
|
- (void)handleKeyEvent:(NSEvent *)event {
|
|
os_log_debug([KMELogs oskLog], "OSKView handleKeyEvent event.type: %lu", event.type);
|
|
NSView *view = [self viewWithTag:event.keyCode|0x1000];
|
|
if (view == nil || ![view isKindOfClass:[KeyView class]])
|
|
return;
|
|
|
|
KeyView *keyView = (KeyView *)view;
|
|
if (event.type == NSEventTypeKeyDown)
|
|
[keyView setKeyPressed:YES];
|
|
[NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(setKeyPressedOff:) object:keyView];
|
|
[self performSelector:@selector(setKeyPressedOff:) withObject:keyView afterDelay:0.1];
|
|
}
|
|
|
|
- (void)setKeyPressedOff:(KeyView *)keyView {
|
|
[keyView setKeyPressed:NO];
|
|
}
|
|
|
|
/**
|
|
* get the Keyman modifier flags that represent the combined state of the physical and osk modifiers
|
|
*/
|
|
- (WORD) getKeymanModifierFlagsForCurrentLayer {
|
|
BOOL shift = self.physicalShiftState | self.oskShiftState;
|
|
BOOL option = self.physicalOptionState | self.oskOptionState;
|
|
BOOL control = self.physicalControlState | self.oskControlState;
|
|
|
|
return [self getKeymanModifierFlags:shift optionFlag:option controlFlag:control];
|
|
}
|
|
|
|
/**
|
|
* get Keyman modifier flags for the specified modifier states
|
|
*/
|
|
- (WORD)getKeymanModifierFlags:(BOOL)shift optionFlag:(BOOL)option controlFlag:(BOOL)control {
|
|
WORD flags = 0;
|
|
if (shift) {
|
|
flags |= KVKS_SHIFT;
|
|
}
|
|
if (option) {
|
|
if (self.kvk.containsRightAltKeys) {
|
|
flags |= KVKS_RALT;
|
|
} else if (self.kvk.containsAltKeys) {
|
|
flags |= KVKS_ALT;
|
|
}
|
|
}
|
|
if (control) {
|
|
flags |= KVKS_RCTRL;
|
|
}
|
|
|
|
return flags;
|
|
}
|
|
|
|
/**
|
|
* Display the key labels that correspond to the current state of the modifier keys.
|
|
* The layer shown depends on both the physical modifier state and the osk modifier state.
|
|
*/
|
|
- (void)updateKeyLabelsForCurrentLayer {
|
|
os_log_debug([KMELogs oskLog], "OSKView updateKeyLabelsForState, phsyical modifiers [shift: %d, option: %d, control: %d]\nosk modifiers [shift: %d, option: %d, control: %d]", self.physicalShiftState, self.physicalOptionState, self.physicalControlState, self.oskShiftState, self.oskOptionState, self.oskControlState);
|
|
|
|
[self resetKeyLabels];
|
|
NSMutableArray *mKeys = [[self keyTags] mutableCopy];
|
|
NSArray *nkeys = [self.kvk keys];
|
|
if (nkeys == nil)
|
|
nkeys = self.oskDefaultNKeys;
|
|
|
|
WORD keymanFlagsForCurrentLayer = [self getKeymanModifierFlagsForCurrentLayer];
|
|
|
|
NSString *ansiFont = [self ansiFont];
|
|
NSString *unicodeFont = [self unicodeFont];
|
|
unsigned short keyCode;
|
|
for (NKey *nkey in nkeys) {
|
|
if (nkey.modifierFlags == keymanFlagsForCurrentLayer) {
|
|
keyCode = [self MacKeyCode:nkey.keyCode];
|
|
os_log_debug([KMELogs keyLog], "keyCode: %d, %x for key: %{public}@", keyCode, keyCode, nkey);
|
|
if (keyCode < USHRT_MAX) {
|
|
NSView *view = [self viewWithTag:keyCode|0x1000];
|
|
if (view == nil || ![view isKindOfClass:[KeyView class]])
|
|
continue;
|
|
|
|
KeyView *keyView = (KeyView *)view;
|
|
[keyView setLabelFont:ansiFont];
|
|
if (nkey.typeFlags & KVKK_UNICODE) {
|
|
[keyView setLabelText:nkey.text];
|
|
NSString* label = nkey.text;
|
|
NSData* data = [label dataUsingEncoding:NSUTF8StringEncoding];
|
|
os_log_debug([KMELogs keyLog], "setLabelText to %{public}@, utf8data %{public}@", label, data);
|
|
[keyView setLabelFont:unicodeFont];
|
|
[mKeys removeObject:[NSNumber numberWithInteger:(keyCode|0x1000)]];
|
|
}
|
|
|
|
if (nkey.typeFlags & KVKK_BITMAP) {
|
|
[keyView setBitmap:nkey.bitmap];
|
|
}
|
|
|
|
[keyView setNeedsDisplay:YES];
|
|
}
|
|
}
|
|
}
|
|
/*
|
|
for (NSNumber *t in mKeys) {
|
|
NSView *view = [self viewWithTag:[t integerValue]|0x1000];
|
|
if (view == nil || ![view isKindOfClass:[KeyView class]])
|
|
continue;
|
|
|
|
KeyView *keyView = (KeyView *)view;
|
|
[keyView setLabelText:@""];
|
|
}*/
|
|
}
|
|
|
|
- (NSArray *)keyTags {
|
|
NSMutableArray *keyTags = [NSMutableArray arrayWithCapacity:0];
|
|
NSArray *views = [self subviews];
|
|
for (NSView *view in views) {
|
|
if (![view isKindOfClass:[KeyView class]])
|
|
continue;
|
|
|
|
[keyTags addObject:[NSNumber numberWithInteger:[view tag]]];
|
|
}
|
|
|
|
return keyTags;
|
|
}
|
|
|
|
- (void)resetKeyLabels {
|
|
NSArray *views = [self subviews];
|
|
for (NSView *view in views) {
|
|
if (![view isKindOfClass:[KeyView class]])
|
|
continue;
|
|
|
|
[(KeyView *)view setKey:[(KeyView *)view key]];
|
|
[(KeyView *)view setBitmap:nil];
|
|
[(KeyView *)view setNeedsDisplay:YES];
|
|
}
|
|
}
|
|
|
|
- (void)setPhysicalShiftState:(BOOL)state {
|
|
if (_physicalShiftState != state) {
|
|
_physicalShiftState = state;
|
|
|
|
/**
|
|
* When setting the physical shift state, clear the OSK shift state
|
|
* The state of the physical key overrides the modifier key clicked in the OSK.
|
|
*/
|
|
_oskShiftState = NO;
|
|
|
|
os_log_debug([KMELogs oskLog], "hardware shift key released");
|
|
[self updateKeyLabelsForCurrentLayer];
|
|
[self updateShiftKeysForState];
|
|
}
|
|
}
|
|
|
|
- (void)setOskShiftState:(BOOL)state {
|
|
if (_oskShiftState != state && !self.physicalShiftState) {
|
|
_oskShiftState = state;
|
|
[self updateKeyLabelsForCurrentLayer];
|
|
[self updateShiftKeysForState];
|
|
}
|
|
}
|
|
|
|
- (void)setPhysicalOptionState:(BOOL)state {
|
|
if (_physicalOptionState != state) {
|
|
_physicalOptionState = state;
|
|
|
|
/**
|
|
* When setting the physical option state, clear the OSK option state
|
|
* The state of the physical key overrides the modifier key clicked in the OSK.
|
|
*/
|
|
_oskOptionState = NO;
|
|
[self updateKeyLabelsForCurrentLayer];
|
|
[self updateOptionKeysForState];
|
|
}
|
|
}
|
|
|
|
- (void)setOskOptionState:(BOOL)state {
|
|
if (_oskOptionState != state && !self.physicalOptionState) {
|
|
_oskOptionState = state;
|
|
[self updateKeyLabelsForCurrentLayer];
|
|
[self updateOptionKeysForState];
|
|
}
|
|
}
|
|
|
|
- (void)setPhysicalControlState:(BOOL)state {
|
|
if (_physicalControlState != state) {
|
|
_physicalControlState = state;
|
|
|
|
/**
|
|
* When setting the physical control state, clear the OSK control state
|
|
* The state of the physical key overrides the modifier key clicked in the OSK.
|
|
*/
|
|
_oskControlState = NO;
|
|
[self updateKeyLabelsForCurrentLayer];
|
|
[self updateControlKeysForState];
|
|
}
|
|
}
|
|
|
|
- (void)setOskControlState:(BOOL)state {
|
|
if (_oskControlState != state && !self.physicalControlState) {
|
|
_oskControlState = state;
|
|
[self updateKeyLabelsForCurrentLayer];
|
|
[self updateControlKeysForState];
|
|
}
|
|
}
|
|
|
|
- (void)updateModifierKeysForState {
|
|
[self updateShiftKeysForState];
|
|
[self updateOptionKeysForState];
|
|
[self updateControlKeysForState];
|
|
}
|
|
|
|
- (void)updateShiftKeysForState {
|
|
BOOL pressed = self.oskShiftState || self.physicalShiftState;
|
|
KeyView *leftShiftKey = (KeyView *)[self viewWithTag:MVK_LEFT_SHIFT|0x1000];
|
|
KeyView *rightShiftKey = (KeyView *)[self viewWithTag:MVK_RIGHT_SHIFT|0x1000];
|
|
[leftShiftKey setKeyPressed:pressed];
|
|
[rightShiftKey setKeyPressed:pressed];
|
|
}
|
|
|
|
- (void)updateOptionKeysForState{
|
|
BOOL pressed = self.oskOptionState || self.physicalOptionState;
|
|
KeyView *leftOptionKey = (KeyView *)[self viewWithTag:MVK_LEFT_ALT|0x1000];
|
|
KeyView *rightOptionKey = (KeyView *)[self viewWithTag:MVK_RIGHT_ALT|0x1000];
|
|
[leftOptionKey setKeyPressed:pressed];
|
|
[rightOptionKey setKeyPressed:pressed];
|
|
}
|
|
|
|
- (void)updateControlKeysForState {
|
|
BOOL pressed = self.oskControlState || self.physicalControlState;
|
|
KeyView *leftControlKey = (KeyView *)[self viewWithTag:MVK_LEFT_CTRL|0x1000];
|
|
KeyView *rightControlKey = (KeyView *)[self viewWithTag:MVK_RIGHT_CTRL|0x1000];
|
|
[leftControlKey setKeyPressed:pressed];
|
|
[rightControlKey setKeyPressed:pressed];
|
|
}
|
|
|
|
- (NSString *)ansiFont {
|
|
return [self.kvk ansiFont].name;
|
|
}
|
|
|
|
- (NSString *)unicodeFont {
|
|
return [self.kvk unicodeFont].name;
|
|
}
|
|
|
|
// Converts a Windows VK code to Mac VK code
|
|
- (unsigned short)MacKeyCode:(unsigned short)vkCode {
|
|
unsigned short keyCode = USHRT_MAX;
|
|
for (unsigned short i = 0; i < 0x80; i++) {
|
|
if (VirtualKeyMap[i] == vkCode) {
|
|
keyCode = i;
|
|
break;
|
|
}
|
|
}
|
|
|
|
return keyCode;
|
|
}
|
|
|
|
@end
|