1/*
2 * Copyright 2009, Haiku, Inc.
3 * Distributed under the terms of the MIT License.
4 *
5 * Authors:
6 *		Michael Lotz <mmlr@mlotz.ch>
7 */
8
9#include "RemoteEventStream.h"
10
11#include "RemoteMessage.h"
12#include "StreamingRingBuffer.h"
13
14#include <Autolock.h>
15
16#include <new>
17
18
19RemoteEventStream::RemoteEventStream()
20	:
21	fEventList(10, true),
22	fEventListLocker("remote event list"),
23	fEventNotification(-1),
24	fWaitingOnEvent(false),
25	fLatestMouseMovedEvent(NULL),
26	fMousePosition(0, 0),
27	fMouseButtons(0),
28	fModifiers(0)
29{
30	fEventNotification = create_sem(0, "remote event notification");
31}
32
33
34RemoteEventStream::~RemoteEventStream()
35{
36	delete_sem(fEventNotification);
37}
38
39
40void
41RemoteEventStream::UpdateScreenBounds(BRect bounds)
42{
43}
44
45
46bool
47RemoteEventStream::GetNextEvent(BMessage** _event)
48{
49	BAutolock lock(fEventListLocker);
50	while (fEventList.CountItems() == 0) {
51		fWaitingOnEvent = true;
52		lock.Unlock();
53
54		status_t result;
55		do {
56			result = acquire_sem(fEventNotification);
57		} while (result == B_INTERRUPTED);
58
59		lock.Lock();
60		if (!lock.IsLocked())
61			return false;
62	}
63
64	*_event = fEventList.RemoveItemAt(0);
65	return true;
66}
67
68
69status_t
70RemoteEventStream::InsertEvent(BMessage* event)
71{
72	BAutolock lock(fEventListLocker);
73	if (!lock.IsLocked())
74		return B_ERROR;
75
76	if (!fEventList.AddItem(event))
77		return B_ERROR;
78
79	if (event->what == B_MOUSE_MOVED)
80		fLatestMouseMovedEvent = event;
81
82	return B_OK;
83}
84
85
86BMessage*
87RemoteEventStream::PeekLatestMouseMoved()
88{
89	return fLatestMouseMovedEvent;
90}
91
92
93bool
94RemoteEventStream::EventReceived(RemoteMessage& message)
95{
96	uint16 code = message.Code();
97	uint32 what = 0;
98	switch (code) {
99		case RP_MOUSE_MOVED:
100			what = B_MOUSE_MOVED;
101			break;
102		case RP_MOUSE_DOWN:
103			what = B_MOUSE_DOWN;
104			break;
105		case RP_MOUSE_UP:
106			what = B_MOUSE_UP;
107			break;
108		case RP_MOUSE_WHEEL_CHANGED:
109			what = B_MOUSE_WHEEL_CHANGED;
110			break;
111		case RP_KEY_DOWN:
112			what = B_KEY_DOWN;
113			break;
114		case RP_KEY_UP:
115			what = B_KEY_UP;
116			break;
117		case RP_MODIFIERS_CHANGED:
118			what = B_MODIFIERS_CHANGED;
119			break;
120	}
121
122	if (what == 0)
123		return false;
124
125	BMessage* event = new BMessage(what);
126	if (event == NULL)
127		return false;
128
129	event->AddInt64("when", system_time());
130
131	switch (code) {
132		case RP_MOUSE_MOVED:
133		case RP_MOUSE_DOWN:
134		case RP_MOUSE_UP:
135		{
136			message.Read(fMousePosition);
137			if (code != RP_MOUSE_MOVED)
138				message.Read(fMouseButtons);
139
140			event->AddPoint("where", fMousePosition);
141			event->AddInt32("buttons", fMouseButtons);
142			event->AddInt32("modifiers", fModifiers);
143
144			if (code == RP_MOUSE_DOWN) {
145				int32 clicks;
146				if (message.Read(clicks) == B_OK)
147					event->AddInt32("clicks", clicks);
148			}
149
150			if (code == RP_MOUSE_MOVED)
151				fLatestMouseMovedEvent = event;
152			break;
153		}
154
155		case RP_MOUSE_WHEEL_CHANGED:
156		{
157			float xDelta, yDelta;
158			message.Read(xDelta);
159			message.Read(yDelta);
160			event->AddFloat("be:wheel_delta_x", xDelta);
161			event->AddFloat("be:wheel_delta_y", yDelta);
162			break;
163		}
164
165		case RP_KEY_DOWN:
166		case RP_KEY_UP:
167		{
168			int32 numBytes;
169			if (message.Read(numBytes) != B_OK)
170				break;
171
172			if (numBytes > 1000)
173				break;
174
175			char* bytes = (char*)malloc(numBytes + 1);
176			if (bytes == NULL)
177				break;
178
179			if (message.ReadList(bytes, numBytes) != B_OK) {
180				free(bytes);
181				break;
182			}
183
184			for (int32 i = 0; i < numBytes; i++)
185				event->AddInt8("byte", (int8)bytes[i]);
186
187			bytes[numBytes] = 0;
188			event->AddData("bytes", B_STRING_TYPE, bytes, numBytes + 1, false);
189			event->AddInt32("modifiers", fModifiers);
190
191			int32 rawChar;
192			if (message.Read(rawChar) == B_OK)
193				event->AddInt32("raw_char", rawChar);
194
195			int32 key;
196			if (message.Read(key) == B_OK)
197				event->AddInt32("key", key);
198
199			free(bytes);
200			break;
201		}
202
203		case RP_MODIFIERS_CHANGED:
204		{
205			event->AddInt32("be:old_modifiers", fModifiers);
206			message.Read(fModifiers);
207			event->AddInt32("modifiers", fModifiers);
208			break;
209		}
210	}
211
212	BAutolock lock(fEventListLocker);
213	fEventList.AddItem(event);
214	if (fWaitingOnEvent) {
215		fWaitingOnEvent = false;
216		lock.Unlock();
217		release_sem(fEventNotification);
218	}
219
220	return true;
221}
222