4

次のようなメソッドを使用して、マウス入力を処理する既存のクロスプラットフォーム C++ コードがあります。

onMouseDown(x,y,button)
onMouseUp(x,y,button)
onMouseMove(x,y,buttons)

必要に応じて最小限の Objective-C を使用して、機能を C++ iOS アプリに移植しています。シングルタッチ ジェスチャを処理してマウス機能をエミュレートし、パラメータを既存のメソッドに渡すことができるようにしたいと考えています (マルチタッチを追加するだけでなく)。

理想的には最小限のサンプルアプリとして、これを行うコードはどのように見えるでしょうか?本当に私を混乱させるのは、主に OBJ-C/C++ の相互作用ですか?

4

4 に答える 4

7

OpenGL プログラム (1 本または 2 本の指) の C++ コードにマルチタッチを渡す方法を次に示します。

// Set this in your ViewController's init code
[self setMultipleTouchEnabled:YES];

// Implement these in ViewController
int touchCount = 0;
UITouch* touch[2];

- (void)touchesBegan:(NSSet*)touches withEvent:(UIEvent*)event{ 
    NSArray* array = [touches allObjects];  
    UITouch* touchTemp; 
    int t;
    int touchedPixel[2];

    for(int i = 0; i < [array count]; ++i){
        touchTemp = [array objectAtIndex:i];

        if(touchCount >= 2)
            return;

        if(touch[0] == NULL)    
            t = 0;
        else
            t = 1;      
        touch[t] = touchTemp;

        CGPoint touchLoc = [touch[t] locationInView:(EAGLView *)self.view]; 
        ++touchCount;

        touchedPixel[X] = touchLoc.x;
        touchedPixel[Y] = touchLoc.y;
        mainScreen->push(t, touchedPixel);  // mainScreen is a C++ object for GL drawing.
    }
}


- (void)touchesMoved:(NSSet*)touches withEvent:(UIEvent*)event{
    NSArray* array = [touches allObjects];
    UITouch* touchTemp; 
    int t;
    int touchedPixel[2];

    for(int i = 0; i < [array count]; ++i){
        touchTemp = [array objectAtIndex:i];
        for(t = 0; t < 2; ++t){         // Find the matching touch in the array
            if(touchTemp == touch[t])
                break;
        }       
        if(t == 2)                      // Return if touch was not found
            continue;

        CGPoint touchLoc = [touch[t] locationInView:(EAGLView *)self.view]; 

        touchedPixel[X] = touchLoc.x;
        touchedPixel[Y] = touchLoc.y;
        mainScreen->move(t, touchedPixel);
    }
}


- (void)touchesEnded:(NSSet*)touches withEvent:(UIEvent*)event{ 
    NSArray* array = [touches allObjects];
    UITouch* touchTemp; 
    int t;
    int touchedPixel[2];

    for(int i = 0; i < [array count]; ++i){
        touchTemp = [array objectAtIndex:i];
        for(t = 0; t < 2; ++t){         // Find the matching touch in the array
            if(touchTemp == touch[t])
                break;
        }       
        if(t == 2)                      // Return if touch was not found
            continue;               

        CGPoint touchLoc = [touch[t] locationInView:(EAGLView *)self.view];

        touch[t] = NULL;
        --touchCount;

        touchedPixel[X] = touchLoc.x;
        touchedPixel[Y] = touchLoc.y;
        mainScreen->release(t, touchedPixel);
    }
}

- (void)touchesCancelled:(NSSet*)touches withEvent:(UIEvent*)event{
    printf("Touch cancelled\n");
    [self touchesEnded:touches withEvent: event];
}
于 2012-12-20T15:48:20.380 に答える
3

これは、シングルタッチとマルチタッチの両方のユース ケースで機能します。oldlib以下の obj-c ファイルで使用しているスタブ c++ libを作成しました。

必要なものは何でも として渡すことができますbutton。私のコードはタッチ ID を渡します。ライブラリがそこで何を期待しているかを確認し、それに応じて変更する必要があると思います。

これが私のコードです:

oldlib.h

#ifndef Quick_oldlib_h
#define Quick_oldlib_h

void onMouseDown(int x,int y,int button);
void onMouseUp(int x,int y,int button);
void onMouseMove(int x,int y,int buttons);

#endif

oldlib.cpp

#include "oldlib.h"
#include <stdio.h>

void onMouseDown(int x,int y,int button)
{
    printf("onMouseDown:%d,%d button:%d\n", x, y, button);
}

void onMouseUp(int x,int y,int button)
{
    printf("onMouseUp:%d,%d button:%d\n", x, y, button);
}

void onMouseMove(int x,int y,int button)
{
    printf("onMouseMove:%d,%d button:%d\n", x, y, button);
}

QViewController.h

#import <UIKit/UIKit.h>

@interface QViewController : UIViewController

@end

QViewController.mm <-これをC++ヘッダーと一緒にコンパイルできるようにするMM拡張に注意してください

#import "QViewController.h"
#include "oldlib.h"

@interface QViewController ()
@property (nonatomic, retain) NSMutableSet* active_touches;
@end

@implementation QViewController

- (void)viewDidLoad
{
    [super viewDidLoad];
    self.active_touches = [[NSMutableSet alloc] init];
    // Do any additional setup after loading the view, typically from a nib.
}

- (void)didReceiveMemoryWarning
{
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}

- (void) touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
    for (UITouch* touch in touches) {
        [self.active_touches addObject:touch];
        onMouseDown([touch locationInView:self.view].x, [touch locationInView:self.view].y, (int)(__bridge void*)touch);
    }
}

- (void) touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
    for (UITouch* touch in touches) {
        if ([self.active_touches containsObject:touch]) {
            onMouseUp([touch locationInView:self.view].x, [touch locationInView:self.view].y, (int)(__bridge void*)touch);
            [self.active_touches removeObject:touch];
        }
    }
}

- (void) touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
    for (UITouch* touch in touches) {
        if ([self.active_touches containsObject:touch]) {
            onMouseMove([touch locationInView:self.view].x, [touch locationInView:self.view].y, (int)(__bridge void*)touch);
        }
    }
}

- (void) touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event
{
    for (UITouch* touch in touches) {
        [self.active_touches removeObject:touch];
        NSLog(@"cancelled: %@", touch);
    }
}

@end
于 2012-12-27T00:01:01.630 に答える
3

この状況では、touchesBegan、moved andEnded を実装し、呼び出しを c++ の mouseDown/Moved/Up コードに転送します。

私がすることのサンプル: コードがアプリの viewController にあると仮定します!

static UITouch *_trackedTouch = nil;
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
    assert(!_trackedTouch && "no multitouch");

    _trackedTouch = [touches anyObject];
    CGPoint pt = [_trackedTouch locationInView:self.view];
    mouseDown(pt.x,pt.y,0);
}
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
    assert(_trackedTouch && "no touch began");

    if(![touches containsObject:_trackedTouch])
        return;

    CGPoint pt = [_trackedTouch locationInView:self.view];
    mouseMoved(pt.x,pt.y,0);
}
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
    assert(_trackedTouch && "no touch began");

    if(![touches containsObject:_trackedTouch])
        return;

    CGPoint pt = [_trackedTouch locationInView:self.view];
    mouseUp(pt.x,pt.y,0);
}

本について...多分:https://stackoverflow.com/questions/5308106/book-recommendations-for-objective-c-for-ios-development(しかし、C++バイアスはありません...objCはCに基づいています. C++ は、ObjC に加えて使用できるものにすぎませんが、C++ を知っていても、ObjC の学習に役立つことは限られています)。

于 2012-12-20T11:18:41.963 に答える
1

これを行うには、タッチ転送を実装し、検出したタッチがレスポンダー チェーン内の Cocoa Touch オブジェクトではなく、C++ コードによって消費されるようにする必要があります。たとえば、ビューのtouchesBegan:withEvent:セレクター内に、onMouseDown(int, int, void*)メソッドの呼び出しを含めます。同様のロジックがありますtouchesMoved:withEvent:touchesEnded:withEvent:

ただし、いくつかの困難があります。HIG によるとtouchesCancelled:withEvent:、他のセレクターが実装されている場合は常に実装する必要があり、それtouches*:withEvent:を処理するロジックを含める必要があります。

発生する可能性のあるもう 1 つの問題は、UIGestureRecognizerサブクラスに関するものです。前に、C++ コードが確実にタッチを消費するようにする必要があると述べました。ただし、ジェスチャー レコグナイザーを使用する場合、touches*:WithEvent:セレクターも実装している場合、レスポンダー チェーン全体が混乱する可能性があります。これを説明する優れた WWDC ビデオがいくつかあります。要するに、ジェスチャ レコグナイザーがタッチを消費する場合、C++ メソッドに送信されることはありません。簡単な解決策は、ジェスチャ認識機能を使用しないことですが、マルチタッチを適切に処理する最も簡単な方法はジェスチャ認識機能です。

これにより、最終的な可能性がもたらされます (ジェスチャ認識機能を使用する場合)。セレクターのみを実装する代わりにtouches*:withEvent:、ジェスチャ認識エンジンのアクションを、C++ コードへの呼び出しを単純にラップする Objective-C セレクターに設定することができます。たとえば、UITapGestureRecogniserのアクションは、onTap単に を呼び出すメソッドである可能性がありますonMouseDown(...)。この道をたどることを選択した場合は、WWDC ビデオ ('11 および '12) を必ず見てください。ここでは、タッチ処理とレスポンダー チェーンがより詳細に説明されています。

Objective-C++ を扱う書籍のトピックについては、Apple 自身が ObjC++ のすべきこととすべきでないことを説明していたページを削除しまし。クロスオーバーを処理する最も簡単な方法は、Objective-C でアプリケーション層の最低限の要素を実装し、すべての適切な呼び出しを C++ エンジンに転送することです。個人的には、純粋な Objective-C で App Delegate をプログラミングしたいと思いますが、一度自分の に慣れればViewController、自由に制御できます。

于 2012-12-24T11:37:01.713 に答える