[cosmetics] update date in GPL header
[vuplus_xbmc] / tools / EventClients / lib / c# / EventClient.cs
1 /*
2  *  Copyright (C) 2008-2013 Team XBMC
3  *
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 2 of the License, or
7  *  (at your option) any later version.
8  *
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.
13  *
14  *  You should have received a copy of the GNU General Public License along
15  *  with this program; if not, write to the Free Software Foundation, Inc.,
16  *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17  */
18
19 using System;
20 using System.IO;
21 using System.Net;
22 using System.Net.Sockets;
23
24 namespace XBMC
25 {
26
27     public enum IconType
28     {
29         ICON_NONE = 0x00,
30         ICON_JPEG = 0x01,
31         ICON_PNG = 0x02,
32         ICON_GIF = 0x03
33     }
34
35     public enum ButtonFlagsType
36     {
37         BTN_USE_NAME = 0x01,
38         BTN_DOWN = 0x02,
39         BTN_UP = 0x04,
40         BTN_USE_AMOUNT = 0x08,
41         BTN_QUEUE = 0x10,
42         BTN_NO_REPEAT = 0x20,
43         BTN_VKEY = 0x40,
44         BTN_AXIS = 0x80
45     }
46
47     public enum MouseFlagsType
48     {
49         MS_ABSOLUTE = 0x01
50     }
51
52     public enum LogTypeEnum
53     {
54         LOGDEBUG = 0,
55         LOGINFO = 1,
56         LOGNOTICE = 2,
57         LOGWARNING = 3,
58         LOGERROR = 4,
59         LOGSEVERE = 5,
60         LOGFATAL = 6,
61         LOGNONE = 7
62     }
63
64     public enum ActionType
65     {
66         ACTION_EXECBUILTIN = 0x01,
67         ACTION_BUTTON = 0x02
68     }
69
70     public class EventClient
71     {
72
73         /************************************************************************/
74         /* Written by Peter Tribe aka EqUiNox (TeamBlackbolt)                   */
75         /* Based upon XBMC's xbmcclient.cpp class                               */
76         /************************************************************************/
77
78         private enum PacketType
79         {
80             PT_HELO = 0x01,
81             PT_BYE = 0x02,
82             PT_BUTTON = 0x03,
83             PT_MOUSE = 0x04,
84             PT_PING = 0x05,
85             PT_BROADCAST = 0x06,  //Currently not implemented
86             PT_NOTIFICATION = 0x07,
87             PT_BLOB = 0x08,
88             PT_LOG = 0x09,
89             PT_ACTION = 0x0A,
90             PT_DEBUG = 0xFF //Currently not implemented
91         }
92
93         private const int STD_PORT = 9777;
94         private const int MAX_PACKET_SIZE = 1024;
95         private const int HEADER_SIZE = 32;
96         private const int MAX_PAYLOAD_SIZE = MAX_PACKET_SIZE - HEADER_SIZE;
97         private const byte MAJOR_VERSION = 2;
98         private const byte MINOR_VERSION = 0;
99
100         private uint uniqueToken;
101         private Socket socket;
102
103         public bool Connect(string Address)
104         {
105             return Connect(Address, STD_PORT, (uint)System.DateTime.Now.TimeOfDay.Milliseconds);
106         }
107
108         public bool Connect(string Address, int Port)
109         {
110             return Connect(Address, Port, (uint)System.DateTime.Now.TimeOfDay.Milliseconds);
111         }
112
113
114         public bool Connect(string Address, int Port, uint UID)
115         {
116             try
117             {
118                 if (socket != null) Disconnect();
119                 uniqueToken = UID;
120                 socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
121
122 // For compilation with .net framework 1.0 or 1.1
123 // define the FRAMEWORK_1_x conditional compilation constant in the project
124 // or add /define:FRAMEWORK_1_x to the csc.exe command line
125 #if FRAMEWORK_1_x
126                 socket.Connect(Dns.GetHostByName(Address).AddressList[0].ToString(), Port);
127 #else
128                 socket.Connect(Address, Port);
129 #endif
130                 return true;
131             }
132             catch
133             {
134                 return false;
135             }
136         }
137
138         public bool Connected
139         {
140             get
141             {
142                 if (socket == null) return false;
143                 return socket.Connected;
144             }
145         }
146
147         public void Disconnect()
148         {
149             try
150             {
151                 if (socket != null)
152                 {
153                     socket.Shutdown(SocketShutdown.Both);
154                     socket.Close();
155                     socket = null;
156                 }
157             }
158             catch
159             {
160             }
161         }
162
163         private byte[] Header(PacketType PacketType, int NumberOfPackets, int CurrentPacket, int PayloadSize)
164         {
165
166             byte[] header = new byte[HEADER_SIZE];
167
168             header[0] = (byte)'X';
169             header[1] = (byte)'B';
170             header[2] = (byte)'M';
171             header[3] = (byte)'C';
172
173             header[4] = MAJOR_VERSION;
174             header[5] = MINOR_VERSION;
175
176             if (CurrentPacket == 1)
177             {
178                 header[6] = (byte)(((ushort)PacketType & 0xff00) >> 8);
179                 header[7] = (byte)((ushort)PacketType & 0x00ff);
180             }
181             else
182             {
183                 header[6] = (byte)(((ushort)PacketType.PT_BLOB & 0xff00) >> 8);
184                 header[7] = (byte)((ushort)PacketType.PT_BLOB & 0x00ff);
185             }
186
187             header[8] = (byte)((CurrentPacket & 0xff000000) >> 24);
188             header[9] = (byte)((CurrentPacket & 0x00ff0000) >> 16);
189             header[10] = (byte)((CurrentPacket & 0x0000ff00) >> 8);
190             header[11] = (byte)(CurrentPacket & 0x000000ff);
191
192             header[12] = (byte)((NumberOfPackets & 0xff000000) >> 24);
193             header[13] = (byte)((NumberOfPackets & 0x00ff0000) >> 16);
194             header[14] = (byte)((NumberOfPackets & 0x0000ff00) >> 8);
195             header[15] = (byte)(NumberOfPackets & 0x000000ff);
196
197             header[16] = (byte)((PayloadSize & 0xff00) >> 8);
198             header[17] = (byte)(PayloadSize & 0x00ff);
199
200             header[18] = (byte)((uniqueToken & 0xff000000) >> 24);
201             header[19] = (byte)((uniqueToken & 0x00ff0000) >> 16);
202             header[20] = (byte)((uniqueToken & 0x0000ff00) >> 8);
203             header[21] = (byte)(uniqueToken & 0x000000ff);
204
205             return header;
206
207         }
208
209         private bool Send(PacketType PacketType, byte[] Payload)
210         {
211             try
212             {
213
214                 bool successfull = true;
215                 int packetCount = (Payload.Length / MAX_PAYLOAD_SIZE) + 1;
216                 int bytesToSend = 0;
217                 int bytesSent = 0;
218                 int bytesLeft = Payload.Length;
219
220                 for (int Package = 1; Package <= packetCount; Package++)
221                 {
222
223                     if (bytesLeft > MAX_PAYLOAD_SIZE)
224                     {
225                         bytesToSend = MAX_PAYLOAD_SIZE;
226                         bytesLeft -= bytesToSend;
227                     }
228                     else
229                     {
230                         bytesToSend = bytesLeft;
231                         bytesLeft = 0;
232                     }
233
234                     byte[] header = Header(PacketType, packetCount, Package, bytesToSend);
235                     byte[] packet = new byte[MAX_PACKET_SIZE];
236
237                     Array.Copy(header, 0, packet, 0, header.Length);
238                     Array.Copy(Payload, bytesSent, packet, header.Length, bytesToSend);
239
240                     int sendSize = socket.Send(packet, header.Length + bytesToSend, SocketFlags.None);
241
242                     if (sendSize != (header.Length + bytesToSend))
243                     {
244                         successfull = false;
245                         break;
246                     }
247
248                     bytesSent += bytesToSend;
249
250                 }
251
252                 return successfull;
253
254             }
255             catch
256             {
257
258                 return false;
259
260             }
261
262         }
263
264         /************************************************************************/
265         /* SendHelo - Payload format                                            */
266         /* %s -  device name (max 128 chars)                                    */
267         /* %c -  icontype ( 0=>NOICON, 1=>JPEG , 2=>PNG , 3=>GIF )              */
268         /* %s -  my port ( 0=>not listening )                                   */
269         /* %d -  reserved1 ( 0 )                                                */
270         /* %d -  reserved2 ( 0 )                                                */
271         /* XX -  imagedata ( can span multiple packets )                        */
272         /************************************************************************/
273         public bool SendHelo(string DevName, IconType IconType, string IconFile)
274         {
275
276             byte[] icon = new byte[0];
277             if (IconType != IconType.ICON_NONE)
278                 icon = File.ReadAllBytes(IconFile);
279
280             byte[] payload = new byte[DevName.Length + 12 + icon.Length];
281
282             int offset = 0;
283
284             for (int i = 0; i < DevName.Length; i++)
285                 payload[offset++] = (byte)DevName[i];
286             payload[offset++] = (byte)'\0';
287
288             payload[offset++] = (byte)IconType;
289
290             payload[offset++] = (byte)0;
291             payload[offset++] = (byte)'\0';
292
293             for (int i = 0; i < 8; i++)
294                 payload[offset++] = (byte)0;
295
296             Array.Copy(icon, 0, payload, DevName.Length + 12, icon.Length);
297
298             return Send(PacketType.PT_HELO, payload);
299
300         }
301
302         public bool SendHelo(string DevName)
303         {
304             return SendHelo(DevName, IconType.ICON_NONE, "");
305         }
306
307         /************************************************************************/
308         /* SendNotification - Payload format                                    */
309         /* %s - caption                                                         */
310         /* %s - message                                                         */
311         /* %c - icontype ( 0=>NOICON, 1=>JPEG , 2=>PNG , 3=>GIF )               */
312         /* %d - reserved ( 0 )                                                  */
313         /* XX - imagedata ( can span multiple packets )                         */
314         /************************************************************************/
315         public bool SendNotification(string Caption, string Message, IconType IconType, string IconFile)
316         {
317
318             byte[] icon = new byte[0];
319             if (IconType != IconType.ICON_NONE)
320                 icon = File.ReadAllBytes(IconFile);
321
322             byte[] payload = new byte[Caption.Length + Message.Length + 7 + icon.Length];
323
324             int offset = 0;
325
326             for (int i = 0; i < Caption.Length; i++)
327                 payload[offset++] = (byte)Caption[i];
328             payload[offset++] = (byte)'\0';
329
330             for (int i = 0; i < Message.Length; i++)
331                 payload[offset++] = (byte)Message[i];
332             payload[offset++] = (byte)'\0';
333
334             payload[offset++] = (byte)IconType;
335
336             for (int i = 0; i < 4; i++)
337                 payload[offset++] = (byte)0;
338
339             Array.Copy(icon, 0, payload, Caption.Length + Message.Length + 7, icon.Length);
340
341             return Send(PacketType.PT_NOTIFICATION, payload);
342
343         }
344
345         public bool SendNotification(string Caption, string Message)
346         {
347             return SendNotification(Caption, Message, IconType.ICON_NONE, "");
348         }
349
350         /************************************************************************/
351         /* SendButton - Payload format                                          */
352         /* %i - button code                                                     */
353         /* %i - flags 0x01 => use button map/name instead of code               */
354         /*            0x02 => btn down                                          */
355         /*            0x04 => btn up                                            */
356         /*            0x08 => use amount                                        */
357         /*            0x10 => queue event                                       */
358         /*            0x20 => do not repeat                                     */
359         /*            0x40 => virtual key                                       */
360         /*            0x80 => axis key                                          */
361         /* %i - amount ( 0 => 65k maps to -1 => 1 )                             */
362         /* %s - device map (case sensitive and required if flags & 0x01)        */
363         /*      "KB" - Standard keyboard map                                    */
364         /*      "XG" - Xbox Gamepad                                             */
365         /*      "R1" - Xbox Remote                                              */
366         /*      "R2" - Xbox Universal Remote                                    */
367         /*      "LI:devicename" -  valid LIRC device map where 'devicename'     */
368         /*                         is the actual name of the LIRC device        */
369         /*      "JS<num>:joyname" -  valid Joystick device map where            */
370         /*                           'joyname'  is the name specified in        */
371         /*                           the keymap. JS only supports button code   */
372         /*                           and not button name currently (!0x01).     */
373         /* %s - button name (required if flags & 0x01)                          */
374         /************************************************************************/
375         private bool SendButton(string Button, ushort ButtonCode, string DeviceMap, ButtonFlagsType Flags, short Amount)
376         {
377
378             if (Button.Length != 0)
379             {
380                 if ((Flags & ButtonFlagsType.BTN_USE_NAME) == 0)
381                     Flags |= ButtonFlagsType.BTN_USE_NAME;
382                 ButtonCode = 0;
383             }
384             else
385                 Button = "";
386
387             if (Amount > 0)
388             {
389                 if ((Flags & ButtonFlagsType.BTN_USE_AMOUNT) == 0)
390                     Flags |= ButtonFlagsType.BTN_USE_AMOUNT;
391             }
392
393             if ((Flags & ButtonFlagsType.BTN_DOWN) == 0 && (Flags & ButtonFlagsType.BTN_UP) == 0)
394                 Flags |= ButtonFlagsType.BTN_DOWN;
395
396             byte[] payload = new byte[Button.Length + DeviceMap.Length + 8];
397
398             int offset = 0;
399
400             payload[offset++] = (byte)((ButtonCode & 0xff00) >> 8);
401             payload[offset++] = (byte)(ButtonCode & 0x00ff);
402
403             payload[offset++] = (byte)(((ushort)Flags & 0xff00) >> 8);
404             payload[offset++] = (byte)((ushort)Flags & 0x00ff);
405
406             payload[offset++] = (byte)((Amount & 0xff00) >> 8);
407             payload[offset++] = (byte)(Amount & 0x00ff);
408
409             for (int i = 0; i < DeviceMap.Length; i++)
410                 payload[offset++] = (byte)DeviceMap[i];
411             payload[offset++] = (byte)'\0';
412
413             for (int i = 0; i < Button.Length; i++)
414                 payload[offset++] = (byte)Button[i];
415             payload[offset++] = (byte)'\0';
416
417             return Send(PacketType.PT_BUTTON, payload);
418
419         }
420
421         public bool SendButton(string Button, string DeviceMap, ButtonFlagsType Flags, short Amount)
422         {
423             return SendButton(Button, 0, DeviceMap, Flags, Amount);
424         }
425
426         public bool SendButton(string Button, string DeviceMap, ButtonFlagsType Flags)
427         {
428             return SendButton(Button, 0, DeviceMap, Flags, 0);
429         }
430
431         public bool SendButton(ushort ButtonCode, string DeviceMap, ButtonFlagsType Flags, short Amount)
432         {
433             return SendButton("", ButtonCode, DeviceMap, Flags, Amount);
434         }
435
436         public bool SendButton(ushort ButtonCode, string DeviceMap, ButtonFlagsType Flags)
437         {
438             return SendButton("", ButtonCode, DeviceMap, Flags, 0);
439         }
440
441         public bool SendButton(ushort ButtonCode, ButtonFlagsType Flags, short Amount)
442         {
443             return SendButton("", ButtonCode, "", Flags, Amount);
444         }
445
446         public bool SendButton(ushort ButtonCode, ButtonFlagsType Flags)
447         {
448             return SendButton("", ButtonCode, "", Flags, 0);
449         }
450
451         public bool SendButton()
452         {
453             return SendButton("", 0, "", ButtonFlagsType.BTN_UP, 0);
454         }
455
456         /************************************************************************/
457         /* SendPing - No payload                                                */
458         /************************************************************************/
459         public bool SendPing()
460         {
461             byte[] payload = new byte[0];
462             return Send(PacketType.PT_PING, payload);
463         }
464
465         /************************************************************************/
466         /* SendBye - No payload                                                 */
467         /************************************************************************/
468         public bool SendBye()
469         {
470             byte[] payload = new byte[0];
471             return Send(PacketType.PT_BYE, payload);
472         }
473
474         /************************************************************************/
475         /* SendMouse - Payload format                                           */
476         /* %c - flags                                                           */
477         /*    - 0x01 absolute position                                          */
478         /* %i - mousex (0-65535 => maps to screen width)                        */
479         /* %i - mousey (0-65535 => maps to screen height)                       */
480         /************************************************************************/
481         public bool SendMouse(ushort X, ushort Y, MouseFlagsType Flags)
482         {
483
484             byte[] payload = new byte[9];
485
486             int offset = 0;
487
488             payload[offset++] = (byte)Flags;
489
490             payload[offset++] = (byte)((X & 0xff00) >> 8);
491             payload[offset++] = (byte)(X & 0x00ff);
492
493             payload[offset++] = (byte)((Y & 0xff00) >> 8);
494             payload[offset++] = (byte)(Y & 0x00ff);
495
496             return Send(PacketType.PT_MOUSE, payload);
497
498         }
499
500         public bool SendMouse(ushort X, ushort Y)
501         {
502             return SendMouse(X, Y, MouseFlagsType.MS_ABSOLUTE);
503         }
504
505         /************************************************************************/
506         /* SendLog - Payload format                                             */
507         /* %c - log type                                                        */
508         /* %s - message                                                         */
509         /************************************************************************/
510         public bool SendLog(LogTypeEnum LogLevel, string Message)
511         {
512
513             byte[] payload = new byte[Message.Length + 2];
514
515             int offset = 0;
516
517             payload[offset++] = (byte)LogLevel;
518
519             for (int i = 0; i < Message.Length; i++)
520                 payload[offset++] = (byte)Message[i];
521             payload[offset++] = (byte)'\0';
522
523             return Send(PacketType.PT_LOG, payload);
524
525         }
526
527         /************************************************************************/
528         /* SendAction - Payload format                                          */
529         /* %c - action type                                                     */
530         /* %s - action message                                                  */
531         /************************************************************************/
532         public bool SendAction(ActionType Action, string Message)
533         {
534
535             byte[] payload = new byte[Message.Length + 2];
536
537             int offset = 0;
538
539             payload[offset++] = (byte)Action;
540
541             for (int i = 0; i < Message.Length; i++)
542                 payload[offset++] = (byte)Message[i];
543             payload[offset++] = (byte)'\0';
544
545             return Send(PacketType.PT_ACTION, payload);
546
547         }
548
549         public bool SendAction(string Message)
550         {
551             return SendAction(ActionType.ACTION_EXECBUILTIN, Message);
552         }
553
554     }
555 }