vrpn  07.33
Virtual Reality Peripheral Network
vrpn_DevInput.C
Go to the documentation of this file.
1 /* file: vrpn_DevInput.cpp
2  * author: Mike Weiblen mew@mew.cx 2004-01-14
3  * copyright: (C) 2003,2004 Michael Weiblen
4  * license: Released to the Public Domain.
5  * depends: gpm 1.19.6, VRPN 06_04
6  * tested on: Linux w/ gcc 2.95.4
7  * references: http://mew.cx/ http://vrpn.org/
8  * http://linux.schottelius.org/gpm/
9 */
10 
11 #include "vrpn_DevInput.h"
12 
14 
15 #ifdef VRPN_USE_DEV_INPUT
16 #include <sys/select.h> // for select, FD_ISSET, FD_SET, etc
17 #include <vrpn_Shared.h> // for vrpn_gettimeofday
18 #include <unistd.h> // for close, read
19 #include <utility> // for pair
20 #include <fcntl.h> // for open, O_RDONLY
21 #include <linux/input.h> // for input_event, ABS_MAX, etc
22 #include <errno.h> // for errno, EACCES, ENOENT
23 #include <string.h> // for strcmp, NULL, strerror
24 #include <sys/ioctl.h> // for ioctl
25 #include <iostream> // for operator<<, ostringstream, etc
26 #include <map> // for map, _Rb_tree_iterator, etc
27 #include <string> // for string, operator+, etc
28 #include <sstream>
29 
30 #define REPORT_ERROR(msg) { send_text_message(msg, timestamp, vrpn_TEXT_ERROR); }
31 
32 static const std::string EMPTY_STRING("");
33 
34 static const std::string &getDeviceNodes(const std::string &device_name)
35 {
36  std::map<std::string, std::string> s_devicesNodes;
37 
38  bool permission_missing = false;
39  unsigned int id = 0;
40  while (1) {
41  std::ostringstream oss;
42  oss << "/dev/input/event" << id;
43 
44  int fd = open(oss.str().c_str(), O_RDONLY);
45  if(fd >= 0){
46  char name[512];
47  if(ioctl(fd, EVIOCGNAME(sizeof(name)), name) >= 0) {
48  s_devicesNodes[name] = oss.str();
49  }
50 
51  close(fd);
52  } else {
53  if (errno == ENOENT) break;
54  if (errno == EACCES) permission_missing = true;
55  }
56  errno = 0;
57  id++;
58  }
59  if (permission_missing) {
60  std::cout << "vrpn_DevInput device scan warning : permission denied for some nodes !" << std::endl;
61  }
62 
63  std::map<std::string, std::string>::iterator node_name = s_devicesNodes.find(device_name);
64  if (node_name != s_devicesNodes.end()) {
65  return node_name->second;
66  }
67 
68  return EMPTY_STRING;
69 }
70 
72 
73 vrpn_DevInput::vrpn_DevInput( const char* name, vrpn_Connection * cxn, const char *device_name, const char * type, int int_param )
74  : vrpn_Analog( name, cxn )
75  , vrpn_Button_Filter( name, cxn )
76  , d_fileDescriptor(-1) // None found yet, device broken.
77 {
78  int i;
79 
80  if (strcmp(type, "keyboard") == 0) {
81  d_type = DEVICE_KEYBOARD;
82  } else if (strcmp(type, "absolute") == 0) {
83  d_type = DEVICE_MOUSE_ABSOLUTE;
84  } else if (strcmp(type, "relative") == 0) {
85  d_type = DEVICE_MOUSE_RELATIVE;
86  } else {
87  REPORT_ERROR("Third parameter must be keyboard, absolute or relative");
88  return;
89  }
90 
93 
94  switch (d_type) {
95  case DEVICE_KEYBOARD:
96  if ((int_param < 1) || (int_param >= vrpn_BUTTON_MAX_BUTTONS)) {
97  REPORT_ERROR("In case of keyboard, the value must be between 1 and 256");
98  return;
99  }
101  break;
102  case DEVICE_MOUSE_ABSOLUTE:
103  vrpn_Analog::num_channel = REL_MAX;
105  d_absolute_min = 0;
106  d_absolute_range = int_param;
107  break;
108  case DEVICE_MOUSE_RELATIVE:
109  vrpn_Analog::num_channel = ABS_MAX;
111  break;
112  };
113 
114  // initialize the vrpn_Analog
115  for( i = 0; i < vrpn_Analog::num_channel; i++) {
117  }
118 
119  // initialize the vrpn_Button_Filter
120  for( i = 0; i < vrpn_Button_Filter::num_buttons; i++) {
122  }
123 
124  std::string node = getDeviceNodes(device_name);
125  if (node.length() == 0) {
126  char msg[4096];
127  sprintf(msg, "vrpn_DevInput::vrpn_DevInput(): Could not get device %s",
128  device_name);
129  REPORT_ERROR(msg);
130  return;
131  }
132 
133  d_fileDescriptor = open(node.c_str(), O_RDONLY);
134  if(d_fileDescriptor < 0){
135  char msg[4096];
136  sprintf(msg, "vrpn_DevInput::vrpn_DevInput(): Could not open device %s (%s)",
137  device_name, strerror(errno));
138  REPORT_ERROR(msg);
139  return;
140  }
141 }
142 
144 
145 vrpn_DevInput::~vrpn_DevInput()
146 {
147  if (d_fileDescriptor >= 0) {
148  close(d_fileDescriptor);
149  }
150  d_fileDescriptor = -1;
151 }
152 
154 
155 void vrpn_DevInput::mainloop()
156 {
157  get_report();
158 
159  server_mainloop();
160 
161  report_changes();
162 }
163 
165 
166 int vrpn_DevInput::get_report()
167 {
168  fd_set readset;
169 
170  if (d_fileDescriptor < 0) {
171  return 0;
172  }
173 
174  FD_ZERO( &readset );
175  FD_SET( d_fileDescriptor, &readset );
176  struct timeval timeout = { 0, 0 };
177  select( d_fileDescriptor+1, &readset, NULL, NULL, &timeout );
178 
179  vrpn_gettimeofday( &timestamp, NULL );
180 
181  if( ! FD_ISSET( d_fileDescriptor, &readset ) )
182  return 0;
183 
184  struct input_event event;
185  if (read(d_fileDescriptor, &event, sizeof(event)) < sizeof(event)) {
186  return 0;
187  }
188 
189  switch (event.type) {
190  case EV_KEY: {
191  int button_number = event.code;
192  if ((d_type == DEVICE_MOUSE_RELATIVE) || (d_type == DEVICE_MOUSE_ABSOLUTE)) {
193  button_number -= BTN_MOUSE;
194  }
195  if ((button_number >= 0) && (button_number < vrpn_Button_Filter::num_buttons)) {
196  buttons[button_number] = event.value;
197  }
198  } break;
199  case EV_REL: {
200  int channel_number = event.code;
201  if ((channel_number >= 0) && (channel_number < vrpn_Analog::num_channel)) {
202  for (unsigned int i = 0 ; i < vrpn_Analog::num_channel ; i++) {
203  vrpn_Analog::last[i] = 0;
204  }
205  vrpn_Analog::channel[channel_number] = (vrpn_float64)event.value;
206  }
207  } break;
208  case EV_ABS:
209  int channel_number = event.code;
210  if ((channel_number >= 0) && (channel_number < vrpn_Analog::num_channel)) {
211  vrpn_float64 value = ((vrpn_float64)event.value - d_absolute_min) / d_absolute_range;
212  vrpn_Analog::channel[channel_number] = value;
213  }
214  break;
215  };
216 
217  return 1;
218 }
219 
221 
222 void vrpn_DevInput::report_changes( vrpn_uint32 class_of_service )
223 {
224  vrpn_Analog::timestamp = timestamp;
225  vrpn_Button_Filter::timestamp = timestamp;
226 
227  vrpn_Analog::report_changes( class_of_service );
229 }
230 
232 
233 void vrpn_DevInput::report( vrpn_uint32 class_of_service )
234 {
235  vrpn_Analog::timestamp = timestamp;
236  vrpn_Button_Filter::timestamp = timestamp;
237 
238  vrpn_Analog::report( class_of_service );
240 }
241 
242 #endif
243 
244 /*EOF*/
virtual void report_changes(vrpn_uint32 class_of_service=vrpn_CONNECTION_LOW_LATENCY, const struct timeval time=vrpn_ANALOG_NOW)
Send a report only if something has changed (for servers) Optionally, tell what time to stamp the val...
Definition: vrpn_Analog.C:71
vrpn_int32 num_buttons
Definition: vrpn_Button.h:47
#define EV_REL
vrpn_float64 channel[vrpn_CHANNEL_MAX]
Definition: vrpn_Analog.h:38
#define REPORT_ERROR(msg)
Definition: vrpn_LUDL.C:27
Generic connection class not specific to the transport mechanism.
virtual void report(vrpn_uint32 class_of_service=vrpn_CONNECTION_LOW_LATENCY, const struct timeval time=vrpn_ANALOG_NOW)
Send a report whether something has changed or not (for servers) Optionally, tell what time to stamp ...
Definition: vrpn_Analog.C:94
#define VRPN_SUPPRESS_EMPTY_OBJECT_WARNING()
virtual void report_changes(void)
Definition: vrpn_Button.C:382
vrpn_int32 num_channel
Definition: vrpn_Analog.h:40
struct timeval timestamp
Definition: vrpn_Button.h:48
const int vrpn_BUTTON_MAX_BUTTONS
Definition: vrpn_Button.h:12
#define vrpn_gettimeofday
Definition: vrpn_Shared.h:89
All button servers should derive from this class, which provides the ability to turn any of the butto...
Definition: vrpn_Button.h:65
unsigned char lastbuttons[vrpn_BUTTON_MAX_BUTTONS]
Definition: vrpn_Button.h:45
unsigned char buttons[vrpn_BUTTON_MAX_BUTTONS]
Definition: vrpn_Button.h:44
struct timeval timestamp
Definition: vrpn_Analog.h:41
#define EV_KEY
vrpn_float64 last[vrpn_CHANNEL_MAX]
Definition: vrpn_Analog.h:39