1//-------------------------------------------------------------------------
2// Handy InputFilter that dumps all Messages to a file.
3//-------------------------------------------------------------------------
4#include <stdlib.h>
5#include <string.h>
6#include <ctype.h>
7
8#include <Debug.h>
9#include <List.h>
10#include <File.h>
11#include <Message.h>
12#include <String.h>
13#include <OS.h>
14
15#include <add-ons/input_server/InputServerFilter.h>
16
17extern "C" _EXPORT BInputServerFilter* instantiate_input_filter();
18
19class MsgSpy : public BInputServerFilter
20{
21public:
22	         MsgSpy();
23	virtual ~MsgSpy();
24
25    virtual status_t      InitCheck(void);
26	virtual	filter_result Filter(BMessage *message, BList *outList);
27private:
28	const char* MapWhatToString(uint32 w);
29	void        OutputMsgField(const char*  fieldName,
30	                           const uint32 rawType,
31                               int          rawCount,
32                               const void*  rawData);
33
34    status_t m_status;
35    BFile*   m_outfile;
36};
37
38//-------------------------------------------------------------------------
39// Create a new MsgSpy instance and return it to the caller.
40//-------------------------------------------------------------------------
41BInputServerFilter* instantiate_input_filter()
42{
43	return (new MsgSpy() );
44}
45
46
47//-------------------------------------------------------------------------
48//-------------------------------------------------------------------------
49MsgSpy::MsgSpy()
50{
51    // Create the output file and return its status.
52    m_outfile = new BFile("/boot/home/MsgSpy.output", B_READ_WRITE | B_CREATE_FILE | B_ERASE_FILE);
53    //m_status = m_outfile->InitCheck();
54    m_status = B_OK;
55}
56
57//-------------------------------------------------------------------------
58//-------------------------------------------------------------------------
59MsgSpy::~MsgSpy()
60{
61    if (NULL != m_outfile)
62    {
63        // Close and destroy the output file.
64        delete m_outfile;
65    }
66}
67
68//-------------------------------------------------------------------------
69//-------------------------------------------------------------------------
70status_t MsgSpy::InitCheck(void)
71{
72	return m_status;
73}
74
75//-------------------------------------------------------------------------
76//-------------------------------------------------------------------------
77filter_result MsgSpy::Filter(BMessage *message, BList *outList)
78{
79    char*       field_name;
80    uint32      field_type;
81    int32       field_count;
82    const void* field_data;
83    ssize_t     field_data_bytes;
84	char        msg_buffer  [1024];
85
86	// Print out the message constant (what).
87	sprintf(msg_buffer, "%s\n", MapWhatToString(message->what) );
88    m_outfile->Write(msg_buffer, strlen(msg_buffer) );
89
90    // Display each field in the message.
91	sprintf(msg_buffer, "{\n");
92    m_outfile->Write(msg_buffer, strlen(msg_buffer) );
93	for (int32 i = 0;  B_OK == message->GetInfo(B_ANY_TYPE,
94	                                            i,
95	                                            &field_name,
96	                                            &field_type,
97	                                            &field_count);  i++)
98	{
99		message->FindData(field_name, field_type, &field_data, &field_data_bytes);
100		OutputMsgField(field_name, field_type, field_count, field_data);
101	}
102	sprintf(msg_buffer, "}\n");
103    m_outfile->Write(msg_buffer, strlen(msg_buffer) );
104
105	return (B_DISPATCH_MESSAGE);
106}
107
108//-------------------------------------------------------------------------
109//-------------------------------------------------------------------------
110const char* MsgSpy::MapWhatToString(uint32 w)
111{
112    const char* s;
113	switch (w)
114	{
115		// Pointing device event messages.
116		case B_MOUSE_DOWN:					s = "B_MOUSE_DOWN";					break;
117		case B_MOUSE_UP:					s = "B_MOUSE_UP";					break;
118		case B_MOUSE_MOVED:					s = "B_MOUSE_MOVED";				break;
119		case B_MOUSE_WHEEL_CHANGED:				s = "B_MOUSE_WHEEL_CHANGED";			break;
120
121		// Keyboard device event messages.
122		case B_KEY_DOWN:					s = "B_KEY_DOWN";					break;
123		case B_UNMAPPED_KEY_DOWN:			s = "B_UNMAPPED_KEY_DOWN";			break;
124		case B_KEY_UP:						s = "B_KEY_UP";						break;
125		case B_UNMAPPED_KEY_UP:				s = "B_UNMAPPED_KEY_UP";			break;
126		case B_MODIFIERS_CHANGED:			s = "B_MODIFIERS_CHANGED";			break;
127
128		case B_INPUT_METHOD_EVENT:			s = "B_INPUT_METHOD_EVENT";			break;
129		default:							s = "UNKNOWN_MESSAGE";				break;
130	}
131	return s;
132}
133
134//-------------------------------------------------------------------------
135//-------------------------------------------------------------------------
136void MsgSpy::OutputMsgField(const char*  fieldName,
137                            const uint32 rawType,
138                            int          rawCount,
139                            const void*  rawData)
140{
141	char        msg_buffer   [1024];
142	char        value_buffer [256];
143	BString     field_data;
144    const char* field_type;
145    const int   field_count  = rawCount;
146    const char* separator;
147
148	switch (rawType)
149	{
150		case B_CHAR_TYPE:
151		{
152			field_type = "B_CHAR_TYPE";
153			field_data << "{ ";
154			for (const char* data_ptr = (const char*)rawData;
155				rawCount > 0;
156				rawCount--, data_ptr++)
157			{
158				separator = (1 < rawCount) ? ", " : " }";
159				field_data << *data_ptr << separator;
160			}
161			break;
162		}
163
164		case B_INT8_TYPE:
165		{
166			field_type = "B_INT8_TYPE";
167			field_data << "{ ";
168			for (const int8* data_ptr = (const int8*)rawData;
169				rawCount > 0;
170				rawCount--, data_ptr++)
171			{
172				separator = (1 < rawCount) ? ", " : " }";
173				field_data << *data_ptr << separator;
174			}
175			break;
176		}
177
178		case B_INT16_TYPE:
179		{
180			field_type = "B_INT16_TYPE";
181			field_data << "{ ";
182			for (const int16* data_ptr = (const int16*)rawData;
183				rawCount > 0;
184				rawCount--, data_ptr++)
185			{
186				separator = (1 < rawCount) ? ", " : " }";
187				field_data << *data_ptr << separator;
188			}
189			break;
190		}
191
192		case B_INT32_TYPE:
193		{
194			field_type = "B_INT32_TYPE";
195			field_data << "{ ";
196			for (const int32* data_ptr = (const int32*)rawData;
197				rawCount > 0;
198				rawCount--, data_ptr++)
199			{
200				separator = (1 < rawCount) ? ", " : " }";
201				field_data << *data_ptr << separator;
202			}
203			break;
204		}
205
206		case B_INT64_TYPE:
207		{
208			field_type = "B_INT64_TYPE";
209			field_data << "{ ";
210			for (const int64* data_ptr = (const int64*)rawData;
211				rawCount > 0;
212				rawCount--, data_ptr++)
213			{
214				separator = (1 < rawCount) ? ", " : " }";
215				field_data << *data_ptr << separator;
216			}
217			break;
218		}
219
220		case B_UINT8_TYPE:
221		{
222			field_type = "B_UINT8_TYPE";
223			field_data << "{ ";
224			for (const uint8* data_ptr = (const uint8*)rawData;
225				rawCount > 0;
226				rawCount--, data_ptr++)
227			{
228				separator = (1 < rawCount) ? ", " : " }";
229				field_data << (uint32)(*data_ptr) << separator;
230			}
231			break;
232		}
233
234		case B_UINT16_TYPE:
235		{
236			field_type = "B_UINT16_TYPE";
237			field_data << "{ ";
238			for (const uint16* data_ptr = (const uint16*)rawData;
239				rawCount > 0;
240				rawCount--, data_ptr++)
241			{
242				separator = (1 < rawCount) ? ", " : " }";
243				field_data << (uint32)(*data_ptr) << separator;
244			}
245			break;
246		}
247
248		case B_UINT32_TYPE:
249		{
250			field_type = "B_UINT32_TYPE";
251			field_data << "{ ";
252			for (const uint32* data_ptr = (const uint32*)rawData;
253				rawCount > 0;
254				rawCount--, data_ptr++)
255			{
256				separator = (1 < rawCount) ? ", " : " }";
257				field_data << *data_ptr << separator;
258			}
259			break;
260		}
261
262		case B_UINT64_TYPE:
263		{
264			field_type = "B_UINT64_TYPE";
265			field_data << "{ ";
266			for (const uint64* data_ptr = (const uint64*)rawData;
267				rawCount > 0;
268				rawCount--, data_ptr++)
269			{
270				separator = (1 < rawCount) ? ", " : " }";
271				field_data << *data_ptr << separator;
272			}
273			break;
274		}
275
276		case B_FLOAT_TYPE:
277		{
278			field_type = "B_FLOAT_TYPE";
279			field_data << "{ ";
280			for (const float* data_ptr = (const float*)rawData;
281				rawCount > 0;
282				rawCount--, data_ptr++)
283			{
284				separator = (1 < rawCount) ? ", " : " }";
285				field_data << *data_ptr << separator;
286			}
287			break;
288		}
289
290		case B_DOUBLE_TYPE:
291		{
292			field_type = "B_DOUBLE_TYPE";
293			field_data << "{ ";
294			for (const double* data_ptr = (const double*)rawData;
295				rawCount > 0;
296				rawCount--, data_ptr++)
297			{
298				separator = (1 < rawCount) ? ", " : " }";
299				sprintf(value_buffer, "%f", *data_ptr);
300				field_data << value_buffer << separator;
301			}
302			break;
303		}
304
305		case B_BOOL_TYPE:
306		{
307			field_type = "B_BOOL_TYPE";
308			field_data << "{ ";
309			for (const bool* data_ptr = (const bool*)rawData;
310				rawCount > 0;
311				rawCount--, data_ptr++)
312			{
313				separator = (1 < rawCount) ? ", " : " }";
314				sprintf(value_buffer, "%s", (true == *data_ptr) ? "true" : "false");
315				field_data << value_buffer << separator;
316			}
317			break;
318		}
319
320		case B_OFF_T_TYPE:
321		{
322			field_type = "B_OFF_T_TYPE";
323			field_data << "{ ";
324			for (const off_t* data_ptr = (const off_t*)rawData;
325				rawCount > 0;
326				rawCount--, data_ptr++)
327			{
328				separator = (1 < rawCount) ? ", " : " }";
329				field_data << *data_ptr << separator;
330			}
331			break;
332		}
333
334		case B_SIZE_T_TYPE:
335		{
336			field_type = "B_SIZE_T_TYPE";
337			field_data << "{ ";
338			for (const size_t* data_ptr = (const size_t*)rawData;
339				rawCount > 0;
340				rawCount--, data_ptr++)
341			{
342				separator = (1 < rawCount) ? ", " : " }";
343				field_data << *data_ptr << separator;
344			}
345			break;
346		}
347
348		case B_SSIZE_T_TYPE:
349		{
350			field_type = "B_SSIZE_T_TYPE";
351			field_data << "{ ";
352			for (const ssize_t* data_ptr = (const ssize_t*)rawData;
353				rawCount > 0;
354				rawCount--, data_ptr++)
355			{
356				separator = (1 < rawCount) ? ", " : " }";
357				field_data << *data_ptr << separator;
358			}
359			break;
360		}
361
362		case B_POINTER_TYPE:
363		{
364			field_type = "B_POINTER_TYPE";
365			break;
366		}
367
368		case B_OBJECT_TYPE:
369		{
370			field_type = "B_OBJECT_TYPE";
371			break;
372		}
373
374		case B_MESSAGE_TYPE:
375		{
376			field_type = "B_MESSAGE_TYPE";
377			break;
378		}
379
380		case B_MESSENGER_TYPE:
381		{
382			field_type = "B_MESSENGER_TYPE";
383			break;
384		}
385
386		case B_POINT_TYPE:
387		{
388			field_type = "B_POINT_TYPE";
389			field_data << "{ ";
390			for (const BPoint* data_ptr = (const BPoint*)rawData;
391				rawCount > 0;
392				rawCount--, data_ptr++)
393			{
394				separator = (1 < rawCount) ? ", " : " }";
395				field_data << "(" << data_ptr->x << ", " << data_ptr->y << ")" << separator;
396			}
397			break;
398		}
399
400		case B_RECT_TYPE:
401		{
402			field_type = "B_RECT_TYPE";
403			break;
404		}
405
406//		case B_PATH_TYPE:					s = "B_PATH_TYPE";					break;
407
408		case B_REF_TYPE:
409		{
410			field_type = "B_REF_TYPE";
411			break;
412		}
413
414		case B_RGB_COLOR_TYPE:
415		{
416			field_type = "B_RGB_COLOR_TYPE";
417			break;
418		}
419
420		case B_PATTERN_TYPE:
421		{
422			field_type = "B_PATTERN_TYPE";
423			break;
424		}
425
426		case B_STRING_TYPE:
427		{
428			field_type = "B_STRING_TYPE";
429			field_data << "{ ";
430			for (const char* data_ptr = (const char*)rawData;
431				rawCount > 0;
432				rawCount--, data_ptr+= strlen(data_ptr) )
433			{
434				separator = (1 < rawCount) ? ", " : " }";
435				field_data << "\"" << data_ptr << "\"" << separator;
436			}
437			break;
438		}
439
440		case B_MONOCHROME_1_BIT_TYPE:
441		{
442			field_type = "B_MONOCHROME_1_BIT_TYPE";
443			break;
444		}
445
446		case B_GRAYSCALE_8_BIT_TYPE:
447		{
448			field_type = "B_GRAYSCALE_8_BIT_TYPE";
449			break;
450		}
451
452		case B_COLOR_8_BIT_TYPE:
453		{
454			field_type = "B_COLOR_8_BIT_TYPE";
455			break;
456		}
457
458		case B_RGB_32_BIT_TYPE:
459		{
460			field_type = "B_RGB_32_BIT_TYPE";
461			break;
462		}
463
464		case B_TIME_TYPE:
465		{
466			field_type = "B_TIME_TYPE";
467			break;
468		}
469
470		case B_MEDIA_PARAMETER_TYPE:
471		{
472			field_type = "B_MEDIA_PARAMETER_TYPE";
473			break;
474		}
475
476		case B_MEDIA_PARAMETER_WEB_TYPE:
477		{
478			field_type = "B_MEDIA_PARAMETER_WEB_TYPE";
479			break;
480		}
481
482		case B_MEDIA_PARAMETER_GROUP_TYPE:
483		{
484			field_type = "B_MEDIA_PARAMETER_GROUP_TYPE";
485			break;
486		}
487
488		case B_RAW_TYPE:
489		{
490			field_type = "B_RAW_TYPE";
491			break;
492		}
493
494		case B_MIME_TYPE:
495		{
496			field_type = "B_MIME_TYPE";
497			break;
498		}
499
500		case B_ANY_TYPE:
501		{
502			field_type = "B_ANY_TYPE";
503			break;
504		}
505
506		default:
507		{
508			field_type = "UNKNOWN_TYPE";
509			break;
510		}
511	}
512
513    sprintf(msg_buffer,
514            "    %-18s %-18s [%2d] = %s\n",
515            field_type,
516            fieldName,
517            field_count,
518            field_data.String() );
519
520    m_outfile->Write(msg_buffer, strlen(msg_buffer) );
521}
522