4

我有现有的跨平台 C++ 代码来处理鼠标输入,方法如下:

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

我正在将功能移植到 C++ iOS 应用程序中……根据需要使用最低限度的 Objective-C。我想处理单点触控手势来模拟鼠标功能,这样我就可以将参数传递给现有方法(以及添加多点触控)。

执行此操作的代码会是什么样子,理想情况下,它是一个最小的示例应用程序 - 主要是 OBJ-C/C++ 交互让我感到困惑?

4

4 回答 4

7

以下是我如何将多点触控传递给 OpenGL 程序的 C++ 代码(使用 1 根或 2 根手指):

// 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

对于这种情况,我将实现 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);
}

关于书籍mhm ...也许:https ://stackoverflow.com/questions/5308106/book-recommendations-for-objective-c-for-ios-development(但arent C++有偏见...... objC基于C。除了 ObjC 之外,C++ 只是您可以使用的东西,但是.. 了解 C++ 只能为学习 ObjC 提供有限的帮助)

于 2012-12-20T11:18:41.963 回答
3

这适用于单点触控和多点触控用例。我编写了一个存根 c++ 库oldlib,名为我在下面的 obj-c 文件中使用。

你可以通过任何你需要的作为button. 我的代码通过了触摸 ID。我想你需要检查你的图书馆对那里的期望并相应地改变它。

这是我的代码:

老库

#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

旧的lib.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 <- 注意 MM 扩展,它可以与 C++ 头文件一起编译

#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 回答
1

为此,您需要实现触摸转发,并确保您刚刚检测到的触摸被您的 C++ 代码使用,而不是响应链中的任何 Cocoa Touch 对象。例如,在视图的touchesBegan:withEvent:选择器中,您将包含对您的onMouseDown(int, int, void*)方法的调用。touchesMoved:withEvent:并且touchesEnded:withEvent:会有类似的逻辑。

不过也有一些困难。根据 HIG,touchesCancelled:withEvent:应始终在实现其他touches*:withEvent:选择器时实现,并且您必须包含处理该问题的逻辑。

您可能遇到的另一个问题是UIGestureRecognizer子类。我之前提到过,您必须确保您的 C++ 代码使用触摸。但是,如果您使用手势识别器,如果您还实现了touches*:WithEvent:选择器,您的整个响应器链可能会变得混乱。有一些优秀的 WWDC 视频解释了这一点。简而言之,如果您的手势识别器消耗了触摸,它将永远不会发送到您的 C++ 方法。简单的解决方案是不使用手势识别器,但它们是迄今为止处理多点触控的最简单方法。

这给我们带来了最后一种可能性(如果你想使用手势识别器)。除了单独实现touches*:withEvent:选择器之外,您还可以将手势识别器的操作设置为一个 Objective-C 选择器,它简单地包装对您的 C++ 代码的调用。例如,aUITapGestureRecogniser的动作可以是一个被调用的方法onTap,它简单地调用onMouseDown(...). 如果您确实选择走这条路,请务必观看 WWDC 视频('11 和 '12),其中更详细地解释了触摸处理和响应程序链。

关于处理 Objective-C++ 的书籍的主题,Apple 自己已经删除了用于解释 ObjC++ 的注意事项的页面......然而,它可以在这里找到,谢天谢地。处理交叉的最简单方法是在 Objective-C 中实现应用层的基本要素,并将所有适当的调用转发到 C++ 引擎。就我个人而言,我会在 Pure Objective-C 中编写 App Delegate,但是一旦你进入了你的应用程序ViewController,你就可以自由支配了。

于 2012-12-24T11:37:01.713 回答