master 28c47751245b cached
19 files
55.6 KB
15.5k tokens
1 symbols
1 requests
Download .txt
Repository: kishikawakatsumi/ScreenRecorder
Branch: master
Commit: 28c47751245b
Files: 19
Total size: 55.6 KB

Directory structure:
gitextract_yulxgphk/

├── .gitignore
├── LICENSE
├── Lib/
│   ├── SRScreenRecorder.h
│   └── SRScreenRecorder.m
├── README.md
├── ScreenRecorder/
│   ├── SRAppDelegate.h
│   ├── SRAppDelegate.m
│   ├── SRDetailViewController.h
│   ├── SRDetailViewController.m
│   ├── SRMasterViewController.h
│   ├── SRMasterViewController.m
│   ├── ScreenRecorder-Info.plist
│   ├── ScreenRecorder-Prefix.pch
│   ├── en.lproj/
│   │   ├── InfoPlist.strings
│   │   └── MainStoryboard.storyboard
│   └── main.m
├── ScreenRecorder.xcodeproj/
│   └── project.pbxproj
└── Vendor/
    ├── KTouchPointerWindow.h
    └── KTouchPointerWindow.m

================================================
FILE CONTENTS
================================================

================================================
FILE: .gitignore
================================================
# Xcode
.DS_Store
build/
*.pbxuser
!default.pbxuser
*.mode1v3
!default.mode1v3
*.mode2v3
!default.mode2v3
*.perspectivev3
!default.perspectivev3
*.xcworkspace
!default.xcworkspace
xcuserdata
profile
*.moved-aside
DerivedData
.idea/


================================================
FILE: LICENSE
================================================
Copyright (c) 2012 kishikawa katsumi (http://kishikawakatsumi.com/)

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.

================================================
FILE: Lib/SRScreenRecorder.h
================================================
//
//  SRScreenRecorder.h
//  ScreenRecorder
//
//  Created by kishikawa katsumi on 2012/12/26.
//  Copyright (c) 2012年 kishikawa katsumi. All rights reserved.
//

#import <Foundation/Foundation.h>
#import <AVFoundation/AVFoundation.h>
#import <TargetConditionals.h>

typedef NSString *(^SRScreenRecorderOutputFilenameBlock)(void);

@interface SRScreenRecorder : NSObject

@property (retain, nonatomic, readonly) UIWindow *window; // A window to be recorded.
@property (assign, nonatomic) NSInteger frameInterval;
@property (assign, nonatomic) NSUInteger autosaveDuration; // in second, default value is 600 (10 minutes).
@property (assign, nonatomic) BOOL showsTouchPointer;
@property (copy, nonatomic) SRScreenRecorderOutputFilenameBlock filenameBlock;

- (instancetype)initWithWindow:(UIWindow *)window;

- (void)startRecording;
- (void)stopRecording;

@end


================================================
FILE: Lib/SRScreenRecorder.m
================================================
//
//  SRScreenRecorder.m
//  ScreenRecorder
//
//  Created by kishikawa katsumi on 2012/12/26.
//  Copyright (c) 2012年 kishikawa katsumi. All rights reserved.
//

#import "SRScreenRecorder.h"
#import "KTouchPointerWindow.h"

#ifndef APPSTORE_SAFE
#define APPSTORE_SAFE 0
#endif

#define DEFAULT_FRAME_INTERVAL 2
#define DEFAULT_AUTOSAVE_DURATION 600
#define TIME_SCALE 600

static NSInteger counter;

#if !APPSTORE_SAFE
CGImageRef UICreateCGImageFromIOSurface(CFTypeRef surface);
#ifndef __IPHONE_11_0
CVReturn CVPixelBufferCreateWithIOSurface(
                                          CFAllocatorRef allocator,
                                          CFTypeRef surface,
                                          CFDictionaryRef pixelBufferAttributes,
                                          CVPixelBufferRef *pixelBufferOut);
#endif

@interface UIWindow (ScreenRecorder)
+ (IOSurfaceRef)createScreenIOSurface;
+ (IOSurfaceRef)createIOSurfaceFromScreen:(UIScreen *)screen;
- (IOSurfaceRef)createIOSurface;
- (IOSurfaceRef)createIOSurfaceWithFrame:(CGRect)frame;
@end
#endif

@interface SRScreenRecorder ()

@property (strong, nonatomic) AVAssetWriter *writer;
@property (strong, nonatomic) AVAssetWriterInput *writerInput;
@property (strong, nonatomic) AVAssetWriterInputPixelBufferAdaptor *writerInputPixelBufferAdaptor;
@property (strong, nonatomic) CADisplayLink *displayLink;

@end

@implementation SRScreenRecorder {
	CFAbsoluteTime firstFrameTime;
    CFTimeInterval startTimestamp;
    BOOL shouldRestart;
    
    dispatch_queue_t queue;
    UIBackgroundTaskIdentifier backgroundTask;
}

- (instancetype)initWithWindow:(UIWindow *)window
{
    self = [super init];
    if (self) {
        _window = window;
        _frameInterval = DEFAULT_FRAME_INTERVAL;
        _autosaveDuration = DEFAULT_AUTOSAVE_DURATION;
        _showsTouchPointer = YES;

        counter++;
        NSString *label = [NSString stringWithFormat:@"com.kishikawakatsumi.screen_recorder-%@", @(counter)];
        queue = dispatch_queue_create([label cStringUsingEncoding:NSUTF8StringEncoding], NULL);

        [self setupNotifications];
    }
    return self;
}

- (void)dealloc
{
    [[NSNotificationCenter defaultCenter] removeObserver:self];
    [self stopRecording];
}

#pragma mark Setup

- (void)setupAssetWriterWithURL:(NSURL *)outputURL
{
    NSError *error = nil;
    
    self.writer = [[AVAssetWriter alloc] initWithURL:outputURL fileType:AVFileTypeQuickTimeMovie error:&error];
    NSParameterAssert(self.writer);
    if (error) {
        NSLog(@"Error: %@", [error localizedDescription]);
    }
    
    UIScreen *mainScreen = [UIScreen mainScreen];
#if APPSTORE_SAFE
    CGSize size = mainScreen.bounds.size;
#else
    CGRect nativeBounds = [mainScreen nativeBounds];
    CGSize size = nativeBounds.size;
#endif
    
    NSDictionary *outputSettings = @{AVVideoCodecKey : AVVideoCodecH264, AVVideoWidthKey : @(size.width), AVVideoHeightKey : @(size.height)};
    self.writerInput = [AVAssetWriterInput assetWriterInputWithMediaType:AVMediaTypeVideo outputSettings:outputSettings];
	self.writerInput.expectsMediaDataInRealTime = YES;
    
    NSDictionary *sourcePixelBufferAttributes = @{(NSString *)kCVPixelBufferPixelFormatTypeKey : @(kCVPixelFormatType_32ARGB)};
    self.writerInputPixelBufferAdaptor = [AVAssetWriterInputPixelBufferAdaptor assetWriterInputPixelBufferAdaptorWithAssetWriterInput:self.writerInput
                                                                                                          sourcePixelBufferAttributes:sourcePixelBufferAttributes];
    NSParameterAssert(self.writerInput);
    NSParameterAssert([self.writer canAddInput:self.writerInput]);
    
    [self.writer addInput:self.writerInput];
    
	firstFrameTime = CFAbsoluteTimeGetCurrent();
    
    [self.writer startWriting];
    [self.writer startSessionAtSourceTime:kCMTimeZero];
}

- (void)setupTouchPointer
{
    if (self.showsTouchPointer) {
        KTouchPointerWindowInstall();
    } else {
        KTouchPointerWindowUninstall();
    }
}

- (void)setupNotifications
{
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(applicationDidEnterBackground:) name:UIApplicationDidEnterBackgroundNotification object:nil];
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(applicationWillEnterForeground:) name:UIApplicationWillEnterForegroundNotification object:nil];
}

- (void)setupTimer
{
    self.displayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(captureFrame:)];
    self.displayLink.frameInterval = self.frameInterval;
    [self.displayLink addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSRunLoopCommonModes];
}

#pragma mark Recording

- (void)startRecording
{
    [self setupAssetWriterWithURL:[self outputFileURL]];
    
    [self setupTouchPointer];
    
    [self setupTimer];
}

- (void)stopRecording
{
    [self.displayLink invalidate];
    startTimestamp = 0.0;
    
    dispatch_async(queue, ^{
        if (self.writer.status != AVAssetWriterStatusCompleted && self.writer.status != AVAssetWriterStatusUnknown) {
            [self.writerInput markAsFinished];
        }
        [self.writer finishWritingWithCompletionHandler:^
         {
             [self finishBackgroundTask];
             [self restartRecordingIfNeeded];
         }];
    });
}

- (void)restartRecordingIfNeeded
{
    if (shouldRestart) {
        shouldRestart = NO;
        dispatch_async(queue, ^{
            dispatch_async(dispatch_get_main_queue(), ^
                           {
                               [self startRecording];
                           });
        });
    }
}

- (void)rotateFile
{
    shouldRestart = YES;
    dispatch_async(queue, ^{
        [self stopRecording];
    });
}

- (void)captureFrame:(CADisplayLink *)displayLink
{
    dispatch_async(queue, ^{
        if (self.writerInput.readyForMoreMediaData) {
            CVReturn status = kCVReturnSuccess;
            CVPixelBufferRef buffer = NULL;
            CFTypeRef backingData;
#if APPSTORE_SAFE || TARGET_IPHONE_SIMULATOR
            __block UIImage *screenshot = nil;
            dispatch_sync(dispatch_get_main_queue(), ^{
                screenshot = [self screenshot];
            });
            CGImageRef image = screenshot.CGImage;

            CGDataProviderRef dataProvider = CGImageGetDataProvider(image);
            CFDataRef data = CGDataProviderCopyData(dataProvider);
            backingData = CFDataCreateMutableCopy(kCFAllocatorDefault, CFDataGetLength(data), data);
            CFRelease(data);

            const UInt8 *bytePtr = CFDataGetBytePtr(backingData);

            status = CVPixelBufferCreateWithBytes(kCFAllocatorDefault,
                                                  CGImageGetWidth(image),
                                                  CGImageGetHeight(image),
                                                  kCVPixelFormatType_32BGRA,
                                                  (void *)bytePtr,
                                                  CGImageGetBytesPerRow(image),
                                                  NULL,
                                                  NULL,
                                                  NULL,
                                                  &buffer);
            NSParameterAssert(status == kCVReturnSuccess && buffer);
#else
            IOSurfaceRef surface = [self.window createIOSurface];
            backingData = surface;

            NSDictionary *pixelBufferAttributes = @{(NSString *)kCVPixelBufferPixelFormatTypeKey : @(kCVPixelFormatType_32BGRA)};
            status = CVPixelBufferCreateWithIOSurface(NULL, surface, (__bridge CFDictionaryRef _Nullable)(pixelBufferAttributes), &buffer);
            NSParameterAssert(status == kCVReturnSuccess && buffer);
#endif
            if (buffer) {
                CFAbsoluteTime currentTime = CFAbsoluteTimeGetCurrent();
                CFTimeInterval elapsedTime = currentTime - firstFrameTime;

                CMTime presentTime =  CMTimeMake(elapsedTime * TIME_SCALE, TIME_SCALE);

                if(![self.writerInputPixelBufferAdaptor appendPixelBuffer:buffer withPresentationTime:presentTime]) {
                    [self stopRecording];
                }

                CVPixelBufferRelease(buffer);
            }

            CFRelease(backingData);
        }
    });
    
    if (startTimestamp == 0.0) {
        startTimestamp = displayLink.timestamp;
    }
    
    NSTimeInterval dalta = displayLink.timestamp - startTimestamp;
    
    if (self.autosaveDuration > 0 && dalta > self.autosaveDuration) {
        startTimestamp = 0.0;
        [self rotateFile];
    }
}

- (UIImage *)screenshot
{
    UIScreen *mainScreen = [UIScreen mainScreen];
    CGSize imageSize = mainScreen.bounds.size;
    UIGraphicsBeginImageContextWithOptions(imageSize, NO, 0);
    
    CGContextRef context = UIGraphicsGetCurrentContext();
    
    NSArray *windows = [[UIApplication sharedApplication] windows];
    for (UIWindow *window in windows) {
        if (![window respondsToSelector:@selector(screen)] || window.screen == mainScreen) {
            CGContextSaveGState(context);
            
            CGContextTranslateCTM(context, window.center.x, window.center.y);
            CGContextConcatCTM(context, [window transform]);
            CGContextTranslateCTM(context,
                                  -window.bounds.size.width * window.layer.anchorPoint.x,
                                  -window.bounds.size.height * window.layer.anchorPoint.y);
            
            [window.layer.presentationLayer renderInContext:context];
            
            CGContextRestoreGState(context);
        }
    }
    
    UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
    
    UIGraphicsEndImageContext();
    
    return image;
}

#pragma mark Background tasks

- (void)applicationDidEnterBackground:(NSNotification *)notification
{
    UIApplication *application = [UIApplication sharedApplication];
    
    UIDevice *device = [UIDevice currentDevice];
    BOOL backgroundSupported = NO;
    if ([device respondsToSelector:@selector(isMultitaskingSupported)]) {
        backgroundSupported = device.multitaskingSupported;
    }
    
    if (backgroundSupported) {
        backgroundTask = [application beginBackgroundTaskWithExpirationHandler:^{
            [self finishBackgroundTask];
        }];
    }
    
    [self stopRecording];
}

- (void)applicationWillEnterForeground:(NSNotification *)notification
{
    [self finishBackgroundTask];
    [self startRecording];
}

- (void)finishBackgroundTask
{
    if (backgroundTask != UIBackgroundTaskInvalid) {
        [[UIApplication sharedApplication] endBackgroundTask:backgroundTask];
        backgroundTask = UIBackgroundTaskInvalid;
    }
}

#pragma mark Utility methods

- (NSString *)documentDirectory
{
	NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
	NSString *documentsDirectory = [paths objectAtIndex:0];
	return documentsDirectory;
}

- (NSString *)defaultFilename
{
    time_t timer;
    time(&timer);
    NSString *timestamp = [NSString stringWithFormat:@"%ld", timer];
    return [NSString stringWithFormat:@"%@.mov", timestamp];
}

- (BOOL)existsFile:(NSString *)filename
{
    NSString *path = [self.documentDirectory stringByAppendingPathComponent:filename];
    NSFileManager *fileManager = [[NSFileManager alloc] init];
    BOOL isDirectory;
    return [fileManager fileExistsAtPath:path isDirectory:&isDirectory] && !isDirectory;
}

- (NSString *)nextFilename:(NSString *)filename
{
    static NSInteger fileCounter;
    
    fileCounter++;
    NSString *pathExtension = [filename pathExtension];
    filename = [[[filename stringByDeletingPathExtension] stringByAppendingString:[NSString stringWithFormat:@"-%@", @(fileCounter)]] stringByAppendingPathExtension:pathExtension];
    
    if ([self existsFile:filename]) {
        return [self nextFilename:filename];
    }
    
    return filename;
}

- (NSURL *)outputFileURL
{    
    if (!self.filenameBlock) {
        __block SRScreenRecorder *wself = self;
        self.filenameBlock = ^(void) {
            return [wself defaultFilename];
        };
    }
    
    NSString *filename = self.filenameBlock();
    if ([self existsFile:filename]) {
        filename = [self nextFilename:filename];
    }
    
    NSString *path = [self.documentDirectory stringByAppendingPathComponent:filename];
    return [NSURL fileURLWithPath:path];
}

@end


================================================
FILE: README.md
================================================
ScreenRecorder
==============
Capturing a screen as videos on iOS devices for user testing.

## Features
* Screen capture
* Show touch pointer
* Autosave and file rotation
* Change FPS

## Setup

###1. Add the files  
Copy the files you need to your project folder, and add them to your Xcode project.
  * Lib/SRScreenRecorder.h
  * Lib/SRScreenRecorder.m
  * Vendor/KTouchPointerWindow.h
  * Vendor/KTouchPointerWindow.m

###2. Link with the frameworks
  * QuartzCore.framework
  * CoreVideo.framework
  * CoreMedia.framework
  * AVFoundation.framework

## Usage
###Basic  
```objective-c
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    [[SRScreenRecorder sharedInstance] startRecording];
    return YES;
}
 ```

In default settings, 
* save movie file automatically on enter background
* and auto rotate save files every 10 minutes
* movie file saved at document directory, named 'TIMESTAMP.mov'
* 30 FPS
* shows touch pointer

###Customize  
```objective-c
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    SRScreenRecorder *recorder = [SRScreenRecorder sharedInstance];
    recorder.frameInterval = 1; // 60 FPS
    recorder.autosaveDuration = 1800; // 30 minutes
    recorder.showsTouchPointer = NO; // hidden touch pointer
    recorder.filenameBlock = ^(void) {
        return @"screencast.mov";
    }; // change filename
    
    [recorder startRecording];
    
    return YES;
}
 ```

###When submit to AppStore if includes this library, define APPSTORE_SAFE macro to eliminate using undocumented API
```objective-c
#define APPSTORE_SAFE 1
 ```

## 3rd party libraries

**KTouchPointerWindow**  
[https://github.com/itok/KTouchPointerWindow](https://github.com/itok/KTouchPointerWindow)  
 
[Apache]: http://www.apache.org/licenses/LICENSE-2.0
[MIT]: http://www.opensource.org/licenses/mit-license.php
[GPL]: http://www.gnu.org/licenses/gpl.html
[BSD]: http://opensource.org/licenses/bsd-license.php

## License

ScreenRecorder is available under the [MIT license][MIT]. See the LICENSE file for more info.


================================================
FILE: ScreenRecorder/SRAppDelegate.h
================================================
//
//  SRAppDelegate.h
//  ScreenRecorder
//
//  Created by kishikawa katsumi on 2012/12/26.
//  Copyright (c) 2012 kishikawa katsumi. All rights reserved.
//

#import <UIKit/UIKit.h>

@interface SRAppDelegate : UIResponder <UIApplicationDelegate>

@property (strong, nonatomic) UIWindow *window;

@end


================================================
FILE: ScreenRecorder/SRAppDelegate.m
================================================
//
//  SRAppDelegate.m
//  ScreenRecorder
//
//  Created by kishikawa katsumi on 2012/12/26.
//  Copyright (c) 2012 kishikawa katsumi. All rights reserved.
//

#import "SRAppDelegate.h"
#import "SRScreenRecorder.h"

@implementation SRAppDelegate {
    SRScreenRecorder *screenRecorder;
}

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    screenRecorder = [[SRScreenRecorder alloc] initWithWindow:self.window];
    [screenRecorder startRecording];
    
    return YES;
}

@end


================================================
FILE: ScreenRecorder/SRDetailViewController.h
================================================
//
//  SRDetailViewController.h
//  ScreenRecorder
//
//  Created by kishikawa katsumi on 2012/12/26.
//  Copyright (c) 2012 kishikawa katsumi. All rights reserved.
//

#import <UIKit/UIKit.h>

@interface SRDetailViewController : UIViewController

@property (strong, nonatomic) id detailItem;

@property (weak, nonatomic) IBOutlet UILabel *detailDescriptionLabel;
@end


================================================
FILE: ScreenRecorder/SRDetailViewController.m
================================================
//
//  SRDetailViewController.m
//  ScreenRecorder
//
//  Created by kishikawa katsumi on 2012/12/26.
//  Copyright (c) 2012 kishikawa katsumi. All rights reserved.
//

#import "SRDetailViewController.h"

@interface SRDetailViewController ()
- (void)configureView;
@end

@implementation SRDetailViewController

#pragma mark - Managing the detail item

- (void)setDetailItem:(id)newDetailItem
{
    if (_detailItem != newDetailItem) {
        _detailItem = newDetailItem;
        
        [self configureView];
    }
}

- (void)configureView
{
    if (self.detailItem) {
        self.detailDescriptionLabel.text = [self.detailItem description];
    }
}

- (void)viewDidLoad
{
    [super viewDidLoad];
    
    [self configureView];
}

- (void)didReceiveMemoryWarning
{
    [super didReceiveMemoryWarning];
}

@end


================================================
FILE: ScreenRecorder/SRMasterViewController.h
================================================
//
//  SRMasterViewController.h
//  ScreenRecorder
//
//  Created by kishikawa katsumi on 2012/12/26.
//  Copyright (c) 2012 kishikawa katsumi. All rights reserved.
//

#import <UIKit/UIKit.h>

@interface SRMasterViewController : UITableViewController

@end


================================================
FILE: ScreenRecorder/SRMasterViewController.m
================================================
//
//  SRMasterViewController.m
//  ScreenRecorder
//
//  Created by kishikawa katsumi on 2012/12/26.
//  Copyright (c) 2012 kishikawa katsumi. All rights reserved.
//

#import "SRMasterViewController.h"
#import "SRDetailViewController.h"

@interface SRMasterViewController () {
    NSMutableArray *_objects;
}
@end

@implementation SRMasterViewController

- (void)awakeFromNib
{
    [super awakeFromNib];
}

- (void)viewDidLoad
{
    [super viewDidLoad];
    
    self.navigationItem.leftBarButtonItem = self.editButtonItem;

    UIBarButtonItem *addButton = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemAdd target:self action:@selector(insertNewObject:)];
    self.navigationItem.rightBarButtonItem = addButton;
}

- (void)didReceiveMemoryWarning
{
    [super didReceiveMemoryWarning];
}

- (void)insertNewObject:(id)sender
{
    if (!_objects) {
        _objects = [[NSMutableArray alloc] init];
    }
    [_objects insertObject:[NSDate date] atIndex:0];
    NSIndexPath *indexPath = [NSIndexPath indexPathForRow:0 inSection:0];
    [self.tableView insertRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationAutomatic];
}

#pragma mark - Table View

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
    return 1;
}

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
    return _objects.count;
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    static NSString *CellIdentifier = @"Cell";
    UITableViewCell *cell;
    if ([tableView respondsToSelector:@selector(dequeueReusableCellWithIdentifier:forIndexPath:)]) {
        cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
    } else {
        cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
        if (!cell) {
            cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
        }
    }

    NSDate *object = _objects[indexPath.row];
    cell.textLabel.text = [object description];
    return cell;
}

- (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath
{
    return YES;
}

- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath
{
    if (editingStyle == UITableViewCellEditingStyleDelete) {
        [_objects removeObjectAtIndex:indexPath.row];
        [tableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationFade];
    } else if (editingStyle == UITableViewCellEditingStyleInsert) {
        // Create a new instance of the appropriate class, insert it into the array, and add a new row to the table view.
    }
}

- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
    if ([[segue identifier] isEqualToString:@"showDetail"]) {
        NSIndexPath *indexPath = [self.tableView indexPathForSelectedRow];
        NSDate *object = _objects[indexPath.row];
        [[segue destinationViewController] setDetailItem:object];
    }
}

@end


================================================
FILE: ScreenRecorder/ScreenRecorder-Info.plist
================================================
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
	<key>CFBundleDevelopmentRegion</key>
	<string>en</string>
	<key>CFBundleDisplayName</key>
	<string>${PRODUCT_NAME}</string>
	<key>CFBundleExecutable</key>
	<string>${EXECUTABLE_NAME}</string>
	<key>CFBundleIdentifier</key>
	<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
	<key>CFBundleInfoDictionaryVersion</key>
	<string>6.0</string>
	<key>CFBundleName</key>
	<string>${PRODUCT_NAME}</string>
	<key>CFBundlePackageType</key>
	<string>APPL</string>
	<key>CFBundleShortVersionString</key>
	<string>1.0</string>
	<key>CFBundleSignature</key>
	<string>????</string>
	<key>CFBundleVersion</key>
	<string>1.0</string>
	<key>LSRequiresIPhoneOS</key>
	<true/>
	<key>UIMainStoryboardFile</key>
	<string>MainStoryboard</string>
	<key>UIRequiredDeviceCapabilities</key>
	<array>
		<string>armv7</string>
	</array>
	<key>UIStatusBarTintParameters</key>
	<dict>
		<key>UINavigationBar</key>
		<dict>
			<key>Style</key>
			<string>UIBarStyleDefault</string>
			<key>Translucent</key>
			<false/>
		</dict>
	</dict>
	<key>UISupportedInterfaceOrientations</key>
	<array>
		<string>UIInterfaceOrientationPortrait</string>
		<string>UIInterfaceOrientationLandscapeLeft</string>
		<string>UIInterfaceOrientationLandscapeRight</string>
	</array>
</dict>
</plist>


================================================
FILE: ScreenRecorder/ScreenRecorder-Prefix.pch
================================================
//
// Prefix header for all source files of the 'ScreenRecorder' target in the 'ScreenRecorder' project
//

#import <Availability.h>

#ifndef __IPHONE_5_0
#warning "This project uses features only available in iOS SDK 5.0 and later."
#endif

#ifdef __OBJC__
    #import <UIKit/UIKit.h>
    #import <Foundation/Foundation.h>
#endif


================================================
FILE: ScreenRecorder/en.lproj/InfoPlist.strings
================================================
/* Localized versions of Info.plist keys */
"CFBundleDisplayName" = "Recorder";


================================================
FILE: ScreenRecorder/en.lproj/MainStoryboard.storyboard
================================================
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="2.0" toolsVersion="2844" systemVersion="12C3006" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" initialViewController="3">
    <dependencies>
        <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="1930"/>
    </dependencies>
    <scenes>
        <!--Navigation Controller-->
        <scene sceneID="11">
            <objects>
                <navigationController id="3" sceneMemberID="viewController">
                    <navigationBar key="navigationBar" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" id="4">
                        <autoresizingMask key="autoresizingMask"/>
                    </navigationBar>
                    <connections>
                        <segue destination="12" kind="relationship" relationship="rootViewController" id="19"/>
                    </connections>
                </navigationController>
                <placeholder placeholderIdentifier="IBFirstResponder" id="10" sceneMemberID="firstResponder"/>
            </objects>
            <point key="canvasLocation" x="-1" y="64"/>
        </scene>
        <!--Master View Controller - Master-->
        <scene sceneID="18">
            <objects>
                <tableViewController storyboardIdentifier="" title="Master" id="12" customClass="SRMasterViewController" sceneMemberID="viewController">
                    <tableView key="view" opaque="NO" clipsSubviews="YES" clearsContextBeforeDrawing="NO" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="prototypes" style="plain" rowHeight="44" sectionHeaderHeight="22" sectionFooterHeight="22" id="13">
                        <rect key="frame" x="0.0" y="64" width="320" height="504"/>
                        <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
                        <color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
                        <prototypes>
                            <tableViewCell contentMode="scaleToFill" selectionStyle="blue" accessoryType="disclosureIndicator" hidesAccessoryWhenEditing="NO" indentationLevel="1" indentationWidth="0.0" reuseIdentifier="Cell" textLabel="phq-AM-6qj" style="IBUITableViewCellStyleDefault" id="lJ0-d7-vTF">
                                <rect key="frame" x="0.0" y="22" width="320" height="44"/>
                                <autoresizingMask key="autoresizingMask"/>
                                <view key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center">
                                    <rect key="frame" x="0.0" y="0.0" width="300" height="43"/>
                                    <autoresizingMask key="autoresizingMask"/>
                                    <subviews>
                                        <label opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" text="Title" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="phq-AM-6qj">
                                            <rect key="frame" x="10" y="0.0" width="280" height="43"/>
                                            <autoresizingMask key="autoresizingMask"/>
                                            <fontDescription key="fontDescription" type="boldSystem" pointSize="20"/>
                                            <color key="textColor" cocoaTouchSystemColor="darkTextColor"/>
                                            <color key="highlightedColor" red="1" green="1" blue="1" alpha="1" colorSpace="calibratedRGB"/>
                                        </label>
                                    </subviews>
                                    <color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/>
                                </view>
                                <color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
                                <connections>
                                    <segue destination="21" kind="push" identifier="showDetail" id="jZb-fq-zAk"/>
                                </connections>
                            </tableViewCell>
                        </prototypes>
                        <sections/>
                        <connections>
                            <outlet property="dataSource" destination="12" id="16"/>
                            <outlet property="delegate" destination="12" id="15"/>
                        </connections>
                    </tableView>
                    <navigationItem key="navigationItem" title="Master" id="36"/>
                </tableViewController>
                <placeholder placeholderIdentifier="IBFirstResponder" id="17" sceneMemberID="firstResponder"/>
            </objects>
            <point key="canvasLocation" x="459" y="64"/>
        </scene>
        <!--Detail View Controller - Detail-->
        <scene sceneID="24">
            <objects>
                <viewController storyboardIdentifier="" title="Detail" id="21" customClass="SRDetailViewController" sceneMemberID="viewController">
                    <view key="view" contentMode="scaleToFill" id="22">
                        <rect key="frame" x="0.0" y="64" width="320" height="504"/>
                        <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
                        <subviews>
                            <label clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleToFill" text="Detail view content goes here" textAlignment="center" lineBreakMode="tailTruncation" minimumFontSize="10" id="27">
                                <rect key="frame" x="20" y="243" width="280" height="18"/>
                                <color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
                                <fontDescription key="fontDescription" type="system" size="system"/>
                                <color key="textColor" cocoaTouchSystemColor="darkTextColor"/>
                                <nil key="highlightedColor"/>
                            </label>
                        </subviews>
                        <color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="calibratedWhite"/>
                    </view>
                    <navigationItem key="navigationItem" title="Detail" id="26"/>
                    <connections>
                        <outlet property="detailDescriptionLabel" destination="27" id="28"/>
                    </connections>
                </viewController>
                <placeholder placeholderIdentifier="IBFirstResponder" id="23" sceneMemberID="firstResponder"/>
            </objects>
            <point key="canvasLocation" x="902" y="64"/>
        </scene>
    </scenes>
    <classes>
        <class className="SRDetailViewController" superclassName="UIViewController">
            <source key="sourceIdentifier" type="project" relativePath="./Classes/SRDetailViewController.h"/>
            <relationships>
                <relationship kind="outlet" name="detailDescriptionLabel" candidateClass="UILabel"/>
            </relationships>
        </class>
        <class className="SRMasterViewController" superclassName="UITableViewController">
            <source key="sourceIdentifier" type="project" relativePath="./Classes/SRMasterViewController.h"/>
        </class>
    </classes>
    <simulatedMetricsContainer key="defaultSimulatedMetrics">
        <simulatedStatusBarMetrics key="statusBar"/>
        <simulatedOrientationMetrics key="orientation"/>
        <simulatedScreenMetrics key="destination" type="retina4"/>
    </simulatedMetricsContainer>
</document>

================================================
FILE: ScreenRecorder/main.m
================================================
//
//  main.m
//  ScreenRecorder
//
//  Created by kishikawa katsumi on 2012/12/26.
//  Copyright (c) 2012 kishikawa katsumi. All rights reserved.
//

#import <UIKit/UIKit.h>

#import "SRAppDelegate.h"

int main(int argc, char *argv[])
{
    @autoreleasepool {
        return UIApplicationMain(argc, argv, nil, NSStringFromClass([SRAppDelegate class]));
    }
}


================================================
FILE: ScreenRecorder.xcodeproj/project.pbxproj
================================================
// !$*UTF8*$!
{
	archiveVersion = 1;
	classes = {
	};
	objectVersion = 46;
	objects = {

/* Begin PBXBuildFile section */
		14068F05168A001400FA0A02 /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 14068F04168A001400FA0A02 /* UIKit.framework */; };
		14068F07168A001400FA0A02 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 14068F06168A001400FA0A02 /* Foundation.framework */; };
		14068F09168A001400FA0A02 /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 14068F08168A001400FA0A02 /* CoreGraphics.framework */; };
		14068F0F168A001400FA0A02 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 14068F0D168A001400FA0A02 /* InfoPlist.strings */; };
		14068F11168A001400FA0A02 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 14068F10168A001400FA0A02 /* main.m */; };
		14068F15168A001400FA0A02 /* SRAppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 14068F14168A001400FA0A02 /* SRAppDelegate.m */; };
		14068F17168A001400FA0A02 /* Default.png in Resources */ = {isa = PBXBuildFile; fileRef = 14068F16168A001400FA0A02 /* Default.png */; };
		14068F19168A001400FA0A02 /* Default@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 14068F18168A001400FA0A02 /* Default@2x.png */; };
		14068F1B168A001400FA0A02 /* Default-568h@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 14068F1A168A001400FA0A02 /* Default-568h@2x.png */; };
		14068F1E168A001400FA0A02 /* MainStoryboard.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 14068F1C168A001400FA0A02 /* MainStoryboard.storyboard */; };
		14068F21168A001400FA0A02 /* SRMasterViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 14068F20168A001400FA0A02 /* SRMasterViewController.m */; };
		14068F24168A001400FA0A02 /* SRDetailViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 14068F23168A001400FA0A02 /* SRDetailViewController.m */; };
		14068F2F168A01B100FA0A02 /* KTouchPointerWindow.m in Sources */ = {isa = PBXBuildFile; fileRef = 14068F2E168A01B100FA0A02 /* KTouchPointerWindow.m */; };
		14068F31168A02B300FA0A02 /* AVFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 14068F30168A02B300FA0A02 /* AVFoundation.framework */; };
		14068F37168A13DA00FA0A02 /* CoreMedia.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 14068F36168A13DA00FA0A02 /* CoreMedia.framework */; };
		14068F39168A13E200FA0A02 /* CoreVideo.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 14068F38168A13E100FA0A02 /* CoreVideo.framework */; };
		14068F3B168A13F800FA0A02 /* QuartzCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 14068F3A168A13F800FA0A02 /* QuartzCore.framework */; };
		14FD26F3168E3C3F005DFD21 /* SRScreenRecorder.m in Sources */ = {isa = PBXBuildFile; fileRef = 14FD26F2168E3C3F005DFD21 /* SRScreenRecorder.m */; };
/* End PBXBuildFile section */

/* Begin PBXFileReference section */
		14068F00168A001400FA0A02 /* ScreenRecorder.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = ScreenRecorder.app; sourceTree = BUILT_PRODUCTS_DIR; };
		14068F04168A001400FA0A02 /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; };
		14068F06168A001400FA0A02 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; };
		14068F08168A001400FA0A02 /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = System/Library/Frameworks/CoreGraphics.framework; sourceTree = SDKROOT; };
		14068F0C168A001400FA0A02 /* ScreenRecorder-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "ScreenRecorder-Info.plist"; sourceTree = "<group>"; };
		14068F0E168A001400FA0A02 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = "<group>"; };
		14068F10168A001400FA0A02 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = "<group>"; };
		14068F12168A001400FA0A02 /* ScreenRecorder-Prefix.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "ScreenRecorder-Prefix.pch"; sourceTree = "<group>"; };
		14068F13168A001400FA0A02 /* SRAppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SRAppDelegate.h; sourceTree = "<group>"; };
		14068F14168A001400FA0A02 /* SRAppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SRAppDelegate.m; sourceTree = "<group>"; };
		14068F16168A001400FA0A02 /* Default.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = Default.png; sourceTree = "<group>"; };
		14068F18168A001400FA0A02 /* Default@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "Default@2x.png"; sourceTree = "<group>"; };
		14068F1A168A001400FA0A02 /* Default-568h@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "Default-568h@2x.png"; sourceTree = "<group>"; };
		14068F1D168A001400FA0A02 /* en */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = en; path = en.lproj/MainStoryboard.storyboard; sourceTree = "<group>"; };
		14068F1F168A001400FA0A02 /* SRMasterViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SRMasterViewController.h; sourceTree = "<group>"; };
		14068F20168A001400FA0A02 /* SRMasterViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SRMasterViewController.m; sourceTree = "<group>"; };
		14068F22168A001400FA0A02 /* SRDetailViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SRDetailViewController.h; sourceTree = "<group>"; };
		14068F23168A001400FA0A02 /* SRDetailViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SRDetailViewController.m; sourceTree = "<group>"; };
		14068F2D168A01B100FA0A02 /* KTouchPointerWindow.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = KTouchPointerWindow.h; path = Vendor/KTouchPointerWindow.h; sourceTree = SOURCE_ROOT; };
		14068F2E168A01B100FA0A02 /* KTouchPointerWindow.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = KTouchPointerWindow.m; path = Vendor/KTouchPointerWindow.m; sourceTree = SOURCE_ROOT; };
		14068F30168A02B300FA0A02 /* AVFoundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AVFoundation.framework; path = System/Library/Frameworks/AVFoundation.framework; sourceTree = SDKROOT; };
		14068F36168A13DA00FA0A02 /* CoreMedia.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreMedia.framework; path = System/Library/Frameworks/CoreMedia.framework; sourceTree = SDKROOT; };
		14068F38168A13E100FA0A02 /* CoreVideo.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreVideo.framework; path = System/Library/Frameworks/CoreVideo.framework; sourceTree = SDKROOT; };
		14068F3A168A13F800FA0A02 /* QuartzCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = QuartzCore.framework; path = System/Library/Frameworks/QuartzCore.framework; sourceTree = SDKROOT; };
		14FD26F1168E3C3F005DFD21 /* SRScreenRecorder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SRScreenRecorder.h; path = Lib/SRScreenRecorder.h; sourceTree = SOURCE_ROOT; };
		14FD26F2168E3C3F005DFD21 /* SRScreenRecorder.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = SRScreenRecorder.m; path = Lib/SRScreenRecorder.m; sourceTree = SOURCE_ROOT; };
/* End PBXFileReference section */

/* Begin PBXFrameworksBuildPhase section */
		14068EFD168A001400FA0A02 /* Frameworks */ = {
			isa = PBXFrameworksBuildPhase;
			buildActionMask = 2147483647;
			files = (
				14068F05168A001400FA0A02 /* UIKit.framework in Frameworks */,
				14068F07168A001400FA0A02 /* Foundation.framework in Frameworks */,
				14068F09168A001400FA0A02 /* CoreGraphics.framework in Frameworks */,
				14068F3B168A13F800FA0A02 /* QuartzCore.framework in Frameworks */,
				14068F39168A13E200FA0A02 /* CoreVideo.framework in Frameworks */,
				14068F37168A13DA00FA0A02 /* CoreMedia.framework in Frameworks */,
				14068F31168A02B300FA0A02 /* AVFoundation.framework in Frameworks */,
			);
			runOnlyForDeploymentPostprocessing = 0;
		};
/* End PBXFrameworksBuildPhase section */

/* Begin PBXGroup section */
		14068EF5168A001400FA0A02 = {
			isa = PBXGroup;
			children = (
				14068F0A168A001400FA0A02 /* ScreenRecorder */,
				14068F03168A001400FA0A02 /* Frameworks */,
				14068F01168A001400FA0A02 /* Products */,
			);
			sourceTree = "<group>";
		};
		14068F01168A001400FA0A02 /* Products */ = {
			isa = PBXGroup;
			children = (
				14068F00168A001400FA0A02 /* ScreenRecorder.app */,
			);
			name = Products;
			sourceTree = "<group>";
		};
		14068F03168A001400FA0A02 /* Frameworks */ = {
			isa = PBXGroup;
			children = (
				14068F04168A001400FA0A02 /* UIKit.framework */,
				14068F06168A001400FA0A02 /* Foundation.framework */,
				14068F08168A001400FA0A02 /* CoreGraphics.framework */,
				14068F3A168A13F800FA0A02 /* QuartzCore.framework */,
				14068F38168A13E100FA0A02 /* CoreVideo.framework */,
				14068F36168A13DA00FA0A02 /* CoreMedia.framework */,
				14068F30168A02B300FA0A02 /* AVFoundation.framework */,
			);
			name = Frameworks;
			sourceTree = "<group>";
		};
		14068F0A168A001400FA0A02 /* ScreenRecorder */ = {
			isa = PBXGroup;
			children = (
				14FD26F4168E3C48005DFD21 /* Lib */,
				14FD26F5168E3C4F005DFD21 /* Vendor */,
				14FD26F6168E3C57005DFD21 /* Demo App */,
				14068F0B168A001400FA0A02 /* Supporting Files */,
			);
			path = ScreenRecorder;
			sourceTree = "<group>";
		};
		14068F0B168A001400FA0A02 /* Supporting Files */ = {
			isa = PBXGroup;
			children = (
				14068F0C168A001400FA0A02 /* ScreenRecorder-Info.plist */,
				14068F0D168A001400FA0A02 /* InfoPlist.strings */,
				14068F10168A001400FA0A02 /* main.m */,
				14068F12168A001400FA0A02 /* ScreenRecorder-Prefix.pch */,
				14068F16168A001400FA0A02 /* Default.png */,
				14068F18168A001400FA0A02 /* Default@2x.png */,
				14068F1A168A001400FA0A02 /* Default-568h@2x.png */,
			);
			name = "Supporting Files";
			sourceTree = "<group>";
		};
		14FD26F4168E3C48005DFD21 /* Lib */ = {
			isa = PBXGroup;
			children = (
				14FD26F1168E3C3F005DFD21 /* SRScreenRecorder.h */,
				14FD26F2168E3C3F005DFD21 /* SRScreenRecorder.m */,
			);
			name = Lib;
			sourceTree = "<group>";
		};
		14FD26F5168E3C4F005DFD21 /* Vendor */ = {
			isa = PBXGroup;
			children = (
				14068F2D168A01B100FA0A02 /* KTouchPointerWindow.h */,
				14068F2E168A01B100FA0A02 /* KTouchPointerWindow.m */,
			);
			name = Vendor;
			sourceTree = "<group>";
		};
		14FD26F6168E3C57005DFD21 /* Demo App */ = {
			isa = PBXGroup;
			children = (
				14068F13168A001400FA0A02 /* SRAppDelegate.h */,
				14068F14168A001400FA0A02 /* SRAppDelegate.m */,
				14068F1F168A001400FA0A02 /* SRMasterViewController.h */,
				14068F20168A001400FA0A02 /* SRMasterViewController.m */,
				14068F22168A001400FA0A02 /* SRDetailViewController.h */,
				14068F23168A001400FA0A02 /* SRDetailViewController.m */,
				14068F1C168A001400FA0A02 /* MainStoryboard.storyboard */,
			);
			name = "Demo App";
			sourceTree = "<group>";
		};
/* End PBXGroup section */

/* Begin PBXNativeTarget section */
		14068EFF168A001400FA0A02 /* ScreenRecorder */ = {
			isa = PBXNativeTarget;
			buildConfigurationList = 14068F27168A001400FA0A02 /* Build configuration list for PBXNativeTarget "ScreenRecorder" */;
			buildPhases = (
				14068EFC168A001400FA0A02 /* Sources */,
				14068EFD168A001400FA0A02 /* Frameworks */,
				14068EFE168A001400FA0A02 /* Resources */,
			);
			buildRules = (
			);
			dependencies = (
			);
			name = ScreenRecorder;
			productName = ScreenRecorder;
			productReference = 14068F00168A001400FA0A02 /* ScreenRecorder.app */;
			productType = "com.apple.product-type.application";
		};
/* End PBXNativeTarget section */

/* Begin PBXProject section */
		14068EF7168A001400FA0A02 /* Project object */ = {
			isa = PBXProject;
			attributes = {
				CLASSPREFIX = SR;
				LastUpgradeCheck = 0900;
				ORGANIZATIONNAME = "kishikawa katsumi";
				TargetAttributes = {
					14068EFF168A001400FA0A02 = {
						DevelopmentTeam = 27AEDK3C9F;
					};
				};
			};
			buildConfigurationList = 14068EFA168A001400FA0A02 /* Build configuration list for PBXProject "ScreenRecorder" */;
			compatibilityVersion = "Xcode 3.2";
			developmentRegion = English;
			hasScannedForEncodings = 0;
			knownRegions = (
				en,
			);
			mainGroup = 14068EF5168A001400FA0A02;
			productRefGroup = 14068F01168A001400FA0A02 /* Products */;
			projectDirPath = "";
			projectRoot = "";
			targets = (
				14068EFF168A001400FA0A02 /* ScreenRecorder */,
			);
		};
/* End PBXProject section */

/* Begin PBXResourcesBuildPhase section */
		14068EFE168A001400FA0A02 /* Resources */ = {
			isa = PBXResourcesBuildPhase;
			buildActionMask = 2147483647;
			files = (
				14068F0F168A001400FA0A02 /* InfoPlist.strings in Resources */,
				14068F17168A001400FA0A02 /* Default.png in Resources */,
				14068F19168A001400FA0A02 /* Default@2x.png in Resources */,
				14068F1B168A001400FA0A02 /* Default-568h@2x.png in Resources */,
				14068F1E168A001400FA0A02 /* MainStoryboard.storyboard in Resources */,
			);
			runOnlyForDeploymentPostprocessing = 0;
		};
/* End PBXResourcesBuildPhase section */

/* Begin PBXSourcesBuildPhase section */
		14068EFC168A001400FA0A02 /* Sources */ = {
			isa = PBXSourcesBuildPhase;
			buildActionMask = 2147483647;
			files = (
				14068F11168A001400FA0A02 /* main.m in Sources */,
				14068F15168A001400FA0A02 /* SRAppDelegate.m in Sources */,
				14068F21168A001400FA0A02 /* SRMasterViewController.m in Sources */,
				14068F24168A001400FA0A02 /* SRDetailViewController.m in Sources */,
				14068F2F168A01B100FA0A02 /* KTouchPointerWindow.m in Sources */,
				14FD26F3168E3C3F005DFD21 /* SRScreenRecorder.m in Sources */,
			);
			runOnlyForDeploymentPostprocessing = 0;
		};
/* End PBXSourcesBuildPhase section */

/* Begin PBXVariantGroup section */
		14068F0D168A001400FA0A02 /* InfoPlist.strings */ = {
			isa = PBXVariantGroup;
			children = (
				14068F0E168A001400FA0A02 /* en */,
			);
			name = InfoPlist.strings;
			sourceTree = "<group>";
		};
		14068F1C168A001400FA0A02 /* MainStoryboard.storyboard */ = {
			isa = PBXVariantGroup;
			children = (
				14068F1D168A001400FA0A02 /* en */,
			);
			name = MainStoryboard.storyboard;
			sourceTree = "<group>";
		};
/* End PBXVariantGroup section */

/* Begin XCBuildConfiguration section */
		14068F25168A001400FA0A02 /* Debug */ = {
			isa = XCBuildConfiguration;
			buildSettings = {
				ALWAYS_SEARCH_USER_PATHS = NO;
				CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
				CLANG_CXX_LIBRARY = "libc++";
				CLANG_ENABLE_OBJC_ARC = YES;
				CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
				CLANG_WARN_BOOL_CONVERSION = YES;
				CLANG_WARN_COMMA = YES;
				CLANG_WARN_CONSTANT_CONVERSION = YES;
				CLANG_WARN_EMPTY_BODY = YES;
				CLANG_WARN_ENUM_CONVERSION = YES;
				CLANG_WARN_INFINITE_RECURSION = YES;
				CLANG_WARN_INT_CONVERSION = YES;
				CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
				CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
				CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
				CLANG_WARN_STRICT_PROTOTYPES = YES;
				CLANG_WARN_SUSPICIOUS_MOVE = YES;
				CLANG_WARN_UNREACHABLE_CODE = YES;
				CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
				"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
				COPY_PHASE_STRIP = NO;
				ENABLE_STRICT_OBJC_MSGSEND = YES;
				ENABLE_TESTABILITY = YES;
				GCC_C_LANGUAGE_STANDARD = gnu99;
				GCC_DYNAMIC_NO_PIC = NO;
				GCC_NO_COMMON_BLOCKS = YES;
				GCC_OPTIMIZATION_LEVEL = 0;
				GCC_PREPROCESSOR_DEFINITIONS = (
					"DEBUG=1",
					"$(inherited)",
				);
				GCC_SYMBOLS_PRIVATE_EXTERN = NO;
				GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
				GCC_WARN_ABOUT_RETURN_TYPE = YES;
				GCC_WARN_UNDECLARED_SELECTOR = YES;
				GCC_WARN_UNINITIALIZED_AUTOS = YES;
				GCC_WARN_UNUSED_FUNCTION = YES;
				GCC_WARN_UNUSED_VARIABLE = YES;
				IPHONEOS_DEPLOYMENT_TARGET = 8.0;
				ONLY_ACTIVE_ARCH = YES;
				SDKROOT = iphoneos;
			};
			name = Debug;
		};
		14068F26168A001400FA0A02 /* Release */ = {
			isa = XCBuildConfiguration;
			buildSettings = {
				ALWAYS_SEARCH_USER_PATHS = NO;
				CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
				CLANG_CXX_LIBRARY = "libc++";
				CLANG_ENABLE_OBJC_ARC = YES;
				CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
				CLANG_WARN_BOOL_CONVERSION = YES;
				CLANG_WARN_COMMA = YES;
				CLANG_WARN_CONSTANT_CONVERSION = YES;
				CLANG_WARN_EMPTY_BODY = YES;
				CLANG_WARN_ENUM_CONVERSION = YES;
				CLANG_WARN_INFINITE_RECURSION = YES;
				CLANG_WARN_INT_CONVERSION = YES;
				CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
				CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
				CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
				CLANG_WARN_STRICT_PROTOTYPES = YES;
				CLANG_WARN_SUSPICIOUS_MOVE = YES;
				CLANG_WARN_UNREACHABLE_CODE = YES;
				CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
				"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
				COPY_PHASE_STRIP = YES;
				ENABLE_STRICT_OBJC_MSGSEND = YES;
				GCC_C_LANGUAGE_STANDARD = gnu99;
				GCC_NO_COMMON_BLOCKS = YES;
				GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
				GCC_WARN_ABOUT_RETURN_TYPE = YES;
				GCC_WARN_UNDECLARED_SELECTOR = YES;
				GCC_WARN_UNINITIALIZED_AUTOS = YES;
				GCC_WARN_UNUSED_FUNCTION = YES;
				GCC_WARN_UNUSED_VARIABLE = YES;
				IPHONEOS_DEPLOYMENT_TARGET = 8.0;
				OTHER_CFLAGS = "-DNS_BLOCK_ASSERTIONS=1";
				SDKROOT = iphoneos;
				VALIDATE_PRODUCT = YES;
			};
			name = Release;
		};
		14068F28168A001400FA0A02 /* Debug */ = {
			isa = XCBuildConfiguration;
			buildSettings = {
				DEVELOPMENT_TEAM = 27AEDK3C9F;
				GCC_PRECOMPILE_PREFIX_HEADER = YES;
				GCC_PREFIX_HEADER = "ScreenRecorder/ScreenRecorder-Prefix.pch";
				INFOPLIST_FILE = "ScreenRecorder/ScreenRecorder-Info.plist";
				IPHONEOS_DEPLOYMENT_TARGET = 8.0;
				PRODUCT_BUNDLE_IDENTIFIER = "com.kishikawakatsumi.${PRODUCT_NAME:rfc1034identifier}";
				PRODUCT_NAME = "$(TARGET_NAME)";
				WRAPPER_EXTENSION = app;
			};
			name = Debug;
		};
		14068F29168A001400FA0A02 /* Release */ = {
			isa = XCBuildConfiguration;
			buildSettings = {
				DEVELOPMENT_TEAM = 27AEDK3C9F;
				GCC_PRECOMPILE_PREFIX_HEADER = YES;
				GCC_PREFIX_HEADER = "ScreenRecorder/ScreenRecorder-Prefix.pch";
				INFOPLIST_FILE = "ScreenRecorder/ScreenRecorder-Info.plist";
				IPHONEOS_DEPLOYMENT_TARGET = 8.0;
				PRODUCT_BUNDLE_IDENTIFIER = "com.kishikawakatsumi.${PRODUCT_NAME:rfc1034identifier}";
				PRODUCT_NAME = "$(TARGET_NAME)";
				WRAPPER_EXTENSION = app;
			};
			name = Release;
		};
/* End XCBuildConfiguration section */

/* Begin XCConfigurationList section */
		14068EFA168A001400FA0A02 /* Build configuration list for PBXProject "ScreenRecorder" */ = {
			isa = XCConfigurationList;
			buildConfigurations = (
				14068F25168A001400FA0A02 /* Debug */,
				14068F26168A001400FA0A02 /* Release */,
			);
			defaultConfigurationIsVisible = 0;
			defaultConfigurationName = Release;
		};
		14068F27168A001400FA0A02 /* Build configuration list for PBXNativeTarget "ScreenRecorder" */ = {
			isa = XCConfigurationList;
			buildConfigurations = (
				14068F28168A001400FA0A02 /* Debug */,
				14068F29168A001400FA0A02 /* Release */,
			);
			defaultConfigurationIsVisible = 0;
			defaultConfigurationName = Release;
		};
/* End XCConfigurationList section */
	};
	rootObject = 14068EF7168A001400FA0A02 /* Project object */;
}


================================================
FILE: Vendor/KTouchPointerWindow.h
================================================
//
//  KTouchPointerWindow.h
//
//  Created by Ito Kei on 12/03/02.
//  Copyright (c) 2012 itok. All rights reserved.
//
/*
 * call this function to start show pointer
 * 
 * ex)
 * - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
 *      KTouchPointerWindowInstall();
 *      ...
 * }
 */
void KTouchPointerWindowInstall(void);
void KTouchPointerWindowUninstall(void);


================================================
FILE: Vendor/KTouchPointerWindow.m
================================================
//
//  TouchWindow.m
//
//  Created by Ito Kei on 12/03/02.
//  Copyright (c) 2012 itok. All rights reserved.
//

#import "KTouchPointerWindow.h"
#import <UIKit/UIKit.h>
#import <objc/runtime.h>

static BOOL installed;

void KTouchPointerWindowInstall() 
{
	if (!installed) {
		installed = YES;
		
		Class _class = [UIWindow class];
		
		Method orig = class_getInstanceMethod(_class, sel_registerName("sendEvent:"));
		Method my = class_getInstanceMethod(_class, sel_registerName("k_sendEvent:"));
		method_exchangeImplementations(orig, my);
	}
}

void KTouchPointerWindowUninstall()
{
	if (installed) {
		installed = NO;
		
		Class _class = [UIWindow class];
		
		Method orig = class_getInstanceMethod(_class, sel_registerName("sendEvent:"));
		Method my = class_getInstanceMethod(_class, sel_registerName("k_sendEvent:"));
		method_exchangeImplementations(orig, my);
        
        NSArray *windows = [[UIApplication sharedApplication] windows];
        [windows makeObjectsPerformSelector:@selector(setNeedsDisplay)];
	}
}

static char s_key;

@interface __KTouchPointerView : UIView

@property (nonatomic, retain) NSSet *touches;

@end

@interface UIWindow (KTouchPointerWindow)

@property (nonatomic, retain) __KTouchPointerView* k_touchPointerView;

@end

@implementation UIWindow (KTouchPointerWindow)

- (__KTouchPointerView*) k_touchPointerView
{
	return objc_getAssociatedObject(self, &s_key);
}

-(void) setK_touchPointerView:(__KTouchPointerView *)value
{
	objc_setAssociatedObject(self, &s_key, value, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}

-(void) k_sendEvent:(UIEvent *)event
{
	if (!self.k_touchPointerView) {
		self.k_touchPointerView = [[__KTouchPointerView alloc] initWithFrame:self.bounds];
		self.k_touchPointerView.backgroundColor = [UIColor clearColor];
		self.k_touchPointerView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
		self.k_touchPointerView.userInteractionEnabled = NO;
		[self addSubview:self.k_touchPointerView];
	}
	
	[self bringSubviewToFront:self.k_touchPointerView];
	
	NSMutableSet *began = nil;
	NSMutableSet *moved = nil;
	NSMutableSet *ended = nil;
	NSMutableSet *cancelled = nil;
	for (UITouch *touch in [event allTouches]) {
		switch (touch.phase) {
			case UITouchPhaseBegan:
				if (!began) {
					began = [NSMutableSet set];
				}
				[began addObject:touch];
				break;
			case UITouchPhaseEnded:
				if (!ended) {
					ended = [NSMutableSet set];
				}
				[ended addObject:touch];
				break;
			case UITouchPhaseCancelled:
				if (!cancelled) {
					cancelled = [NSMutableSet set];
				}
				[cancelled addObject:touch];
				break;
			case UITouchPhaseMoved:
				if (!moved) {
					moved = [NSMutableSet set];
				}
				[moved addObject:touch];
				break;
			default:
				break;
		}
	}
	if (began) {
		[self.k_touchPointerView touchesBegan:began withEvent:event];
	}
	if (moved) {
		[self.k_touchPointerView touchesMoved:moved withEvent:event];
	}
	if (ended) {
		[self.k_touchPointerView touchesEnded:ended withEvent:event];
	}
	if (cancelled) {
		[self.k_touchPointerView touchesCancelled:cancelled withEvent:event];
	}
	[self k_sendEvent:event];
}

@end

@implementation __KTouchPointerView

@synthesize touches;

- (void)drawRect:(CGRect)rect
{
	for (UITouch* touch in self.touches) {
		CGRect touchRect = CGRectZero;
		touchRect.origin = [touch locationInView:self];
		UIBezierPath* bp = [UIBezierPath bezierPathWithOvalInRect:CGRectInset(touchRect, -10, -10)];
		[[UIColor colorWithRed:1 green:0 blue:0 alpha:0.6] set];
		[bp fill];
	}
}

- (void)touchesBegan:(NSSet *)_touches withEvent:(UIEvent *)event
{
	self.touches = _touches;
	[self setNeedsDisplay];
}

- (void)touchesMoved:(NSSet *)_touches withEvent:(UIEvent *)event
{
	self.touches = _touches;
	[self setNeedsDisplay];	
}

- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event
{
	self.touches = nil;
	[self setNeedsDisplay];	
}

- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
	self.touches = nil;
	[self setNeedsDisplay];
}

@end
Download .txt
gitextract_yulxgphk/

├── .gitignore
├── LICENSE
├── Lib/
│   ├── SRScreenRecorder.h
│   └── SRScreenRecorder.m
├── README.md
├── ScreenRecorder/
│   ├── SRAppDelegate.h
│   ├── SRAppDelegate.m
│   ├── SRDetailViewController.h
│   ├── SRDetailViewController.m
│   ├── SRMasterViewController.h
│   ├── SRMasterViewController.m
│   ├── ScreenRecorder-Info.plist
│   ├── ScreenRecorder-Prefix.pch
│   ├── en.lproj/
│   │   ├── InfoPlist.strings
│   │   └── MainStoryboard.storyboard
│   └── main.m
├── ScreenRecorder.xcodeproj/
│   └── project.pbxproj
└── Vendor/
    ├── KTouchPointerWindow.h
    └── KTouchPointerWindow.m
Download .txt
SYMBOL INDEX (1 symbols across 1 files)

FILE: Lib/SRScreenRecorder.h
  type NSString (line 13) | typedef NSString *(^SRScreenRecorderOutputFilenameBlock)(void);
Condensed preview — 19 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (62K chars).
[
  {
    "path": ".gitignore",
    "chars": 232,
    "preview": "# Xcode\n.DS_Store\nbuild/\n*.pbxuser\n!default.pbxuser\n*.mode1v3\n!default.mode1v3\n*.mode2v3\n!default.mode2v3\n*.perspectivev"
  },
  {
    "path": "LICENSE",
    "chars": 1091,
    "preview": "Copyright (c) 2012 kishikawa katsumi (http://kishikawakatsumi.com/)\n\nPermission is hereby granted, free of charge, to an"
  },
  {
    "path": "Lib/SRScreenRecorder.h",
    "chars": 861,
    "preview": "//\n//  SRScreenRecorder.h\n//  ScreenRecorder\n//\n//  Created by kishikawa katsumi on 2012/12/26.\n//  Copyright (c) 2012年 "
  },
  {
    "path": "Lib/SRScreenRecorder.m",
    "chars": 12552,
    "preview": "//\n//  SRScreenRecorder.m\n//  ScreenRecorder\n//\n//  Created by kishikawa katsumi on 2012/12/26.\n//  Copyright (c) 2012年 "
  },
  {
    "path": "README.md",
    "chars": 2147,
    "preview": "ScreenRecorder\n==============\nCapturing a screen as videos on iOS devices for user testing.\n\n## Features\n* Screen captur"
  },
  {
    "path": "ScreenRecorder/SRAppDelegate.h",
    "chars": 303,
    "preview": "//\n//  SRAppDelegate.h\n//  ScreenRecorder\n//\n//  Created by kishikawa katsumi on 2012/12/26.\n//  Copyright (c) 2012 kish"
  },
  {
    "path": "ScreenRecorder/SRAppDelegate.m",
    "chars": 542,
    "preview": "//\n//  SRAppDelegate.m\n//  ScreenRecorder\n//\n//  Created by kishikawa katsumi on 2012/12/26.\n//  Copyright (c) 2012 kish"
  },
  {
    "path": "ScreenRecorder/SRDetailViewController.h",
    "chars": 369,
    "preview": "//\n//  SRDetailViewController.h\n//  ScreenRecorder\n//\n//  Created by kishikawa katsumi on 2012/12/26.\n//  Copyright (c) "
  },
  {
    "path": "ScreenRecorder/SRDetailViewController.m",
    "chars": 813,
    "preview": "//\n//  SRDetailViewController.m\n//  ScreenRecorder\n//\n//  Created by kishikawa katsumi on 2012/12/26.\n//  Copyright (c) "
  },
  {
    "path": "ScreenRecorder/SRMasterViewController.h",
    "chars": 258,
    "preview": "//\n//  SRMasterViewController.h\n//  ScreenRecorder\n//\n//  Created by kishikawa katsumi on 2012/12/26.\n//  Copyright (c) "
  },
  {
    "path": "ScreenRecorder/SRMasterViewController.m",
    "chars": 3160,
    "preview": "//\n//  SRMasterViewController.m\n//  ScreenRecorder\n//\n//  Created by kishikawa katsumi on 2012/12/26.\n//  Copyright (c) "
  },
  {
    "path": "ScreenRecorder/ScreenRecorder-Info.plist",
    "chars": 1416,
    "preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/P"
  },
  {
    "path": "ScreenRecorder/ScreenRecorder-Prefix.pch",
    "chars": 331,
    "preview": "//\n// Prefix header for all source files of the 'ScreenRecorder' target in the 'ScreenRecorder' project\n//\n\n#import <Ava"
  },
  {
    "path": "ScreenRecorder/en.lproj/InfoPlist.strings",
    "chars": 80,
    "preview": "/* Localized versions of Info.plist keys */\n\"CFBundleDisplayName\" = \"Recorder\";\n"
  },
  {
    "path": "ScreenRecorder/en.lproj/MainStoryboard.storyboard",
    "chars": 7909,
    "preview": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n<document type=\"com.apple.InterfaceBuilder3.CocoaTouch.Storyboard"
  },
  {
    "path": "ScreenRecorder/main.m",
    "chars": 362,
    "preview": "//\n//  main.m\n//  ScreenRecorder\n//\n//  Created by kishikawa katsumi on 2012/12/26.\n//  Copyright (c) 2012 kishikawa kat"
  },
  {
    "path": "ScreenRecorder.xcodeproj/project.pbxproj",
    "chars": 20048,
    "preview": "// !$*UTF8*$!\n{\n\tarchiveVersion = 1;\n\tclasses = {\n\t};\n\tobjectVersion = 46;\n\tobjects = {\n\n/* Begin PBXBuildFile section *"
  },
  {
    "path": "Vendor/KTouchPointerWindow.h",
    "chars": 432,
    "preview": "//\n//  KTouchPointerWindow.h\n//\n//  Created by Ito Kei on 12/03/02.\n//  Copyright (c) 2012 itok. All rights reserved.\n//"
  },
  {
    "path": "Vendor/KTouchPointerWindow.m",
    "chars": 4027,
    "preview": "//\n//  TouchWindow.m\n//\n//  Created by Ito Kei on 12/03/02.\n//  Copyright (c) 2012 itok. All rights reserved.\n//\n\n#impor"
  }
]

About this extraction

This page contains the full source code of the kishikawakatsumi/ScreenRecorder GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 19 files (55.6 KB), approximately 15.5k tokens, and a symbol index with 1 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!