18/05/2013

Bind edit shortcuts cho chương trình Mac OS X

Lập trình Mac OS X, ai cũng biết rằng để bind các edit shortcuts như Cmd-C, Cmd-V, Cmd-A, ... cho chương trình chúng ta thường sử dụng built-in Edit menu. Tuy nhiên trong vài trường hợp chúng ta cần customize menu bar nên không có built-in Edit menu trên menu bar. Trong trường hợp này chúng ta thực hiện theo phương pháp sau:

  1. Kế thừa NSApplication, tạo lớp CustomApplication:
    • CustomApplication.h:
      @interface CustomApplication:NSApplication
      @end
    • CustomApplication.m
      @implementation CustomApplication
      - (void) sendEvent:(NSEvent *)event {
          if ([event type] == NSKeyDown) {
              if (([event modifierFlags] & NSDeviceIndependentModifierFlagsMask) == NSCommandKeyMask) {
                  if ([[event charactersIgnoringModifiers] isEqualToString:@"x"]) {
                      if ([self sendAction:@selector(cut:) to:nil from:self])
                          return;
                  }
                  else if ([[event charactersIgnoringModifiers] isEqualToString:@"c"]) {
                      if ([self sendAction:@selector(copy:) to:nil from:self])
                          return;
                  }
                  else if ([[event charactersIgnoringModifiers] isEqualToString:@"v"]) {
                      if ([self sendAction:@selector(paste:) to:nil from:self])
                          return;
                  }
                  else if ([[event charactersIgnoringModifiers] isEqualToString:@"z"]) {
                      if ([self sendAction:@selector(undo:) to:nil from:self])
                          return;
                  }
                  else if ([[event charactersIgnoringModifiers] isEqualToString:@"a"]) {
                      if ([self sendAction:@selector(selectAll:) to:nil from:self])
                          return;
                  }
              }
              else if (([event modifierFlags] & NSDeviceIndependentModifierFlagsMask) == (NSCommandKeyMask | NSShiftKeyMask)) {
                  if ([[event charactersIgnoringModifiers] isEqualToString:@"Z"]) {
                      if ([self sendAction:@selector(redo:) to:nil from:self])
                          return;
                  }
              }
          }
          [super sendEvent:event];
      }
      @end
  2. Thay đổi NSApplication thành CustomApplication trong mục Principal Class ở Target properties.
       

11/05/2013

Lưu ý khi dùng NSColor trong MAC OS X programming

Trong khi lập trình MAC OS X bạn sẽ gặp phải vấn đề sau đây:
Khách hàng đưa cho bạn màu sắc của một bản thiết kế nào đó dạng chuỗi HTML RGB ví dụ: 6F5A4E và yêu cầu bạn đưa lên màn hình. Thông thường bạn sẽ làm như sau:
Tạo category cho NSColor để thêm phương thức tạo NSColor từ chuỗi HTMLRGB:
  • Tạo file NSColor+Ext.h:
       @interface NSColor(Ext)
       +(NSColor*) newColorFromRGBString:(NSString*) rgb;
      @end
    
  • Tạo file NSColor+Ext.m
    @implementation NSColor(Ext)
        +(NSColor*) newColorFromRGBString:(NSString*) rgb{
    
            NSColor*result= nil;
    
            unsigned colorValue=0;
    
            unsigned char  r,g, b;
        if (nil != rgb)
        {
             NSScanner* scanner = [NSScanner scannerWithString:rgb];
              // ignore error
             (void) [scanner scanHexInt:&colorValue];
        }
        r = (unsigned char)(colorValue >> 16);
        g = (unsigned char)(colorValue >> 8);
        // masks off high bits
        b = (unsigned char)(colorValue);
        result = [NSColor colorWithCalibratedRed:(CGFloat)r / 0xff green:(CGFloat)g / 0xff blue:(CGFloat)b / 0xff alpha:1.0f];
        return result;
       }
    @end
    
Đoạn code trên có vấn đề ở chỗ là chúng ta sử dụng phương thức colorWithCalibratedRed:green: blue:, màu sắc hiện lên trên màn hình chỉ đúng khi người dùng chọn Generic RGB Profile trong System Preferences > Display > Color. Nếu người dùng chọn color profile khác thì màu sắc hiện lên màn hình không như bạn mong đợi. Bạn có thể sử dụng công cụ đo màu (color picker) để kiểm chứng điều này.
Sau đây mình sẽ trình bày phương pháp để giải quyết vấn đề này bằng ColorSync Manager API (Xem thêm tài liệu Technical Q&A QA1396):
  1. Khai property colorSpace trong AppDelegate.h:
    @interface AppDelegate:NSObject
    @property (strong) NSColorSpace*colorSpace;
    @end
    
  2. Trong AppDelegate.m Private category:
    #import <ApplicationServices/ApplicationServices.h>
    @interface AppDelegate()
    +(CGColorSpaceRef)CreateDisplayColorSpace;
    -(void)updateColorSpace;
    -(void)registerNotifications;
    @end
    @implementation AppDelegate
    //Disable deprecated warning
    #pragma GCC diagnostic ignored "-Wdeprecated-declarations"
    +(CGColorSpaceRef)CreateDisplayColorSpace{
    CMProfileRef sysprof = NULL;
        CGColorSpaceRef dispColorSpace = NULL;
    
        // Get the Systems Profile for the main display
        if (CMGetSystemProfile(&sysprof) == noErr)
        {
            // Create a colorspace with the systems profile
            dispColorSpace = CGColorSpaceCreateWithPlatformColorSpace(sysprof);
    
            // Close the profile
            CMCloseProfile(sysprof);
        }
    
        return dispColorSpace;
    }
    //Enable deprecated warning
    #pragma GCC diagnostic warning "-Wdeprecated-declarations"
    -(void)registerNotifications
    {
        NSDistributedNotificationCenter *center;
    
        center = [NSDistributedNotificationCenter defaultCenter];
    
        [center addObserver:self
                   selector:@selector(updateColorSpace)
                       name:kCMDeviceUnregisteredNotification
                     object:nil];
        [center addObserver:self
                   selector:@selector(updateColorSpace)
                       name:kCMDefaultDeviceNotification
                     object:nil];
        [center addObserver:self
                   selector:@selector(updateColorSpace)
                       name:kCMDeviceProfilesNotification
                     object:nil];
        [center addObserver:self
                   selector:@selector(updateColorSpace)
                       name:kCMDefaultDeviceProfileNotification
                     object:nil];
    }
    -(void)updateColorSpace{
     CGColorSpaceRef csr = [AppDelegate CreateDisplayColorSpace];
     self.colorSpace = [[NSColorSpace alloc] initWithCGColorSpace:csr];
    CGColorSpaceRelease(csr);
    }
    - (void)applicationWillFinishLaunching:(NSNotification *)aNotification{
    [self registerNotifications];
    [self updateColorSpace];
    } @end
  3. Nhiệm vụ cuối cùng là thay đổi cách viết NSColor+Ext ở trên dùng property colorSpace trong lớp AppDelegate:
        @implementation NSColor(Ext)
        +(NSColor*) newColorFromRGBString:(NSString*) rgb{
             NSColor* result = nil;
             unsigned colorValue = 0;
             unsigned char r, g, b;
             if (nil != rgb)
              {
                    NSScanner* scanner = [NSScanner scannerWithString:rgb];
                    // ignore error
                    (void) [scanner scanHexInt:&colorValue];
              }
              r = (unsigned char)(colorValue >> 16);
              g = (unsigned char)(colorValue >> 8);
              // masks off high bits
              b = (unsigned char)(colorValue);
              CGFloat components[4] = {(CGFloat)r / 0xff,(CGFloat)g / 0xff,(CGFloat)b / 0xff,1.0f};
              return [NSColor colorWithColorSpace:(AppDelegate*)([NSApplication shareApplication].delegate).colorSpace components:components count:4];
              }
         @end
            

01/05/2013

NCTDownloader version 1.0.0.0

Hôm nay rãnh rỗi ngồi viết code cho bài viết: Tải nhạc (phim) từ trang nhaccuatui.com.
Chương trình này tạm gọi là NCTDownloader. Phiên bản 1.0.0.0 download về tại đây.
Ở phiên bản này  NCTDownloader chỉ lấy link download trực tiếp bài nhạc hay video clip.