]> git.vomp.tv Git - vompclient.git/blob - command.cc
0.2.7 readiness patches for Windows
[vompclient.git] / command.cc
1 /*
2     Copyright 2004-2005 Chris Tallon
3
4     This file is part of VOMP.
5
6     VOMP is free software; you can redistribute it and/or modify
7     it under the terms of the GNU General Public License as published by
8     the Free Software Foundation; either version 2 of the License, or
9     (at your option) any later version.
10
11     VOMP is distributed in the hope that it will be useful,
12     but WITHOUT ANY WARRANTY; without even the implied warranty of
13     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14     GNU General Public License for more details.
15
16     You should have received a copy of the GNU General Public License
17     along with VOMP; if not, write to the Free Software
18     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19 */
20
21 #ifndef WIN32
22 #include <linux/errno.h>
23 #endif
24
25 #include "command.h"
26
27 #ifdef WIN32
28 #include "remotewin.h"
29 #endif
30
31 #include "led.h"
32 #include "video.h"
33 #include "audio.h"
34 #include "vdr.h"
35 #include "vvolume.h"
36 #include "vserverselect.h"
37 #include "vwelcome.h"
38 #include "vmute.h"
39 #include "colour.h"
40 #include "osd.h"
41 #include "i18n.h"
42 #include "timerreceiver.h"
43 #include "timers.h"
44 #include "wol.h"
45 #include "vvideolive.h"
46 #include "vconnect.h"
47 #include "message.h"
48 #include "remote.h"
49 #include "vinfo.h"
50 #include "boxx.h"
51 #include "boxstack.h"
52 #include "log.h"
53
54
55 Command* Command::instance = NULL;
56
57 Command::Command()
58 {
59   if (instance) return;
60   instance = this;
61   initted = 0;
62   isStandby = 0;
63   firstBoot = 1;
64   connLost = NULL;
65 }
66
67 Command::~Command()
68 {
69   instance = NULL;
70 }
71
72 Command* Command::getInstance()
73 {
74   return instance;
75 }
76
77 int Command::init()
78 {
79   if (initted) return 0;
80   initted = 1;
81
82   logger = Log::getInstance();
83   boxstack = BoxStack::getInstance();
84   remote = Remote::getInstance();
85   
86   if (!logger || !boxstack || !remote)
87   {
88     initted = 0;
89     return 0;
90   }
91 #ifndef WIN32
92   pthread_mutex_init(&masterLock, NULL);
93 #else
94   masterLock=CreateMutex(NULL,FALSE,NULL);
95 #endif
96
97   return 1;
98 }
99
100 int Command::shutdown()
101 {
102   if (!initted) return 0;
103   initted = 0;
104   return 1;
105 }
106
107 void Command::stop()
108 {
109 //  VDR::getInstance()->cancelFindingServer();
110   udp.shutdown();
111   irun = 0;
112 }
113
114 void Command::doWallpaper()
115 {
116   Video* video = Video::getInstance();
117
118   // Blue background
119   Boxx* bbg = new Boxx();
120   bbg->setSize(video->getScreenWidth(), video->getScreenHeight());
121   bbg->createBuffer();
122   bbg->fillColour(Colour::VIDEOBLUE);
123   boxstack->add(bbg);
124   boxstack->update(bbg);
125   boxstack->remove(bbg);
126
127   // Wallpaper
128   WJpeg* wallpaperj = new WJpeg();
129   wallpaperj->setSize(video->getScreenWidth(), video->getScreenHeight());
130   wallpaperj->createBuffer();
131
132   if (video->getFormat() == Video::PAL)
133   {
134     logger->log("Command", Log::DEBUG, "PAL wallpaper selected");
135     wallpaperj->init("/wallpaperPAL.jpg");
136   }
137   else
138   {
139     logger->log("Command", Log::DEBUG, "NTSC wallpaper selected");
140     wallpaperj->init("/wallpaperNTSC.jpg");
141   }
142   wallpaperj->draw();
143
144   boxstack->add(wallpaperj);
145   boxstack->update(wallpaperj);
146
147   wallpaper = wallpaperj;
148 }
149
150 void Command::run()
151 {
152   if (!initted) return;
153   irun = 1;
154 #ifndef WIN32
155   mainPid = getpid();
156 #endif
157
158   // just in case
159   Video::getInstance()->signalOn();
160   Led::getInstance()->on();
161
162   doWallpaper();
163
164   // End of startup. Lock the mutex and put the first view up
165 //  logger->log("Command", Log::DEBUG, "WANT LOCK");
166 #ifndef WIN32
167   pthread_mutex_lock(&masterLock);
168 #else
169   WaitForSingleObject(masterLock, INFINITE );
170 #endif
171   //logger->log("Command", Log::DEBUG, "LOCKED");
172
173   VConnect* vconnect = new VConnect();
174   boxstack->add(vconnect);
175   vconnect->run();
176
177   // Start method 2 of getting commands in...
178   udp.run(this);
179
180   UCHAR button = 0;
181   while(irun)
182   {
183     // unlock and wait
184     //logger->log("Command", Log::DEBUG, "UNLOCK");
185 #ifndef WIN32
186     pthread_mutex_unlock(&masterLock);
187 #else
188     ReleaseMutex(masterLock);
189 #endif
190     button = remote->getButtonPress(2);  // FIXME why is this set to 2 and not 0? so it can quit
191     // something happened, lock and process
192
193     //  logger->log("Command", Log::DEBUG, "WANT LOCK");
194 #ifndef WIN32
195     pthread_mutex_lock(&masterLock);
196 #else
197     WaitForSingleObject(masterLock, INFINITE );
198 #endif
199     // logger->log("Command", Log::DEBUG, "LOCK");
200
201     if ((button == Remote::NA_NONE) /*|| (button == Remote::NA_UNKNOWN)*/) continue;
202
203     if (button != Remote::NA_SIGNAL) handleCommand(button);
204     processMessageQueue();
205   }
206
207   //logger->log("Command", Log::DEBUG, "UNLOCK");
208 #ifndef WIN32
209   pthread_mutex_unlock(&masterLock);
210 #else
211   ReleaseMutex(masterLock);
212 #endif
213 }
214
215 void Command::postMessage(Message* m)
216 {
217   // This is locked here in case the main loop is not waiting for an event, but is processing one
218   // it could be killed but then not react to it because the signal wouldn't cause
219   // remote->getButtonPress to break
220   // locking the mutex ensures that the master thread is waiting on getButtonPress
221
222
223   //logger->log("Command", Log::DEBUG, "WANT LOCK");
224 #ifndef WIN32
225   pthread_mutex_lock(&masterLock);
226 #else
227   WaitForSingleObject(masterLock, INFINITE );
228 #endif
229   //logger->log("Command", Log::DEBUG, "LOCK");
230   MessageQueue::postMessage(m);
231
232 #ifndef WIN32
233   kill(mainPid, SIGURG);
234   pthread_mutex_unlock(&masterLock);
235 #else
236   ((RemoteWin*)Remote::getInstance())->Signal();
237   ReleaseMutex(masterLock);
238 #endif
239   //logger->log("Command", Log::DEBUG, "UNLOCK");
240 }
241
242 void Command::postMessageNoLock(Message* m)
243 {
244   // As above but use this one if this message is being posted because of a button press
245   // the mutex is already locked, locking around postMessage is not needed as the
246   // queue is guaranteed to be run when the button has been processed
247   MessageQueue::postMessage(m);
248 }
249
250 bool Command::postMessageIfNotBusy(Message* m)
251 {
252   // Used for Windows mouse events
253
254   //logger->log("Command", Log::DEBUG, "TRY LOCK");
255 #ifndef WIN32
256   if (pthread_mutex_trylock(&masterLock) != EBUSY)
257   {
258     //logger->log("Command", Log::DEBUG, "LOCK");
259     MessageQueue::postMessage(m);
260     kill(mainPid, SIGURG);
261     pthread_mutex_unlock(&masterLock);
262     //logger->log("Command", Log::DEBUG, "UNLOCK");
263     return true;
264   }
265   else
266   {
267     return false;
268   }
269 #else
270   switch (WaitForSingleObject(masterLock, 0 ))
271   { //FIXME this is not "if not busy" check
272     case WAIT_OBJECT_0: //but with proper argument 0 this did not work
273     // case WAIT_ABANDONED:
274     MessageQueue::postMessage(m);
275     ((RemoteWin*)Remote::getInstance())->Signal();
276     ReleaseMutex(masterLock);
277     return true;
278
279     case WAIT_ABANDONED: return false;
280     case WAIT_TIMEOUT: return false;
281   }
282     return false;
283 #endif
284 }
285
286 void Command::postMessageFromOuterSpace(Message* m)
287 {
288   /*
289   Yet another way of getting messages into Command. This one is for events that
290   are not standard button presses (or UDP generated buttons). It is also not for
291   events that are generated as a result of other events (events that can safely
292   call postMessageNoLock and be guaranteed that the message will be processed
293   because it is known that the queue is currently being processed).
294   This is for events that come from outer space and can occur when the master
295   mutex is locked or not, they need to be queued and executed but it doesn't
296   matter when.
297   Actually so far it is for events caused by the video stream - aspect ratio
298   changes. These can occur when the master mutex is locked and so postMessage
299   doesn't work. postMessageNoLock doesn't work because if the mutex *isn't*
300   locked at the time then the message could be sat around a while before
301   being noticed.
302   The whole message system was at first supposed to prevent the problem of
303   calling a function on an object that had just been deleted, by ordering
304   messages such that all calls are done before object deletion. However,
305   because of the new centralised messaging system and the fact that BoxStack
306   locates the destination object before calling it, the messaging system now
307   allows the kind of sloppy calls it was supposed to stop. Weird huh. This
308   is mentioned here because the video stream might generate an event just as
309   the user hits stop. The mutex is locked, and by the time the message
310   is examined the vvideorec/live has been deleted. This doesn't matter because
311   boxstack will drop the message if it can't find the matching object to
312   deliver it to.
313   Finally, all this is fine and dandy, except that I'm not 100% sure that
314   this sloppy postMessage and hope a queued signal will force it to be processed
315   thingy will actually work. Hmmm.
316   Lastly <g>, I will consider making the naming system a little more sane
317   if this works.
318   */
319
320   logger->log("Command", Log::DEBUG, "PMFOS called");
321   MessageQueue::postMessage(m);
322
323 #ifndef WIN32
324   kill(mainPid, SIGURG);
325 #else
326   ((RemoteWin*)Remote::getInstance())->Signal();
327 #endif
328 }
329
330 void Command::processMessage(Message* m)
331 {
332     // FIXME - a slight modification - how if messagereceivers were to register
333     // themselves as receivers to avoid the calling-a-deleted-object problem
334     // then only deliver/register/unregister would have to be protected
335
336   logger->log("Command", Log::DEBUG, "processing message %i", m->message);
337
338
339   if (m->to == this)
340   {
341     switch(m->message)
342     {
343       case Message::STANDBY:
344       {
345         doStandby();
346         break;
347       }
348
349
350       // << FIXME OBSELETE
351       case Message::STOP_PLAYBACK:
352       {
353         handleCommand(Remote::STOP); // an odd way of doing it, but so simple
354         break;
355       }
356       case Message::STREAM_END:
357       {
358         VVideoLive::getInstance()->streamEnd();
359         break;
360       }
361
362       // Also connection_lost comes from player - anywhere else?
363       // FIXME OBSELETE >>
364
365
366       case Message::VDR_CONNECTED:
367       {
368         doJustConnected((VConnect*)m->from);
369         break;
370       }
371       case Message::SCREENSHOT:
372       {
373         Osd::getInstance()->screenShot("/out.jpg");
374         break;
375       }
376       case Message::CONNECTION_LOST:
377       {
378         doFromTheTop(true);
379         break;
380       }
381       case Message::UDP_BUTTON:
382       {
383         handleCommand(m->parameter);
384         break;
385       }
386       case Message::CHANGE_LANGUAGE:
387       {
388         boxstack->removeAll();
389         boxstack->update(wallpaper);
390         I18n::initialize();
391         VWelcome* vw = new VWelcome();
392         vw->draw();
393         boxstack->add(vw);
394         boxstack->update(vw);
395         break;
396       }
397       case Message::LAST_VIEW_CLOSE:
398       {
399 //        not currently used
400 //        VWelcome* vw = new VWelcome();
401 //        vw->draw();
402 //        boxstack->add(vw);
403 //        boxstack->update(vw);
404
405         break;
406       }
407     }
408   }
409   else
410   {
411     logger->log("Command", Log::DEBUG, "Sending message to boxstack");
412     boxstack->processMessage(m);
413   }
414 }
415
416 void Command::handleCommand(int button)
417 {
418   if (isStandby && (button != Remote::POWER)) return;
419   if (!connLost && boxstack->handleCommand(button)) return; // don't send to boxstack if connLost
420
421   // command was not handled
422
423   switch(button)
424   {
425     case Remote::DF_LEFT:
426     case Remote::DF_RIGHT:
427     case Remote::VOLUMEUP:
428     case Remote::VOLUMEDOWN:
429     {
430       VVolume* v = new VVolume();
431       boxstack->add(v);
432       v->handleCommand(button); // this will draw+show
433       return;
434     }
435     case Remote::MUTE:
436     {
437       VMute* v = new VMute();
438       v->draw();
439       boxstack->add(v);
440       boxstack->update(v);
441       return;
442     }
443     case Remote::POWER:
444     {
445       doStandby();
446       return;
447     }
448     case Remote::OK:
449     {
450       if (!connLost) return; // if connLost, handle Remote::OK
451       doFromTheTop(false);
452       return;
453     }
454   }
455 }
456
457 void Command::sig1()
458 {
459 #ifdef DEV
460   Message* m = new Message(); // break into master mutex
461   m->message = Message::SCREENSHOT;
462   m->to = this;
463   postMessage(m);
464 #endif
465 }
466
467 void Command::doStandby()
468 {
469   if (isStandby)
470   {
471     Video::getInstance()->signalOn();
472     Led::getInstance()->on();
473     isStandby = 0;
474
475
476     VConnect* vconnect = new VConnect();
477     boxstack->add(vconnect);
478     vconnect->run();
479   }
480   else
481   {
482     boxstack->removeAll();
483     Video::getInstance()->signalOff();
484     boxstack->update(wallpaper);
485
486     VDR::getInstance()->configSave("General", "Last Power State", "Off");
487     VDR::getInstance()->disconnect();
488     Led::getInstance()->off();
489     isStandby = 1;
490 #ifdef WIN32
491     stop(); //different behavoiur on windows, we exit
492 #endif
493   }
494 }
495
496 void Command::doFromTheTop(bool which)
497 {
498   if (which)
499   {
500     connLost = new VInfo();
501     connLost->setSize(360, 200);
502     connLost->createBuffer();
503     if (Video::getInstance()->getFormat() == Video::PAL)
504       connLost->setPosition(190, 170);
505     else
506       connLost->setPosition(180, 120);
507     connLost->setOneLiner(tr("Connection lost"));
508     connLost->setDropThrough();
509     connLost->setBorderOn(1);
510     connLost->setTitleBarColour(Colour::DANGER);
511     connLost->okButton();
512     connLost->draw();
513     boxstack->add(connLost);
514     boxstack->update(connLost);
515     remote->clearBuffer();
516   }
517   else
518   {
519     VDR::getInstance()->disconnect();
520     boxstack->removeAll();
521     boxstack->update(wallpaper);
522     connLost = NULL;
523     VConnect* vconnect = new VConnect();
524     boxstack->add(vconnect);
525     vconnect->run();
526   }
527 }
528
529 void Command::doReboot()
530 {
531   VDR::getInstance()->disconnect();
532   // just kill it...
533   logger->log("Command", Log::NOTICE, "Reboot");
534 #ifndef WIN32
535   reboot(LINUX_REBOOT_CMD_RESTART);
536 #endif //Would we support this on windows?
537 }
538
539 void Command::connectionLost()
540 {
541   Message* m = new Message(); // break into master mutex
542   m->message = Message::CONNECTION_LOST;
543   m->to = this;
544   postMessageNoLock(m);
545 }
546
547 void Command::doJustConnected(VConnect* vconnect)
548 {
549   I18n::initialize();
550   Video* video = Video::getInstance();
551   Audio* audio = Audio::getInstance();  
552   boxstack->remove(vconnect);
553
554   VInfo* vi = new VInfo();
555   vi->setSize(400, 200);
556   vi->createBuffer();
557   if (video->getFormat() == Video::PAL)
558     vi->setPosition(170, 200);
559   else
560     vi->setPosition(160, 150);
561   vi->setOneLiner(tr("Connected, loading config"));
562   vi->draw();
563   boxstack->add(vi);
564   boxstack->update(vi);
565
566   VDR* vdr = VDR::getInstance();
567   char* config;
568
569   // See if config says to override video format (PAL/NTSC)
570   config = vdr->configLoad("General", "Override Video Format");
571   if (config)
572   {
573     logger->log("Command", Log::DEBUG, "Override Video Format is present");
574
575     if (   (!strcmp(config, "PAL") && (video->getFormat() == Video::NTSC))
576         || (!strcmp(config, "NTSC") && (video->getFormat() == Video::PAL))  )
577     {
578       // Oh sheesh, need to switch format. Bye bye TV...
579
580       // Take everything down
581       boxstack->removeAll();
582       boxstack->remove(wallpaper);
583       Osd* osd = Osd::getInstance();
584       osd->shutdown();
585       video->shutdown();
586
587       // Get video and osd back up with the new mode
588       if (!strcmp(config, "PAL"))
589       {
590         logger->log("Command", Log::DEBUG, "Switching to PAL");
591         video->init(Video::PAL);
592       }
593       else if (!strcmp(config, "NTSC"))
594       {
595         logger->log("Command", Log::DEBUG, "Switching to NTSC");
596         video->init(Video::NTSC);
597       }
598       osd->init((char*)("/dev/stbgfx"));
599
600       // Put the wallpaper back
601       doWallpaper();
602
603       // Re add the vinfo
604       vi = new VInfo();
605       vi->setSize(400, 200);
606       vi->createBuffer();
607       if (video->getFormat() == Video::PAL)
608         vi->setPosition(170, 200);
609       else
610         vi->setPosition(160, 150);
611
612       vi->setOneLiner(tr("Connected, loading config"));
613       vi->draw();
614       boxstack->add(vi);
615       boxstack->update(vi);
616     }
617     else
618     {
619       logger->log("Command", Log::DEBUG, "Already in requested mode, or request was not 'PAL' or 'NTSC'");
620     }
621   }
622   else
623   {
624     logger->log("Command", Log::DEBUG, "Phew, no dangerous on-the-fly mode switching to do!");
625   }
626
627   // Power off if first boot and config says so
628   if (firstBoot)
629   {
630     firstBoot = 0;
631
632     logger->log("Command", Log::DEBUG, "Load power after boot");
633
634     config = vdr->configLoad("General", "Power After Boot");
635
636     if (config)
637     {
638       if (!STRCASECMP(config, "On"))
639       {
640         logger->log("Command", Log::INFO, "Config says Power After Boot = On");
641       }
642       else if (!STRCASECMP(config, "Off"))
643       {
644         logger->log("Command", Log::INFO, "Config says Power After Boot = Off");
645         doStandby();
646         delete[] config;
647         return; // quit here
648       }
649       else if (!STRCASECMP(config, "Last state"))
650       {
651         char* lastPowerState = vdr->configLoad("General", "Last Power State");
652         if (lastPowerState)
653         {
654           if (!STRCASECMP(lastPowerState, "On"))
655           {
656             logger->log("Command", Log::INFO, "Config says Last Power State = On");
657           }
658           else if (!STRCASECMP(lastPowerState, "Off"))
659           {
660             logger->log("Command", Log::INFO, "Config says Last Power State = Off");
661             doStandby();
662             delete[] config;
663             return; // quit here
664           }
665           else
666           {
667             logger->log("Command", Log::INFO, "Config General/Last Power State not understood");
668           }
669         }
670         else
671         {
672           logger->log("Command", Log::INFO, "Config General/Last Power State not found");
673         }
674       }
675       else
676       {
677         logger->log("Command", Log::INFO, "Config/Power After Boot not understood");
678       }
679       delete[] config;
680     }
681     else
682     {
683       logger->log("Command", Log::INFO, "Config General/Power After Boot not found");
684     }
685   }
686
687
688   // Go S-Video if config says so
689
690   config = vdr->configLoad("TV", "Connection");
691
692   if (config)
693   {
694     if (!STRCASECMP(config, "S-Video"))
695     {
696       logger->log("Command", Log::INFO, "Switching to S-Video as Connection=%s", config);
697       video->setConnection(Video::SVIDEO);
698     }
699     else
700     {
701       logger->log("Command", Log::INFO, "Switching to RGB/Composite as Connection=%s", config);
702       video->setConnection(Video::COMPOSITERGB);
703     }
704     delete[] config;
705   }
706   else
707   {
708     logger->log("Command", Log::INFO, "Config TV/S-Video not found");
709   }
710
711   // Set remote type
712
713   config = vdr->configLoad("General", "Remote type");
714
715   if (config)
716   {
717     if (!STRCASECMP(config, "New"))
718     {
719       logger->log("Command", Log::INFO, "Switching to New remote type");
720       remote->setRemoteType(Remote::NEWREMOTE);
721     }
722     else
723     {
724       logger->log("Command", Log::INFO, "Switching to Old remote type");
725       remote->setRemoteType(Remote::OLDREMOTE);
726     }
727     delete[] config;
728   }
729   else
730   {
731     logger->log("Command", Log::INFO, "Config General/Remote type not found");
732     remote->setRemoteType(Remote::OLDREMOTE);
733   }
734
735
736
737
738   // Get TV aspect ratio
739
740   config = vdr->configLoad("TV", "Aspect");
741   if (config)
742   {
743     if (!STRCASECMP(config, "16:9"))
744     {
745       logger->log("Command", Log::INFO, "/// Switching to TV aspect 16:9");
746       video->setTVsize(Video::ASPECT16X9);
747     }
748     else
749     {
750       logger->log("Command", Log::INFO, "/// Switching to TV aspect 4:3");
751       video->setTVsize(Video::ASPECT4X3);
752     }
753     delete[] config;
754   }
755   else
756   {
757     logger->log("Command", Log::INFO, "Config TV/Aspect type not found, going 4:3");
758     video->setTVsize(Video::ASPECT4X3);
759   }
760
761   config = vdr->configLoad("TV", "Widemode");
762   if (config)
763   {
764     if (!STRCASECMP(config, "Letterbox"))
765     {
766       logger->log("Command", Log::INFO, "Setting letterbox mode");
767       video->setMode(Video::LETTERBOX);
768     }
769     else
770     {
771       logger->log("Command", Log::INFO, "Setting chop-sides mode");
772       video->setMode(Video::NORMAL);
773     }
774     delete[] config;
775   }
776   else
777   {
778     logger->log("Command", Log::INFO, "Config TV/Widemode not found, Setting chop-sides mode");
779     video->setMode(Video::NORMAL);
780   }
781
782   config = vdr->configLoad("Advanced", "TCP receive window");
783   if (config)
784   {
785     size_t newTCPsize = atoi(config);
786     delete[] config;
787
788     logger->log("Command", Log::INFO, "Setting TCP window size %i", newTCPsize);
789     vdr->setReceiveWindow(newTCPsize);
790   }
791   else
792   {
793     logger->log("Command", Log::INFO, "TCP window size not found, setting 2048");
794     vdr->setReceiveWindow(2048); // Default
795   }
796
797   config = vdr->configLoad("Advanced", "Disable WOL");
798   if (config)
799   {
800     if (!STRCASECMP(config, "Yes"))
801     {
802       logger->log("Command", Log::INFO, "Config says disable WOL");
803       Wol::getInstance()->setEnabled(false);
804     }
805     else
806     {
807       logger->log("Command", Log::INFO, "Config says enable WOL");
808       Wol::getInstance()->setEnabled(true);
809     }
810
811     delete[] config;
812   }
813   else
814   {
815     logger->log("Command", Log::INFO, "By default, enable WOL");
816     Wol::getInstance()->setEnabled(true);
817   }
818   /* device dependend config */
819   audio->loadOptionsfromServer(vdr);
820   video->loadOptionsfromServer(vdr);
821   remote->loadOptionsfromServer(vdr);
822   // config done
823
824   // Save power state = on
825
826   vdr->configSave("General", "Last Power State", "On");
827
828   // Make sure connection didn't die
829   if (!vdr->isConnected())
830   {
831     Command::getInstance()->connectionLost();
832   }
833   else
834   {
835     boxstack->remove(vi);
836
837     VWelcome* vw = new VWelcome();
838     vw->draw();
839     boxstack->add(vw);
840     boxstack->update(vw);
841
842     // Enter pre-keys here
843 //    handleCommand(Remote::SIX);
844 //    handleCommand(Remote::UP);
845 //    handleCommand(Remote::PLAY);
846 //    handleCommand(Remote::DOWN);
847 //    handleCommand(Remote::DOWN);
848 //    handleCommand(Remote::DOWN);
849 //    handleCommand(Remote::OK);
850 //    handleCommand(Remote::OK);
851 //    handleCommand(Remote::RED);
852   }
853 }