-
Notifications
You must be signed in to change notification settings - Fork 2
/
mouse_mac.mm
119 lines (105 loc) · 3.29 KB
/
mouse_mac.mm
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
#include "mouse.h"
#include <QMutex>
#include <QMessageBox>
#include <QApplication>
#include <QDesktopWidget>
#include <ApplicationServices/ApplicationServices.h>
#include <QGuiApplication>
#include <QtGlobal>
#include <QScreen>
#import <Foundation/Foundation.h>
#import <AppKit/AppKit.h>
static QPoint confineToScreen(QPoint p) {
// TODO: This function doesn't work perfectly for multiple screens because finding the closest point
// on the boundary of multiple rectangles would take a while to figure out.
// This allows it to kind of work by accepting points that are in non-primary screen.
foreach (QScreen *screen, QGuiApplication::screens()) {
if(screen->geometry().contains(p)) return p;
}
QRect geom = QGuiApplication::primaryScreen()->geometry();
QPoint res;
res.setX(qMax(geom.left(), qMin(p.x(), geom.right())));
res.setY(qMax(geom.top(), qMin(p.y(), geom.bottom())));
return res;
}
struct mouseLocalData{
mouseLocalData():pressed((buttons_t)0){}
buttons_t pressed;
QMutex mutex;
};
mouseClass::mouseClass(){
data = new mouseLocalData();
}
mouseClass::~mouseClass(){
delete data;
}
bool mouseClass::init()
{
return true;
}
bool mouseClass::move(int dx, int dy)
{
//Gotcha - when a key is pressed, while moving, emit not mouse moved, but mouse dragged event
data->mutex.lock();
CGEventType event;
CGEventRef ev_ref;
QPoint pos = QCursor::pos();
pos = QPoint(pos.x() + dx, pos.y() + dy);
pos = confineToScreen(pos);
int pressed = [NSEvent pressedMouseButtons];
if(pressed & LEFT_BUTTON){
event = kCGEventLeftMouseDragged;
} else if(pressed & RIGHT_BUTTON){
event = kCGEventRightMouseDragged;
} else {
event = kCGEventMouseMoved;
}
ev_ref = CGEventCreateMouseEvent(NULL, event, CGPointMake(pos.x(),pos.y()), kCGMouseButtonLeft);
CGEventPost(kCGHIDEventTap, ev_ref);
CFRelease(ev_ref);
QCursor::setPos(pos.x(), pos.y());
data->mutex.unlock();
return true;
}
bool mouseClass::click(buttons_t buttons, struct timeval ts)
{
(void) ts;
data->mutex.lock();
buttons_t changed = (buttons_t)(buttons ^ data->pressed);
CGEventType event;
CGEventRef ev_ref;
CGPoint pos;
QPoint currentPos = QCursor::pos();
pos.x = currentPos.x();
pos.y = currentPos.y();
if(changed & LEFT_BUTTON){
if(buttons & LEFT_BUTTON){
event = kCGEventLeftMouseDown;
}else{
event = kCGEventLeftMouseUp;
}
ev_ref = CGEventCreateMouseEvent(NULL, event, pos, kCGMouseButtonLeft);
CGEventPost(kCGHIDEventTap, ev_ref);
CFRelease(ev_ref);
}
if(changed & RIGHT_BUTTON){
if(buttons & RIGHT_BUTTON){
event = kCGEventRightMouseDown;
}else{
event = kCGEventRightMouseUp;
}
CGEventCreateMouseEvent(NULL, event, pos, kCGMouseButtonLeft);
CGEventPost(kCGHIDEventTap, ev_ref);
CFRelease(ev_ref);
}
data->pressed = buttons;
data->mutex.unlock();
return true;
}
/*
Possible leads:
https://developer.apple.com/library/mac/#documentation/graphicsimaging/reference/Quartz_Services_Ref/Reference/reference.html
http://stackoverflow.com/questions/11860285/opposit-of-cgdisplaymovecursortopoint
https://developer.apple.com/library/mac/#documentation/Carbon/Reference/QuartzEventServicesRef/Reference/reference.html
http://stackoverflow.com/questions/1483657/performing-a-double-click-using-cgeventcreatemouseevent
*/