2 // Copyright (C) 2010, 2011, 2012 Free Software Foundation, Inc
4 // This program is free software; you can redistribute it and/or modify
5 // it under the terms of the GNU General Public License as published by
6 // the Free Software Foundation; either version 3 of the License, or
7 // (at your option) any later version.
9 // This program is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 // GNU General Public License for more details.
14 // You should have received a copy of the GNU General Public License
15 // along with this program; if not, write to the Free Software
16 // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
20 #include "gnashconfig.h"
23 #include <sys/types.h>
27 #include <boost/shared_array.hpp>
29 #include "GnashSleep.h"
31 #include "InputDevice.h"
35 static const char *MOUSE_DEVICE
= "/dev/input/mice";
37 MouseDevice::MouseDevice()
41 // GNASH_REPORT_FUNCTION;
44 MouseDevice::~MouseDevice()
46 // GNASH_REPORT_FUNCTION;
49 std::vector
<boost::shared_ptr
<InputDevice
> >
50 MouseDevice::scanForDevices()
52 // GNASH_REPORT_FUNCTION;
56 std::vector
<boost::shared_ptr
<InputDevice
> > devices
;
58 // Look for these files for mouse input
60 InputDevice::devicetype_e type
;
64 // Debug strings to make output more readable
65 const char *debug
[] = {
78 struct mouse_types mice
[] = {
79 {InputDevice::MOUSE
, "/dev/input/mice"}, // PS/2 Mouse
80 #ifdef MULTIPLE_DEVICES
81 {InputDevice::MOUSE
, "/dev/input/mouse0"},
82 {InputDevice::MOUSE
, "/dev/input/mouse1"},
83 {InputDevice::MOUSE
, "/dev/usb/tkpanel0"}, // eTurboTouch touchscreen
85 {InputDevice::UNKNOWN
, 0}
89 while (mice
[i
].type
!= InputDevice::UNKNOWN
) {
91 if (stat(mice
[i
].filespec
, &st
) == 0) {
92 // Then see if we can open it
93 if ((fd
= open(mice
[i
].filespec
, O_RDWR
|O_NONBLOCK
)) < 0) {
94 log_error(_("You don't have the proper permissions to open %s"),
99 log_debug(_("Found a %s device for mouse input using %s"),
100 debug
[mice
[i
].type
], mice
[i
].filespec
);
102 boost::shared_ptr
<InputDevice
> dev
;
103 #if defined(USE_MOUSE_PS2) || defined(USE_MOUSE_ETT)
104 dev
= boost::shared_ptr
<InputDevice
>(new MouseDevice());
105 // The User Mode Mouse is write only, so we don't consider
106 // it an input device.
107 dev
->setType(mice
[i
].type
);
108 // Close the device now that we know the permissions are
109 // correct. It's reopened correctly by init() when each
110 // found device is instantiated.
114 if (dev
->init(mice
[i
].filespec
, DEFAULT_BUFFER_SIZE
)) {
115 devices
.push_back(dev
);
130 // GNASH_REPORT_FUNCTION;
132 return init(MOUSE_DEVICE
, DEFAULT_BUFFER_SIZE
);
136 MouseDevice::init(const std::string
&filespec
, size_t size
)
138 GNASH_REPORT_FUNCTION
;
140 _filespec
= filespec
;
142 _fd
= open(filespec
.c_str(), O_RDWR
| O_NDELAY
);
145 log_debug(_("Could not open %s: %s"), filespec
, strerror(errno
));
150 if (fcntl(_fd
, F_SETFL
, fcntl(_fd
, F_GETFL
) | O_NONBLOCK
) < 0) {
151 log_error(_("Could not set non-blocking mode for mouse device: %s"),
161 // see http://www.computer-engineering.org/ps2mouse/
162 // Clear input buffer
163 unsigned char buf
[10], byte
;
164 while (read(_fd
, buf
, size
) > 0 ) { }
166 // A touchscreen works similar to a Mouse, but not exactly...
167 if (_type
== InputDevice::MOUSE
) {
169 if ((!command(0xFF, buf
, 3)) || (buf
[0] != 0xFA)) {
170 log_error(_("Mouse reset failed"));
178 // Get Device ID (not crucial, debug only)
179 if ((!command(0xF2, buf
, 2)) || (buf
[0] != 0xFA)) {
180 log_debug(_("WARNING: Could not detect mouse device ID"));
182 unsigned char devid
= buf
[1];
184 log_debug(_("WARNING: Non-standard mouse device ID %d"), devid
);
187 // Enable mouse data reporting
188 if ((!command(0xF4, &byte
, 1)) || (byte
!= 0xFA)) {
189 log_debug(_("Could not activate Data Reporting mode for mouse"));
197 log_debug(_("Mouse enabled for %s on fd #%d"), _filespec
, _fd
);
203 // From http://www.computer-engineering.org/ps2mouse
205 // PS/2 Mouse mouse data is always in a 3 byte packet that looks like this:
207 // Bit 7 Bit 6 Bit 5 Bit 4 Bit 3 Bit 2 Bit 1 Bit 0
208 // Byte 1 | Y overflow | X overflow | Y sign bit | X sign bit | Always 1 | Middle | Right | Left
212 // The movement values are 9-bit 2's complement integers, where the
213 // most significant bit appears as a "sign" bit in byte 1 of the
214 // movement data packet. Their value represents the mouse's offset
215 // relative to its position when the previous packet was sent, in
216 // units determined by the current resolution. The range of values
217 // that can be expressed is -255 to +255. If this range is exceeded,
218 // the appropriate overflow bit is set.
220 // Note that reporting is disabled by default. The mouse will not
221 // actually issue any movement data packets until it receives the
222 // "Enable Data Reporting" (0xF4) command.
224 // Stream mode is the default operating mode, and is otherwise set
225 // using the "Set Stream Mode" (0xEA) command.
227 // In remote mode the mouse reads its inputs and updates its
228 // counters/flags at the current sample rate, but it does not
229 // automatically issue data packets when movement has
230 // occured. Instead, the host polls the mouse using the "Read Data"
231 // (0xEB) command. Upon receiving this command the mouse will issue a
232 // single movement data packet and reset its movement counters.
234 // The mouse enters remote mode upon receiving the "Set Remote Mode"
239 // GNASH_REPORT_FUNCTION;
241 int xmove
, ymove
, btn
;
242 boost::shared_array
<boost::uint8_t> buf
;
243 if (_type
== InputDevice::TOUCHMOUSE
) {
244 // The eTurboTouch has a 4 byte packet
246 } else if (_type
== InputDevice::MOUSE
) {
247 // PS/2 Mouse packets are always 3 bytes
256 if (!buf
[0] & 8) { // bit 3 us always set in the first byte
257 log_error(_("No sync in first byte!"));
261 // A Touchscreen works similar to a Mouse, but not exactly.
262 // At least for the eTurboTouch, it has a different layout
263 // in the packet for the location as it has an additional byte
265 if (_type
== InputDevice::TOUCHMOUSE
) {
266 xmove
= (buf
[1] << 7) | (buf
[2]);
267 ymove
= (buf
[3] << 7) | (buf
[4]);
269 printf("touchscreen: %02x %02x %02x %02x %02x | status %d, pos: %d/%d\n",
270 mouse_buf[0], mouse_buf[1], mouse_buf[2], mouse_buf[3], mouse_buf[4],
271 new_btn, new_x, new_y);
274 xmove
= static_cast<int>(((static_cast<double>(xmove
)- 355) / (1702 - 355)
276 ymove
= static_cast<int>(((static_cast<double>(ymove
) - 482) / (1771 - 482)
278 // FIXME: don't calculate here, this should be done by the GUI
279 xmove
= xmove
* _screen_width
/ 2048;
280 ymove
= (2048-ymove
) * _screen_height
/ 2048;
281 } else { // end of InputDevice::TOUCHMOUSE
283 // The movement values are 9-bit 2's complement integers,
284 // where the most significant bit appears as a "sign" bit in
285 // byte 1 of the movement data packet. Their value represents
286 // the mouse's offset relative to its position when the
287 // previous packet was sent, in units determined by the
288 // current resolution. The range of values that can be
289 // expressed is -255 to +255. If this range is exceeded, the
290 // appropriate overflow bit is set.
291 // (from the manpage for the psm driver)
293 // bit 7 One indicates overflow in the vertical movement count.
294 // bit 6 One indicates overflow in the horizontal movement count.
295 // bit 5 Set if the vertical movement count is negative.
296 // bit 4 Set if the horizontal movement count is negative.
298 // bit 2 Middle button status; set if pressed. For devices without
299 // the middle button, this bit is always zero.
300 // bit 1 Right button status; set if pressed.
301 // bit 0 Left button status; set if pressed.
302 // Byte 2 Horizontal movement count in two’s complement; -256 through 255.
303 // Note that the sign bit is in the first byte.
304 // Byte 3 Vertical movement count in two’s complement; -256 through 255.
305 // Note that the sign bit is in the first byte.
311 log_debug(_("Vertical mouse movement overflow bit set"));
314 log_debug(_("Horizontal mouse movement overflow bit set"));
316 // 0,0 is the lower left of the display, so the negative bits are set
317 // when going from the upper left to the lower right.
320 log_debug(_("Horizontal mouse movement negative bit set"));
325 log_debug(_("Vertical mouse movement negative bit set"));
330 log_debug(_("PS/2 Mouse: Xmove=%d, Ymove=%d, Button %d"),
333 _input_data
.x
+= xmove
;
334 if (_input_data
.x
< 0) {
338 _input_data
.y
+= ymove
;
339 if (_input_data
.y
< 0) {
342 boost::shared_array
<int> coords
=
343 InputDevice::convertAbsCoords(_input_data
.x
, _input_data
.y
,
344 _screen_width
, _screen_height
);
345 // MouseDevice::convertCoordinates(_input_data.x, _input_data.y,
346 // _screen_width, _screen_height);
347 log_debug(_("convert: Xin=%d, Yin=%d, Xout=%d, Yout=%d"),
348 _input_data
.x
, _input_data
.y
, coords
[0],coords
[1]);
350 _input_data
.x
= coords
[0];
351 _input_data
.y
= coords
[1];
352 } // end of InputDevice::MOUSE
354 log_debug(_("read mouse: X=%d, Y=%d, Btn: btn %d"), _input_data
.x
,
355 _input_data
.y
, _input_data
.button
);
356 addData(false, gnash::key::INVALID
, 0, _input_data
.x
, _input_data
.y
);
359 if (btn
!= _input_data
.button
) {
360 _input_data
.button
= btn
;
361 addData(true, gnash::key::INVALID
, 0, _input_data
.x
, _input_data
.y
);
362 log_debug(_("mouse click! %d"), btn
);
369 MouseDevice::command(unsigned char cmd
, unsigned char *buf
, int count
)
371 // GNASH_REPORT_FUNCTION;
375 // flush input buffer
378 n
= ::read(_fd
, trash
, sizeof trash
);
380 log_debug(_("mouse_command: discarded %d bytes from input buffer"), n
);
384 if ( -1 == ::write(_fd
, &cmd
, 1) ) {
388 // read response (if any)
390 gnashSleep(250*1000); // 250 ms inter-char timeout (simple method)
391 // TODO: use select() instead
393 n
= read(_fd
, buf
, count
);
410 // indent-tabs-mode: nil