Skip to content

Instantly share code, notes, and snippets.

@claymcleod
Created August 28, 2014 05:40
Show Gist options
  • Save claymcleod/36d1fd65192c920e4245 to your computer and use it in GitHub Desktop.
Save claymcleod/36d1fd65192c920e4245 to your computer and use it in GitHub Desktop.
Keystroke Profile
//
// PRKeystrokeProfile.m
//
// The MIT License (MIT)
//
// Copyright (c) 2014 Clay McLeod. All rights reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#import "PRKeystrokeProfile.h"
@implementation PRKeystrokeProfile
double PRTotalDurationValuesForKeyCode[255];
double PRIterationsForKeyCode[255];
NSMutableDictionary *PRKeystokeDictionary;
NSString *PRDictionaryKeyFormat = @"KeyCode[%d]";
+ (float) keystrokeProfileAverageDurationForKeyCode:(int)keyCode
{
if(PRIterationsForKeyCode[keyCode] == 0)
return 0;
return (PRTotalDurationValuesForKeyCode[keyCode] / PRIterationsForKeyCode[keyCode]);
}
+ (float) computeAverageDurationPressOfValues
{
float keyValues = 0;
int keysLogged = 0;
for (int i = 0; i < 255; i++) {
if(PRTotalDurationValuesForKeyCode[i] > 0) {
keyValues += PRTotalDurationValuesForKeyCode[i];
keysLogged++;
}
}
return (keyValues / keysLogged);
}
+ (float) computeStandardDeviationOfValues
{
float numerator = 0;
float keyValues = 0;
int keysLogged = 0;
for (int i = 0; i < 255; i++) {
if(PRTotalDurationValuesForKeyCode[i] > 0) {
keyValues += PRTotalDurationValuesForKeyCode[i];
keysLogged++;
}
}
float average = (keyValues / keysLogged);
if(average < 0.1)
return 0;
for (int i = 0; i < 255; i++) {
if(PRTotalDurationValuesForKeyCode[i] > 0)
numerator += abs(PRTotalDurationValuesForKeyCode[i] - average);
}
return numerator / keysLogged;
}
+ (void) addValueToProfile:(double)timeElapsed withIndex:(int)index
{
PRTotalDurationValuesForKeyCode[index] = PRTotalDurationValuesForKeyCode[index] + timeElapsed;
PRIterationsForKeyCode[index]++;
}
+ (void) reportKeystrokeProfileValues
{
for (int i = 0; i <= 255; i++) {
if(PRIterationsForKeyCode[i] > 0)
NSLog(@"[%d] => Average: %f", i, [self keystrokeProfileAverageDurationForKeyCode:i]);
}
NSLog(@"Std = %f", [self computeStandardDeviationOfValues]);
}
+ (NSMutableDictionary*) createKeystrokeDictionaryFromValues
{
NSMutableDictionary* dict = [[NSMutableDictionary alloc] initWithCapacity:275];
float value;
for (int i = 0; i < 255; i++) {
value = PRTotalDurationValuesForKeyCode[i];
NSString *key = [NSString stringWithFormat:PRDictionaryKeyFormat, i];
[dict setObject:[NSNumber numberWithFloat:value] forKey:key];
}
[dict setObject:[NSNumber numberWithFloat:[self computeAverageDurationPressOfValues]] forKey:@"Average"];
[dict setObject:[NSNumber numberWithFloat:[self computeStandardDeviationOfValues]] forKey:@"Std"];
return dict;
}
+ (float) getValueFromKeystrokeDictionaryWithKeyCode: (int) keyCode
{
return [[PRKeystokeDictionary valueForKey:[NSString stringWithFormat:PRDictionaryKeyFormat, keyCode]] floatValue];
}
+ (float) getAverageFromKeystrokeDictionary
{
return [[PRKeystokeDictionary valueForKey:@"Average"] floatValue];
}
+ (float) getStdFromKeystrokeDictionary
{
return [[PRKeystokeDictionary valueForKey:@"Std"] floatValue];
}
+ (NSString *) PRGetPathForKeystrokesProfile
{
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
if ([paths count] > 0)
{
return [[paths objectAtIndex:0] stringByAppendingPathComponent:@"keystrokes.plist"];
} else {
return nil;
}
}
+ (bool) writeKeystokeDictionaryToFile
{
NSDictionary *dict = [self createKeystrokeDictionaryFromValues];
NSString *dictPath = [self PRGetPathForKeystrokesProfile];
return [dict writeToFile:dictPath atomically:YES];
}
+ (void) updateKeystrokesProfileDictionary
{
PRKeystokeDictionary = [self createKeystrokeDictionaryFromValues];
[self writeKeystokeDictionaryToFile];
}
+ (bool) loadKeystrokeProfileFromFile
{
PRKeystokeDictionary = [[NSMutableDictionary alloc] initWithContentsOfFile:[self PRGetPathForKeystrokesProfile]];
if(PRKeystokeDictionary) {
return true;
} else {
return false;
}
}
@end
//
// PRKeystrokeProfile.h
//
// The MIT License (MIT)
//
// Copyright (c) 2014 Clay McLeod. All rights reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#import <Foundation/Foundation.h>
@interface PRKeystrokeProfile : NSObject
+ (float) keystrokeProfileAverageDurationForKeyCode:(int)keyCode;
+ (float) computeAverageDurationPressOfValues;
+ (float) computeStandardDeviationOfValues;
+ (void) addValueToProfile:(double)timeElapsed withIndex:(int)index;
+ (void) reportKeystrokeProfileValues;
+ (NSMutableDictionary*) createKeystrokeDictionaryFromValues;
+ (float) getValueFromKeystrokeDictionaryWithKeyCode:(int) keyCode;
+ (float) getAverageFromKeystrokeDictionary;
+ (float) getStdFromKeystrokeDictionary;
+ (bool) writeKeystokeDictionaryToFile;
+ (void) updateKeystrokesProfileDictionary;
+ (bool) loadKeystrokeProfileFromFile;
@end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment