2 Copyright 2004-2020 Chris Tallon
4 This file is part of VOMP.
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.
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.
16 You should have received a copy of the GNU General Public License
17 along with VOMP. If not, see <https://www.gnu.org/licenses/>.
20 // FIXME rename to Control and move stuff from main to here
23 #include <unistd.h> // for reboot
24 #include <linux/reboot.h>
25 #include <sys/reboot.h>
35 #include "inputandroid.h"
43 #include "vserverselect.h"
59 #include "sleeptimer.h"
61 #include "osdvector.h"
64 #ifdef VOMP_PLATFORM_RASPBERRY
65 #include "ledraspberry.h"
66 #include "osdopenvg.h"
72 #include "windowsosd.h"
74 #include "osdwinpixel.h"
76 #include "osdwinvector.h"
86 static const char* TAG = "Control";
88 Control* Control::instance = NULL;
102 Control* Control::getInstance()
107 bool Control::init(bool tcrashed)
109 if (initted) return false;
111 logger = LogNT::getInstance();
113 SkinFactory::InitSkin(0);
117 led = new Led_TYPE(); if (!led) throw 10;
118 if (!led->init(-1)) throw 11; // FIXME init(0) on Win32
120 timers = new Timers(); if (!timers) throw 20;
121 if (!timers->init()) throw 21;
123 video = new Video_TYPE(); if (!video) throw 30;
124 if (!video->init(Video::PAL)) throw 31;
126 audio = new Audio_TYPE(); if (!audio) throw 40;
127 if (!audio->init(Audio::MPEG2_PES)) throw 41;
129 osd = new Osd_TYPE(); if (!osd) throw 50;
130 if (!osd->init()) throw 51;
132 vdr = new VDR(); if (!vdr) throw 60;
133 if (!vdr->init()) throw 61;
135 boxstack = new BoxStack(); if (!boxstack) throw 70;
136 if (!boxstack->init()) throw 71;
138 sleepTimer = new SleepTimer(); if (!sleepTimer) throw 80;
140 wol = new Wol(); if (!wol) throw 90;
142 inputMan = new InputMan(); if (!inputMan) throw 100;
143 if (!inputMan->init()) throw 101;
148 if (e == 10) logger->crit(TAG, "LED module failed to create");
149 else if (e == 11) logger->crit(TAG, "LED module failed to initialise");
150 else if (e == 20) logger->crit(TAG, "Timers module failed to create");
151 else if (e == 21) logger->crit(TAG, "Timers module failed to initialise");
152 else if (e == 30) logger->crit(TAG, "Video module failed to create");
153 else if (e == 31) logger->crit(TAG, "Video module failed to initialise");
154 else if (e == 40) logger->crit(TAG, "Audio module failed to create");
155 else if (e == 41) logger->crit(TAG, "Audio module failed to initialise");
156 else if (e == 50) logger->crit(TAG, "OSD module failed to create");
157 else if (e == 51) logger->crit(TAG, "OSD module failed to initialise");
158 else if (e == 60) logger->crit(TAG, "VDR module failed to create");
159 else if (e == 61) logger->crit(TAG, "VDR module failed to initialise");
160 else if (e == 70) logger->crit(TAG, "BoxStack module failed to create");
161 else if (e == 71) logger->crit(TAG, "BoxStack module failed to initialise");
162 else if (e == 80) logger->crit(TAG, "SleepTimer module failed to create");
163 else if (e == 90) logger->crit(TAG, "WOL module failed to create");
164 else if (e == 100) logger->crit(TAG, "InputMan module failed to create");
165 else if (e == 101) logger->crit(TAG, "InputMan module failed to initialise");
182 boxstack->shutdown();
242 void Control::shutdown()
244 if (!initted) return;
249 inputMan->shutdown();
252 logger->info(TAG, "InputMan module shut down");
258 logger->info(TAG, "WOL module shut down");
265 logger->info(TAG, "SleepTimer module shut down");
270 boxstack->shutdown();
273 logger->info(TAG, "BoxStack module shut down");
281 logger->info(TAG, "VDR module shut down");
289 logger->info(TAG, "OSD module shut down");
297 logger->info(TAG, "Audio module shut down");
305 logger->info(TAG, "Video module shut down");
313 logger->info(TAG, "Timers module shut down");
321 logger->info(TAG, "LED module shut down");
327 logger->info(TAG, "Request stop");
329 Message* m = new Message(); // break master loop
330 m->message = Message::SHUTDOWN;
331 m->p_to = Message::CONTROL;
335 void Control::doWallpaper()
338 Boxx* bbg = new Boxx();
339 bbg->setSize(video->getScreenWidth(), video->getScreenHeight());
341 bbg->fillColour(DrawStyle::WALLPAPER);
343 boxstack->update(bbg);
344 boxstack->remove(bbg);
347 wallpaper = new Boxx();
348 wallpaper->setSize(video->getScreenWidth(), video->getScreenHeight());
349 wallpaper->createBuffer();
350 wallpaper->setBackgroundColour(DrawStyle::WALLPAPER);
352 wallpaper_pict = new WJpegTYPE();
353 wallpaper_pict->setSize(video->getScreenWidth(), video->getScreenHeight());
355 if (video->getFormat() == Video::PAL)
357 logger->debug(TAG, "PAL wallpaper selected");
359 wallpaper_pict->init("/wallpaperPAL.jpg");
361 wallpaper_pict->init("wallpaperPAL.jpg");
366 logger->debug(TAG, "NTSC wallpaper selected");
367 wallpaper_pict->init("/wallpaperNTSC.jpg");
370 if (DrawStyle::WALLPAPER.alpha)
371 wallpaper_pict->setVisible(true);
373 wallpaper_pict->setVisible(false);
375 wallpaper->add(wallpaper_pict);
378 boxstack->add(wallpaper);
379 boxstack->update(wallpaper);
381 OsdVector* osdv = dynamic_cast<OsdVector*>(Osd::getInstance());
382 if (osdv) osdv->updateBackgroundColor(DrawStyle::WALLPAPER);
387 if (!initted) return;
391 Video::getInstance()->signalOn();
392 Led::getInstance()->on();
402 VConnect* vconnect = new VConnect(); // FIXME never deleted?
403 boxstack->add(vconnect);
408 // FIXME Input::NA_SIGNAL is possibly obsolete now
410 std::unique_lock<std::mutex> lockWrapper(messageQueueMutex); // locks. unlocks on out-of-scope
416 messageQueueCond.wait(lockWrapper, [&] { return !irun || !messages.empty(); });
417 logger->debug(TAG, "woke");
421 while(!messages.empty())
423 Message* m = messages.front();
424 messages.pop_front();
426 lockWrapper.unlock();
437 boxstack->removeAllExceptWallpaper();
438 boxstack->remove(wallpaper);
439 delete wallpaper_pict; wallpaper_pict = NULL; wallpaper = NULL;
442 void Control::processMessage(Message* m)
444 // FIXME - a slight modification - how if messagereceivers were to register
445 // themselves as receivers to avoid the calling-a-deleted-object problem
446 // then only deliver/register/unregister would have to be protected
448 logger->debug(TAG, "processing message {}", m->message);
451 if ((m->p_to == Message::CONTROL) || (m->to == this)) // Maybe don't check m->to here? Always use predefined?
455 case Message::SHUTDOWN:
461 case Message::STOP_PLAYBACK:
463 handleCommand(Input::STOP); // an odd way of doing it, but so simple
466 // Also connection_lost comes from player - anywhere else?
470 case Message::VDR_CONNECTED:
472 doJustConnected(static_cast<VConnect*>(m->from)); // FIXME delete from here?
475 case Message::SCREENSHOT:
477 logger->info(TAG, "Screenshot Message arrived");
478 Osd::getInstance()->screenShot("out.jpg");
481 case Message::CONNECTION_LOST:
486 case Message::INPUT_EVENT:
488 logger->info(TAG, "INPUT_EVENT {}", m->parameter);
490 handleCommand(m->parameter);
493 case Message::CHANGE_LANGUAGE:
495 boxstack->removeAllExceptWallpaper();
496 boxstack->update(wallpaper);
498 if (!VDR::getInstance()->isConnected()) { connectionLost(); break; }
499 VWelcome* vw = new VWelcome();
502 boxstack->update(vw);
505 case Message::LAST_VIEW_CLOSE:
507 // Shouldn't be done like this. Some generic message pass back from vinfo perhaps
514 // VWelcome* vw = new VWelcome();
516 // boxstack->add(vw);
517 // boxstack->update(vw);
521 case Message::NEW_PICTURE:
523 //Log::getInstance()->log("Control", Log::DEBUG, "TVMedia NEW_PICTURE");
524 OsdVector* osdv = dynamic_cast<OsdVector*>(Osd::getInstance());
525 if (osdv) osdv->informPicture(m->tag, reinterpret_cast<ImageIndex>(m->data));
528 case Message::NEW_PICTURE_STATIC:
530 //Log::getInstance()->log("Control", Log::DEBUG, "TVMedia NEW_PICTURE %x %x",m->tag,m->parameter);
531 OsdVector* osdv = dynamic_cast<OsdVector*>(Osd::getInstance());
532 if (osdv) osdv->informPicture(static_cast<unsigned long long>(m->tag) << 32LL, reinterpret_cast<ImageIndex>(m->data));
541 Instead of sending through the boxstack, implement a more generic MessageReceiver interface
542 and have potential receivers register with something
543 When a message needs to be delivered, check if the receiver is still registered, if so, deliver the message
544 This could all be done using the existing big control mutex to keep it simple
547 logger->debug(TAG, "Sending message to boxstack");
548 boxstack->processMessage(m);
552 void Control::handleCommand(int button)
554 if (isStandby && (button != Input::POWER)
555 && (button != Input::POWERON)
556 && (button != Input::POWEROFF)) return;
558 if (!connLost && boxstack->handleCommand(button)) return; // don't send to boxstack if connLost
560 // command was not handled
564 case Input::VOLUMEUP:
565 case Input::VOLUMEDOWN:
567 if (inputMan->handlesVolume()) // CEC volume handler?
569 if (button == Input::VOLUMEDOWN)
570 inputMan->volumeDown();
572 inputMan->volumeUp();
576 VVolume* v = new VVolume();
578 v->handleCommand(button); // this will draw+show
584 if (inputMan->handlesVolume())
586 inputMan->volumeMute();
590 VMute* v = new VMute();
607 case Input::POWEROFF:
615 if (!connLost) return; // if connLost, handle Input::OK
621 logger->debug(TAG, "Handling sleeptimer go");
632 Message* m = new Message(); // break into master mutex
633 m->message = Message::SCREENSHOT;
640 void Control::doStandby()
653 void Control::doPowerOn()
657 Video::getInstance()->signalOn();
658 Led::getInstance()->on();
659 InputMan::getInstance()->changePowerState(true);
662 VConnect* vconnect = new VConnect();
663 boxstack->add(vconnect);
668 void Control::doPowerOff()
672 VDR::getInstance()->shutdownVDR();
673 boxstack->removeAllExceptWallpaper();
674 Video::getInstance()->signalOff();
675 boxstack->update(wallpaper);
677 VDR::getInstance()->configSave("General", "Last Power State", "Off");
678 logger->unsetExternLogger();
679 VDR::getInstance()->disconnect();
680 Led::getInstance()->off();
681 InputMan::getInstance()->changePowerState(false);
683 sleepTimer->shutdown();
687 void Control::doFromTheTop(bool which)
689 if (isStandby) return;
694 logger->info(TAG, "Connection lost dialog already present");
698 logger->info(TAG, "Doing connection lost dialog");
699 connLost = new VInfo();
700 connLost->setSize(360, 200);
701 connLost->createBuffer();
702 if (Video::getInstance()->getFormat() == Video::PAL)
703 connLost->setPosition(190, 170);
705 connLost->setPosition(180, 120);
706 connLost->setOneLiner(tr("Connection lost"));
707 connLost->setDropThrough();
708 connLost->setBorderOn(1);
709 connLost->setTitleBarColour(DrawStyle::DANGER);
710 connLost->okButton();
712 boxstack->add(connLost);
713 boxstack->update(connLost);
715 clearMQInputEvents();
719 logger->unsetExternLogger();
720 VDR::getInstance()->disconnect();
721 boxstack->removeAllExceptWallpaper();
722 boxstack->update(wallpaper);
727 // at this point, everything should be reset to first-go
729 VConnect* vconnect = new VConnect(); // deleted eventually in boxstack
730 boxstack->add(vconnect);
735 void Control::clearMQInputEvents()
737 std::lock_guard<std::mutex> lg(messageQueueMutex); // Get the lock
739 MQueueI i = messages.begin();
740 while(i != messages.end())
743 if (m->message == Message::INPUT_EVENT)
746 i = messages.erase(i);
755 void Control::doReboot()
758 logger->unsetExternLogger();
759 VDR::getInstance()->disconnect();
761 logger->info(TAG, "Reboot");
763 #ifndef VOMP_HAS_EXIT
764 // some plattforms, want a proper deinitialisation of their hardware before reboot
765 Osd::getInstance()->shutdown();
766 Audio::getInstance()->shutdown();
767 Video::getInstance()->shutdown();
768 InputMan::getInstance()->shutdown();
770 reboot(LINUX_REBOOT_CMD_RESTART);
771 // if reboot is not allowed -> stop
783 #endif //Would we support this on windows?
786 void Control::connectionLost()
788 logger->unsetExternLogger();
789 Message* m = new Message(); // break into master mutex
790 m->message = Message::CONNECTION_LOST;
791 m->p_to = Message::CONTROL;
795 void Control::buildCrashedBox()
797 VInfo* crash = new VInfo();
798 crash->setSize(360, 250);
799 crash->createBuffer();
800 if (Video::getInstance()->getFormat() == Video::PAL)
801 crash->setPosition(190, 146);
803 crash->setPosition(180, 96);
804 crash->setMainText("Oops, vomp crashed.. :(\nPlease report this crash to the author, with as much detail as possible about what you were doing at the time that might have caused the crash.");
805 crash->setBorderOn(1);
806 crash->setTitleBarColour(DrawStyle::DANGER);
808 crash->setExitable();
810 boxstack->add(crash);
811 boxstack->update(crash);
814 int Control::getLangPref(bool subtitle, const char* langcode)
816 std::vector<struct ASLPref>::iterator itty=langcodes.begin();
817 char templangcode[4];
818 templangcode[0] = langcode[0];
819 templangcode[1] = langcode[1];
820 templangcode[2] = langcode[2];
821 templangcode[3] = '\0';
823 while (itty != langcodes.end())
825 size_t pos = (*itty).langcode.find(templangcode);
826 if (pos != std::string::npos)
828 //vector<struct ASLPref>::iterator itty2=langcodes.begin();
829 for (unsigned int i = 0; i < langcodes.size(); i++)
833 pref = langcodes[i].subtitlepref;
835 pref = langcodes[i].audiopref;
840 if (langcodes[i].subtitlepref==langpos) return i;
844 if (langcodes[i].audiopref==langpos) return i;
852 return langcodes.size(); //neutral
855 void Control::doJustConnected(VConnect* vconnect)
858 if (!VDR::getInstance()->isConnected()) { connectionLost(); return; }
859 logger->info(TAG, "Entering doJustConnected");
861 boxstack->remove(vconnect);
863 VInfo* vi = new VInfo();
864 vi->setSize(400, 200);
866 if (video->getFormat() == Video::PAL)
867 vi->setPosition(170, 200);
869 vi->setPosition(160, 150);
870 vi->setOneLiner(tr("Connected, loading config"));
873 boxstack->update(vi);
875 // FIXME make config system
879 // See if we're supposed to do network logging
880 config = vdr->configLoad("Advanced", "Network logging");
881 if (config && !STRCASECMP(config, "On"))
883 logger->info(TAG, "Turning on network logging");
884 logger->setExternLogger(vdr);
888 logger->unsetExternLogger();
889 logger->info(TAG, "Turned off network logging");
891 if (config) delete[] config;
893 config = vdr->configLoad("Advanced", "Skin Name");
896 const char **skinnames=SkinFactory::getSkinNames();
897 for (int i=0;i<SkinFactory::getNumberofSkins();i++)
899 if (!STRCASECMP(config, skinnames[i]))
901 SkinFactory::InitSkin(i);
907 if (wallpaper && wallpaper_pict)
909 if (DrawStyle::WALLPAPER.alpha)
910 wallpaper_pict->setVisible(true);
912 wallpaper_pict->setVisible(false);
915 boxstack->update(wallpaper);
920 SkinFactory::InitSkin(0);
923 // See if config says to override video format (PAL/NTSC)
924 config = vdr->configLoad("General", "Override Video Format");
927 logger->debug(TAG, "Override Video Format is present");
929 if ( (!strcmp(config, "PAL") && (video->getFormat() != Video::PAL))
930 || (!strcmp(config, "NTSC") && (video->getFormat() != Video::NTSC))
931 || (!strcmp(config, "PAL_M") && (video->getFormat() != Video::PAL_M))
932 || (!strcmp(config, "NTSC_J") && (video->getFormat() != Video::NTSC_J))
935 // Oh sheesh, need to switch format. Bye bye TV...
937 // Take everything down
938 boxstack->removeAllExceptWallpaper();
939 boxstack->remove(wallpaper);
940 delete wallpaper_pict; wallpaper_pict = NULL; wallpaper = NULL;
947 inputMan->shutdown(); // need on raspberry shut not do any harm, hopefully
948 inputMan->init(); // FIXME this breaks badly now
950 // Get video and osd back up with the new mode
951 if (!strcmp(config, "PAL"))
953 logger->debug(TAG, "Switching to PAL");
954 video->init(Video::PAL);
956 else if (!strcmp(config, "NTSC"))
958 logger->debug(TAG, "Switching to NTSC");
959 video->init(Video::NTSC);
960 } else if (!strcmp(config, "PAL_M"))
962 logger->debug(TAG, "Switching to PAL_M");
963 video->init(Video::PAL_M);
964 } else if (!strcmp(config, "NTSC_J"))
966 logger->debug(TAG, "Switching to NTSC_J");
967 video->init(Video::NTSC_J);
972 //we do not init twice
976 // Put the wallpaper back
981 vi->setSize(400, 200);
983 if (video->getFormat() == Video::PAL)
984 vi->setPosition(170, 200);
986 vi->setPosition(160, 150);
988 vi->setOneLiner(tr("Connected, loading config"));
991 boxstack->update(vi);
995 logger->debug(TAG, "Already in requested mode, or request was not 'PAL' or 'NTSC'");
1000 logger->debug(TAG, "Phew, no dangerous on-the-fly mode switching to do!");
1003 // Power off if first boot and config says so
1008 logger->debug(TAG, "Load power after boot");
1010 config = vdr->configLoad("General", "Power After Boot");
1014 if (!STRCASECMP(config, "On"))
1016 logger->info(TAG, "Config says Power After Boot = On");
1018 else if (!STRCASECMP(config, "Off"))
1020 logger->info(TAG, "Config says Power After Boot = Off");
1023 return; // quit here
1025 else if (!STRCASECMP(config, "Last state"))
1027 char* lastPowerState = vdr->configLoad("General", "Last Power State");
1030 if (!STRCASECMP(lastPowerState, "On"))
1032 logger->info(TAG, "Config says Last Power State = On");
1034 else if (!STRCASECMP(lastPowerState, "Off"))
1036 logger->info(TAG, "Config says Last Power State = Off");
1039 return; // quit here
1043 logger->info(TAG, "Config General/Last Power State not understood");
1048 logger->info(TAG, "Config General/Last Power State not found");
1053 logger->info(TAG, "Config/Power After Boot not understood");
1059 logger->info(TAG, "Config General/Power After Boot not found");
1064 // Go S-Video if config says so
1066 config = vdr->configLoad("TV", "Connection");
1070 if (!STRCASECMP(config, "S-Video"))
1072 logger->info(TAG, "Switching to S-Video as Connection={}", config);
1073 video->setConnection(Video::SVIDEO);
1074 } else if (!STRCASECMP(config, "HDMI"))
1076 logger->info(TAG, "Switching to HDMI as Connection={}", config);
1077 video->setConnection(Video::HDMI);
1078 } else if (!STRCASECMP(config, "HDMI3D"))
1080 logger->info(TAG, "Switching to HDMI3D as Connection={}", config);
1081 video->setConnection(Video::HDMI3D);
1085 logger->info(TAG, "Switching to RGB/Composite as Connection={}", config);
1086 video->setConnection(Video::COMPOSITERGB);
1092 logger->info(TAG, "Config TV/S-Video not found");
1095 // Set to shutdown VDR if config says
1097 config = vdr->configLoad("General", "VDR shutdown");
1100 if (!STRCASECMP(config, "On"))
1102 logger->info(TAG, "Shutdown VDR when shutting down vomp");
1103 vdr->setVDRShutdown(true);
1105 else if (!STRCASECMP(config, "Off"))
1107 logger->info(TAG, "Shutdown only vomp");
1108 vdr->setVDRShutdown(false);
1113 logger->info(TAG, "Default shutdown only vomp");
1114 vdr->setVDRShutdown(false); // Default
1117 // Get TV aspect ratio
1119 config = vdr->configLoad("TV", "Aspect");
1122 if (!STRCASECMP(config, "16:9"))
1124 logger->info(TAG, "/// Switching to TV aspect 16:9");
1125 video->setTVsize(Video::ASPECT16X9);
1129 logger->info(TAG, "/// Switching to TV aspect 4:3");
1130 video->setTVsize(Video::ASPECT4X3);
1136 logger->info(TAG, "Config TV/Aspect type not found, going 4:3");
1137 video->setTVsize(Video::ASPECT4X3);
1140 config = vdr->configLoad("TV", "Widemode");
1143 if (!STRCASECMP(config, "Letterbox"))
1145 logger->info(TAG, "Setting letterbox mode");
1146 video->setMode(Video::LETTERBOX);
1150 logger->info(TAG, "Setting chop-sides mode");
1151 video->setMode(Video::NORMAL);
1158 logger->info(TAG, "Config TV/Widemode not found, Setting letterbox mode");
1159 video->setMode(Video::LETTERBOX);
1161 logger->info(TAG, "Config TV/Widemode not found, Setting chop-sides mode");
1162 video->setMode(Video::NORMAL);
1166 config = vdr->configLoad("Advanced", "TCP receive window");
1169 size_t newTCPsize = atoi(config);
1172 logger->info(TAG, "Setting TCP window size %i", newTCPsize);
1173 vdr->setReceiveWindow(newTCPsize);
1177 logger->info(TAG, "TCP window size not found, setting 2048");
1178 if (DEFAULT_TCP_WINDOWSIZE) vdr->setReceiveWindow(2048); // Default
1181 config = vdr->configLoad("Advanced", "Font Name");
1184 Osd::getInstance()->setFont(config);
1185 logger->info(TAG, "Setting Font to %s", config);
1191 // Set recording list type
1193 #ifdef ADVANCED_MENUES
1194 config = vdr->configLoad("Advanced", "Menu type");
1198 if (!STRCASECMP(config, "Advanced"))
1200 logger->info(TAG, "Switching to Advanced menu");
1205 logger->info(TAG, "Switching to Classic menu");
1212 logger->info(TAG, "Config General/menu type not found");
1217 config = vdr->configLoad("Advanced", "Disable WOL");
1220 if (!STRCASECMP(config, "Yes"))
1222 logger->info(TAG, "Config says disable WOL");
1223 Wol::getInstance()->setEnabled(false);
1227 logger->info(TAG, "Config says enable WOL");
1228 Wol::getInstance()->setEnabled(true);
1235 logger->info(TAG, "By default, enable WOL");
1236 Wol::getInstance()->setEnabled(true);
1238 /* device dependend config */
1239 audio->loadOptionsFromServer(vdr);
1240 video->loadOptionsFromServer(vdr);
1241 inputMan->loadOptionsFromServer(vdr);
1243 video->executePendingModeChanges();
1246 // Save power state = on
1248 vdr->configSave("General", "Last Power State", "On");
1250 // Make sure connection didn't die
1251 if (!vdr->isConnected())
1253 Control::getInstance()->connectionLost();
1257 boxstack->remove(vi);
1259 VWelcome* vw = new VWelcome();
1262 boxstack->update(vw);
1264 // Enter pre-keys here
1265 // handleCommand(Input::OK);
1266 // handleCommand(Input::THREE);
1267 // handleCommand(Input::SIX);
1268 // handleCommand(Input::UP);
1269 // handleCommand(Input::OK);
1270 // handleCommand(Input::OK);
1271 // handleCommand(Input::PLAY);
1272 // handleCommand(Input::DOWN);
1273 // handleCommand(Input::DOWN);
1274 // handleCommand(Input::DOWN);
1275 // handleCommand(Input::RIGHT);
1276 // handleCommand(Input::RED);