Skip to content

Commit a47130f

Browse files
committed
Implement beginnings of multitouch support
1 parent 7ed8b01 commit a47130f

File tree

13 files changed

+243
-15
lines changed

13 files changed

+243
-15
lines changed

direct/src/gui/DirectButton.py

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ def __init__(self, parent = None, **kw):
3434
('command', None, None),
3535
('extraArgs', [], None),
3636
# Which mouse buttons can be used to click the button
37-
('commandButtons', (DGG.LMB,), self.setCommandButtons),
37+
('commandButtons', (DGG.LMB, DGG.TOUCH), self.setCommandButtons),
3838
# Sounds to be used for button events
3939
('rolloverSound', DGG.getDefaultRolloverSound(), self.setRolloverSound),
4040
('clickSound', DGG.getDefaultClickSound(), self.setClickSound),
@@ -82,13 +82,15 @@ def setCommandButtons(self):
8282
else:
8383
self.unbind(DGG.B1CLICK)
8484
self.guiItem.removeClickButton(MouseButton.one())
85+
8586
# Middle mouse button
8687
if DGG.MMB in self['commandButtons']:
8788
self.guiItem.addClickButton(MouseButton.two())
8889
self.bind(DGG.B2CLICK, self.commandFunc)
8990
else:
9091
self.unbind(DGG.B2CLICK)
9192
self.guiItem.removeClickButton(MouseButton.two())
93+
9294
# Right mouse button
9395
if DGG.RMB in self['commandButtons']:
9496
self.guiItem.addClickButton(MouseButton.three())
@@ -97,6 +99,14 @@ def setCommandButtons(self):
9799
self.unbind(DGG.B3CLICK)
98100
self.guiItem.removeClickButton(MouseButton.three())
99101

102+
# Tapping with the finger
103+
if DGG.TOUCH in self['commandButtons']:
104+
self.guiItem.addClickButton(MouseButton.tap())
105+
self.bind(DGG.TOUCHCLICK, self.commandFunc)
106+
else:
107+
self.unbind(DGG.TOUCHCLICK)
108+
self.guiItem.removeClickButton(MouseButton.tap())
109+
100110
def commandFunc(self, event):
101111
if self['command']:
102112
# Pass any extra args to command
@@ -108,13 +118,16 @@ def setClickSound(self):
108118
self.guiItem.clearSound(DGG.B1PRESS + self.guiId)
109119
self.guiItem.clearSound(DGG.B2PRESS + self.guiId)
110120
self.guiItem.clearSound(DGG.B3PRESS + self.guiId)
121+
self.guiItem.clearSound(DGG.TOUCHPRESS + self.guiId)
111122
if clickSound:
112123
if DGG.LMB in self['commandButtons']:
113124
self.guiItem.setSound(DGG.B1PRESS + self.guiId, clickSound)
114125
if DGG.MMB in self['commandButtons']:
115126
self.guiItem.setSound(DGG.B2PRESS + self.guiId, clickSound)
116127
if DGG.RMB in self['commandButtons']:
117128
self.guiItem.setSound(DGG.B3PRESS + self.guiId, clickSound)
129+
if DGG.TOUCH in self['commandButtons']:
130+
self.guiItem.setSound(DGG.TOUCHPRESS + self.guiId, clickSound)
118131

119132
def setRolloverSound(self):
120133
rolloverSound = self['rolloverSound']

direct/src/gui/DirectCheckBox.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ def __init__(self, parent = None, **kw):
2323
('command', None, None),
2424
('extraArgs', [], None),
2525
# Which mouse buttons can be used to click the button
26-
('commandButtons', (DGG.LMB,), self.setCommandButtons),
26+
('commandButtons', (DGG.LMB, DGG.TOUCH), self.setCommandButtons),
2727
# Sounds to be used for button events
2828
('rolloverSound', DGG.getDefaultRolloverSound(), self.setRolloverSound),
2929
('clickSound', DGG.getDefaultClickSound(), self.setClickSound),

direct/src/gui/DirectGuiGlobals.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
LMB = 0
2626
MMB = 1
2727
RMB = 2
28+
TOUCH = -1
2829

2930
# Widget state
3031
NORMAL = 'normal'
@@ -63,12 +64,15 @@
6364
B1CLICK = PGButton.getClickPrefix() + MouseButton.one().getName() + '-'
6465
B2CLICK = PGButton.getClickPrefix() + MouseButton.two().getName() + '-'
6566
B3CLICK = PGButton.getClickPrefix() + MouseButton.three().getName() + '-'
67+
TOUCHCLICK = PGButton.getClickPrefix() + MouseButton.touch().getName() + '-'
6668
B1PRESS = PGButton.getPressPrefix() + MouseButton.one().getName() + '-'
6769
B2PRESS = PGButton.getPressPrefix() + MouseButton.two().getName() + '-'
6870
B3PRESS = PGButton.getPressPrefix() + MouseButton.three().getName() + '-'
71+
TOUCHPRESS = PGButton.getPressPrefix() + MouseButton.touch().getName() + '-'
6972
B1RELEASE = PGButton.getReleasePrefix() + MouseButton.one().getName() + '-'
7073
B2RELEASE = PGButton.getReleasePrefix() + MouseButton.two().getName() + '-'
7174
B3RELEASE = PGButton.getReleasePrefix() + MouseButton.three().getName() + '-'
75+
TOUCHRELEASE = PGButton.getPressPrefix() + MouseButton.touch().getName() + '-'
7276
# For DirectEntry widgets
7377
OVERFLOW = PGEntry.getOverflowPrefix()
7478
ACCEPT = PGEntry.getAcceptPrefix() + KeyboardButton.enter().getName() + '-'

panda/src/device/inputDevice.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -259,6 +259,7 @@ class EXPCL_PANDA_DEVICE InputDevice : public TypedReferenceCount {
259259
// Enable rumble force-feedback effects
260260
INLINE void set_vibration(double strong, double weak);
261261

262+
public:
262263
INLINE void enable_pointer_events();
263264
INLINE void disable_pointer_events();
264265

panda/src/pgui/pgButton.cxx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ PGButton(const std::string &name) : PGItem(name)
3030
{
3131
_button_down = false;
3232
_click_buttons.insert(MouseButton::one());
33+
_click_buttons.insert(MouseButton::touch());
3334

3435
set_active(true);
3536
}

panda/src/putil/mouseButton.cxx

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ ButtonHandle MouseButton::_wheel_up;
2222
ButtonHandle MouseButton::_wheel_down;
2323
ButtonHandle MouseButton::_wheel_left;
2424
ButtonHandle MouseButton::_wheel_right;
25+
ButtonHandle MouseButton::_touch;
2526

2627
/**
2728
* Returns the ButtonHandle associated with the particular numbered mouse
@@ -112,6 +113,14 @@ wheel_right() {
112113
return _wheel_right;
113114
}
114115

116+
/**
117+
* Returns the ButtonHandle generated when a finger touches the screen.
118+
*/
119+
ButtonHandle MouseButton::
120+
touch() {
121+
return _touch;
122+
}
123+
115124
/**
116125
* Returns true if the indicated ButtonHandle is a mouse button, false if it
117126
* is some other kind of button.
@@ -146,4 +155,5 @@ init_mouse_buttons() {
146155
ButtonRegistry::ptr()->register_button(_wheel_down, "wheel_down");
147156
ButtonRegistry::ptr()->register_button(_wheel_left, "wheel_left");
148157
ButtonRegistry::ptr()->register_button(_wheel_right, "wheel_right");
158+
ButtonRegistry::ptr()->register_button(_touch, "touch");
149159
}

panda/src/putil/mouseButton.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ class EXPCL_PANDA_PUTIL MouseButton {
3434
static ButtonHandle wheel_down();
3535
static ButtonHandle wheel_left();
3636
static ButtonHandle wheel_right();
37+
static ButtonHandle touch();
3738

3839
static bool is_mouse_button(ButtonHandle button);
3940

@@ -46,6 +47,7 @@ class EXPCL_PANDA_PUTIL MouseButton {
4647
static ButtonHandle _wheel_down;
4748
static ButtonHandle _wheel_left;
4849
static ButtonHandle _wheel_right;
50+
static ButtonHandle _touch;
4951
};
5052

5153
#endif

panda/src/tform/mouseWatcher.I

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,14 @@ is_button_down(ButtonHandle button) const {
147147
return _inactivity_state != IS_inactive && _current_buttons_down.get_bit(button.get_index());
148148
}
149149

150+
/**
151+
* Returns true if the pointer with the given identifier is currently pressed.
152+
*/
153+
INLINE bool MouseWatcher::
154+
is_pointer_down(int id) const {
155+
return _active_pointers.find(id) != _active_pointers.end();
156+
}
157+
150158
/**
151159
* Sets the pattern string that indicates how the event names are generated
152160
* when a button is depressed. This is a string that may contain any of the

panda/src/tform/mouseWatcher.cxx

Lines changed: 127 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,12 @@ remove_region(MouseWatcherRegion *region) {
120120
_preferred_button_down_region = nullptr;
121121
}
122122

123+
for (auto it = _active_pointers.begin(); it != _active_pointers.end(); ++it) {
124+
if (it->second._region == region) {
125+
it->second._region = nullptr;
126+
}
127+
}
128+
123129
return MouseWatcherBase::do_remove_region(region);
124130
}
125131

@@ -902,6 +908,90 @@ throw_event_pattern(const string &pattern, const MouseWatcherRegion *region,
902908
}
903909
}
904910

911+
/**
912+
* Records the indicated pointer as having made contact.
913+
*/
914+
void MouseWatcher::
915+
pointer_down(PointerType type, int id, const LPoint2 &pos, double pressure) {
916+
nassertv(_lock.debug_is_locked());
917+
918+
MouseWatcherParameter param;
919+
param.set_modifier_buttons(_mods);
920+
param.set_mouse(pos);
921+
param.set_outside(false);
922+
param._pressure = pressure;
923+
param._pointer_id = id;
924+
925+
Regions regions;
926+
get_over_regions(regions, pos);
927+
MouseWatcherRegion *region = get_preferred_region(regions);
928+
929+
double now = ClockObject::get_global_clock()->get_frame_time();
930+
_active_pointers[id] = {region, type, pressure, now};
931+
932+
if (region != nullptr && type != PointerType::mouse) {
933+
param.set_button(MouseButton::touch());
934+
region->press(param);
935+
}
936+
}
937+
938+
/**
939+
* Records the indicated pointer as having moved.
940+
*/
941+
void MouseWatcher::
942+
pointer_move(int id, const LPoint2 &pos, double pressure) {
943+
nassertv(_lock.debug_is_locked());
944+
945+
ActivePointer &pointer = _active_pointers[id];
946+
947+
MouseWatcherParameter param;
948+
param.set_modifier_buttons(_mods);
949+
param.set_mouse(pos);
950+
param._pressure = pressure;
951+
param._pointer_id = id;
952+
953+
pointer._max_pressure = std::max(pointer._max_pressure, pressure);
954+
955+
MouseWatcherRegion *region = pointer._region;
956+
if (region != nullptr) {
957+
region->move(param);
958+
}
959+
}
960+
961+
/**
962+
* Records the indicated pointer as no longer making contact.
963+
*/
964+
void MouseWatcher::
965+
pointer_up(int id, const LPoint2 &pos) {
966+
nassertv(_lock.debug_is_locked());
967+
968+
MouseWatcherRegion *region = _active_pointers[id]._region;
969+
if (region != nullptr && _active_pointers[id]._type != PointerType::mouse) {
970+
// Generate a release event.
971+
MouseWatcherParameter param;
972+
param.set_modifier_buttons(_mods);
973+
param.set_mouse(pos);
974+
param.set_button(MouseButton::touch());
975+
976+
// Are we still within the same region?
977+
PN_stdfloat mx = (pos[0] + 1.0f) * 0.5f * (_frame[1] - _frame[0]) + _frame[0];
978+
PN_stdfloat my = (pos[1] + 1.0f) * 0.5f * (_frame[3] - _frame[2]) + _frame[2];
979+
980+
const LVecBase4 &frame = region->get_frame();
981+
if (region->get_active() &&
982+
mx >= frame[0] && mx <= frame[1] &&
983+
my >= frame[2] && my <= frame[3]) {
984+
985+
param.set_outside(false);
986+
} else {
987+
param.set_outside(true);
988+
}
989+
990+
param._pointer_id = id;
991+
region->release(param);
992+
}
993+
}
994+
905995
/**
906996
* Records the indicated mouse or keyboard button as being moved from last
907997
* position.
@@ -913,6 +1003,7 @@ move() {
9131003
MouseWatcherParameter param;
9141004
param.set_modifier_buttons(_mods);
9151005
param.set_mouse(_mouse);
1006+
param._pressure = 1.0;
9161007

9171008
if (_preferred_button_down_region != nullptr) {
9181009
_preferred_button_down_region->move(param);
@@ -931,6 +1022,7 @@ press(ButtonHandle button, bool keyrepeat) {
9311022
param.set_keyrepeat(keyrepeat);
9321023
param.set_modifier_buttons(_mods);
9331024
param.set_mouse(_mouse);
1025+
param._pressure = 1.0;
9341026

9351027
if (MouseButton::is_mouse_button(button)) {
9361028
// Mouse buttons are inextricably linked to the mouse position.
@@ -982,6 +1074,7 @@ release(ButtonHandle button) {
9821074
param.set_button(button);
9831075
param.set_modifier_buttons(_mods);
9841076
param.set_mouse(_mouse);
1077+
param._pressure = 0.0;
9851078

9861079
if (MouseButton::is_mouse_button(button)) {
9871080
// Button up. Send the up event associated with the region(s) we were
@@ -1023,6 +1116,7 @@ keystroke(int keycode) {
10231116
param.set_keycode(keycode);
10241117
param.set_modifier_buttons(_mods);
10251118
param.set_mouse(_mouse);
1119+
param._pressure = 1.0;
10261120

10271121
// Make sure there are no duplicates in the regions vector.
10281122
if (!_sorted) {
@@ -1322,17 +1416,41 @@ do_transmit_data(DataGraphTraverser *trav, const DataNodeTransmit &input,
13221416

13231417
// Code for recording the mouse trail.
13241418
_num_trail_recent = 0;
1325-
if (input.has_data(_pointer_events_input) && (_trail_log_duration > 0.0)) {
1419+
if (input.has_data(_pointer_events_input)) {
13261420
const PointerEventList *this_pointer_events;
13271421
DCAST_INTO_V(this_pointer_events, input.get_data(_pointer_events_input).get_ptr());
1328-
_num_trail_recent = this_pointer_events->get_num_events();
1329-
for (size_t i = 0; i < _num_trail_recent; i++) {
1330-
bool in_win = this_pointer_events->get_in_window(i);
1331-
int xpos = this_pointer_events->get_xpos(i);
1332-
int ypos = this_pointer_events->get_ypos(i);
1333-
int sequence = this_pointer_events->get_sequence(i);
1334-
double time = this_pointer_events->get_time(i);
1335-
_trail_log->add_event(in_win, xpos, ypos, sequence, time);
1422+
1423+
for (size_t i = 0; i < this_pointer_events->get_num_events(); ++i) {
1424+
const PointerEvent &event = this_pointer_events->get_event(i);
1425+
auto it = _active_pointers.find(event._id);
1426+
1427+
// Determine the position in the -1..1 range.
1428+
LVecBase2 size = _pixel_size->get_value();
1429+
LPoint2 pos((PN_stdfloat)(2 * event._xpos) / size[0] - 1.0f,
1430+
1.0f - (PN_stdfloat)(2 * event._ypos) / size[1]);
1431+
1432+
if (event._pressure > 0.0) {
1433+
if (it == _active_pointers.end()) {
1434+
pointer_down(event._type, event._id, pos, event._pressure);
1435+
} else {
1436+
pointer_move(event._id, pos, event._pressure);
1437+
}
1438+
} else if (it != _active_pointers.end()) {
1439+
pointer_up(event._id, pos);
1440+
_active_pointers.erase(it);
1441+
}
1442+
}
1443+
1444+
if (_trail_log_duration > 0.0) {
1445+
_num_trail_recent = this_pointer_events->get_num_events();
1446+
for (size_t i = 0; i < _num_trail_recent; i++) {
1447+
bool in_win = this_pointer_events->get_in_window(i);
1448+
int xpos = this_pointer_events->get_xpos(i);
1449+
int ypos = this_pointer_events->get_ypos(i);
1450+
int sequence = this_pointer_events->get_sequence(i);
1451+
double time = this_pointer_events->get_time(i);
1452+
_trail_log->add_event(in_win, xpos, ypos, sequence, time);
1453+
}
13361454
}
13371455
}
13381456
if (_trail_log->get_num_events() > 0) {

panda/src/tform/mouseWatcher.h

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,7 @@ class EXPCL_PANDA_TFORM MouseWatcher : public DataNode, public MouseWatcherBase
8484
MouseWatcherRegion *get_over_region(const LPoint2 &pos) const;
8585

8686
INLINE bool is_button_down(ButtonHandle button) const;
87+
INLINE bool is_pointer_down(int id) const;
8788

8889
INLINE void set_button_down_pattern(const std::string &pattern);
8990
INLINE const std::string &get_button_down_pattern() const;
@@ -177,6 +178,10 @@ class EXPCL_PANDA_TFORM MouseWatcher : public DataNode, public MouseWatcherBase
177178
const MouseWatcherRegion *region,
178179
const ButtonHandle &button);
179180

181+
void pointer_down(PointerType type, int id, const LPoint2 &pos, double pressure);
182+
void pointer_move(int id, const LPoint2 &pos, double pressure);
183+
void pointer_up(int id, const LPoint2 &pos);
184+
180185
void move();
181186
void press(ButtonHandle button, bool keyrepeat);
182187
void release(ButtonHandle button);
@@ -217,6 +222,17 @@ class EXPCL_PANDA_TFORM MouseWatcher : public DataNode, public MouseWatcherBase
217222
LPoint2 _mouse_pixel;
218223
BitArray _current_buttons_down;
219224

225+
// Keeps track of which pointers are down and which regions they went down
226+
// in.
227+
struct ActivePointer {
228+
PT(MouseWatcherRegion) _region;
229+
PointerType _type;
230+
double _max_pressure;
231+
double _time;
232+
};
233+
pmap<int, ActivePointer> _active_pointers;
234+
int _primary_pointer = -1;
235+
220236
LVecBase4 _frame;
221237

222238
PT(PointerEventList) _trail_log;

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy