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(); // Deleted when VConnect messages Control, and is boxstack->remove()'d
403 boxstack->add(vconnect);
407 std::unique_lock<std::mutex> lockWrapper(messageQueueMutex); // locks. unlocks on out-of-scope
413 messageQueueCond.wait(lockWrapper, [&] { return !irun || !messages.empty(); });
414 logger->debug(TAG, "woke");
418 while(!messages.empty())
420 Message* m = messages.front();
421 messages.pop_front();
423 lockWrapper.unlock();
434 boxstack->removeAllExceptWallpaper();
435 boxstack->remove(wallpaper);
436 delete wallpaper_pict; wallpaper_pict = NULL; wallpaper = NULL;
439 void Control::processMessage(Message* m)
441 // FIXME - a slight modification - how if messagereceivers were to register
442 // themselves as receivers to avoid the calling-a-deleted-object problem
443 // then only deliver/register/unregister would have to be protected
445 logger->debug(TAG, "processing message {}", m->message);
448 if ((m->p_to == Message::CONTROL) || (m->to == this)) // Maybe don't check m->to here? Always use predefined?
452 case Message::SHUTDOWN:
458 case Message::STOP_PLAYBACK:
460 handleCommand(Input::STOP); // an odd way of doing it, but so simple
463 // Also connection_lost comes from player - anywhere else?
467 case Message::VDR_CONNECTED:
469 doJustConnected(static_cast<VConnect*>(m->from)); // FIXME delete from here?
472 case Message::SCREENSHOT:
474 logger->info(TAG, "Screenshot Message arrived");
475 Osd::getInstance()->screenShot("out.jpg");
478 case Message::CONNECTION_LOST:
483 case Message::INPUT_EVENT:
485 logger->info(TAG, "INPUT_EVENT {}", m->parameter);
487 handleCommand(m->parameter);
490 case Message::CHANGE_LANGUAGE:
492 boxstack->removeAllExceptWallpaper();
493 boxstack->update(wallpaper);
495 if (!VDR::getInstance()->isConnected()) { connectionLost(); break; }
496 VWelcome* vw = new VWelcome();
499 boxstack->update(vw);
502 case Message::LAST_VIEW_CLOSE:
504 // Shouldn't be done like this. Some generic message pass back from vinfo perhaps
511 // VWelcome* vw = new VWelcome();
513 // boxstack->add(vw);
514 // boxstack->update(vw);
518 case Message::NEW_PICTURE:
520 //Log::getInstance()->log("Control", Log::DEBUG, "TVMedia NEW_PICTURE");
521 OsdVector* osdv = dynamic_cast<OsdVector*>(Osd::getInstance());
522 if (osdv) osdv->informPicture(m->tag, reinterpret_cast<ImageIndex>(m->data));
525 case Message::NEW_PICTURE_STATIC:
527 //Log::getInstance()->log("Control", Log::DEBUG, "TVMedia NEW_PICTURE %x %x",m->tag,m->parameter);
528 OsdVector* osdv = dynamic_cast<OsdVector*>(Osd::getInstance());
529 if (osdv) osdv->informPicture(static_cast<unsigned long long>(m->tag) << 32LL, reinterpret_cast<ImageIndex>(m->data));
538 Instead of sending through the boxstack, implement a more generic MessageReceiver interface
539 and have potential receivers register with something
540 When a message needs to be delivered, check if the receiver is still registered, if so, deliver the message
541 This could all be done using the existing big control mutex to keep it simple
544 logger->debug(TAG, "Sending message to boxstack");
545 boxstack->processMessage(m);
549 void Control::handleCommand(int button)
551 if (isStandby && (button != Input::POWER)
552 && (button != Input::POWERON)
553 && (button != Input::POWEROFF)) return;
555 if (!connLost && boxstack->handleCommand(button)) return; // don't send to boxstack if connLost
557 // command was not handled
561 case Input::VOLUMEUP:
562 case Input::VOLUMEDOWN:
564 if (inputMan->handlesVolume()) // CEC volume handler?
566 if (button == Input::VOLUMEDOWN)
567 inputMan->volumeDown();
569 inputMan->volumeUp();
573 VVolume* v = new VVolume();
575 v->handleCommand(button); // this will draw+show
581 if (inputMan->handlesVolume())
583 inputMan->volumeMute();
587 VMute* v = new VMute();
604 case Input::POWEROFF:
612 if (!connLost) return; // if connLost, handle Input::OK
618 logger->debug(TAG, "Handling sleeptimer go");
629 Message* m = new Message(); // break into master mutex
630 m->message = Message::SCREENSHOT;
637 void Control::doStandby()
650 void Control::doPowerOn()
654 Video::getInstance()->signalOn();
655 Led::getInstance()->on();
656 InputMan::getInstance()->changePowerState(true);
659 VConnect* vconnect = new VConnect();
660 boxstack->add(vconnect);
665 void Control::doPowerOff()
669 VDR::getInstance()->shutdownVDR();
670 boxstack->removeAllExceptWallpaper();
671 Video::getInstance()->signalOff();
672 boxstack->update(wallpaper);
674 VDR::getInstance()->configSave("General", "Last Power State", "Off");
675 logger->unsetExternLogger();
676 VDR::getInstance()->disconnect();
677 Led::getInstance()->off();
678 InputMan::getInstance()->changePowerState(false);
680 sleepTimer->shutdown();
684 void Control::doFromTheTop(bool which)
686 if (isStandby) return;
691 logger->info(TAG, "Connection lost dialog already present");
695 logger->info(TAG, "Doing connection lost dialog");
696 connLost = new VInfo();
697 connLost->setSize(360, 200);
698 connLost->createBuffer();
699 if (Video::getInstance()->getFormat() == Video::PAL)
700 connLost->setPosition(190, 170);
702 connLost->setPosition(180, 120);
703 connLost->setOneLiner(tr("Connection lost"));
704 connLost->setDropThrough();
705 connLost->setBorderOn(1);
706 connLost->setTitleBarColour(DrawStyle::DANGER);
707 connLost->okButton();
709 boxstack->add(connLost);
710 boxstack->update(connLost);
712 clearMQInputEvents();
716 logger->unsetExternLogger();
717 VDR::getInstance()->disconnect();
718 boxstack->removeAllExceptWallpaper();
719 boxstack->update(wallpaper);
724 // at this point, everything should be reset to first-go
726 VConnect* vconnect = new VConnect(); // deleted eventually in boxstack
727 boxstack->add(vconnect);
732 void Control::clearMQInputEvents()
734 std::lock_guard<std::mutex> lg(messageQueueMutex); // Get the lock
736 MQueueI i = messages.begin();
737 while(i != messages.end())
740 if (m->message == Message::INPUT_EVENT)
743 i = messages.erase(i);
752 void Control::doReboot()
755 logger->unsetExternLogger();
756 VDR::getInstance()->disconnect();
758 logger->info(TAG, "Reboot");
760 #ifndef VOMP_HAS_EXIT
761 // some plattforms, want a proper deinitialisation of their hardware before reboot
762 Osd::getInstance()->shutdown();
763 Audio::getInstance()->shutdown();
764 Video::getInstance()->shutdown();
765 InputMan::getInstance()->shutdown();
767 reboot(LINUX_REBOOT_CMD_RESTART);
768 // if reboot is not allowed -> stop
780 #endif //Would we support this on windows?
783 void Control::connectionLost()
785 logger->unsetExternLogger();
786 Message* m = new Message(); // break into master mutex
787 m->message = Message::CONNECTION_LOST;
788 m->p_to = Message::CONTROL;
792 void Control::buildCrashedBox()
794 VInfo* crash = new VInfo();
795 crash->setSize(360, 250);
796 crash->createBuffer();
797 if (Video::getInstance()->getFormat() == Video::PAL)
798 crash->setPosition(190, 146);
800 crash->setPosition(180, 96);
801 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.");
802 crash->setBorderOn(1);
803 crash->setTitleBarColour(DrawStyle::DANGER);
805 crash->setExitable();
807 boxstack->add(crash);
808 boxstack->update(crash);
811 int Control::getLangPref(bool subtitle, const char* langcode)
813 std::vector<struct ASLPref>::iterator itty=langcodes.begin();
814 char templangcode[4];
815 templangcode[0] = langcode[0];
816 templangcode[1] = langcode[1];
817 templangcode[2] = langcode[2];
818 templangcode[3] = '\0';
820 while (itty != langcodes.end())
822 size_t pos = (*itty).langcode.find(templangcode);
823 if (pos != std::string::npos)
825 //vector<struct ASLPref>::iterator itty2=langcodes.begin();
826 for (unsigned int i = 0; i < langcodes.size(); i++)
830 pref = langcodes[i].subtitlepref;
832 pref = langcodes[i].audiopref;
837 if (langcodes[i].subtitlepref==langpos) return i;
841 if (langcodes[i].audiopref==langpos) return i;
849 return langcodes.size(); //neutral
852 void Control::doJustConnected(VConnect* vconnect)
855 if (!VDR::getInstance()->isConnected()) { connectionLost(); return; }
856 logger->info(TAG, "Entering doJustConnected");
858 boxstack->remove(vconnect);
860 VInfo* vi = new VInfo();
861 vi->setSize(400, 200);
863 if (video->getFormat() == Video::PAL)
864 vi->setPosition(170, 200);
866 vi->setPosition(160, 150);
867 vi->setOneLiner(tr("Connected, loading config"));
870 boxstack->update(vi);
872 // FIXME make config system
876 // See if we're supposed to do network logging
877 config = vdr->configLoad("Advanced", "Network logging");
878 if (config && !STRCASECMP(config, "On"))
880 logger->info(TAG, "Turning on network logging");
881 logger->setExternLogger(vdr);
885 logger->unsetExternLogger();
886 logger->info(TAG, "Turned off network logging");
888 if (config) delete[] config;
890 config = vdr->configLoad("Advanced", "Skin Name");
893 const char **skinnames=SkinFactory::getSkinNames();
894 for (int i=0;i<SkinFactory::getNumberofSkins();i++)
896 if (!STRCASECMP(config, skinnames[i]))
898 SkinFactory::InitSkin(i);
904 if (wallpaper && wallpaper_pict)
906 if (DrawStyle::WALLPAPER.alpha)
907 wallpaper_pict->setVisible(true);
909 wallpaper_pict->setVisible(false);
912 boxstack->update(wallpaper);
917 SkinFactory::InitSkin(0);
920 // See if config says to override video format (PAL/NTSC)
921 config = vdr->configLoad("General", "Override Video Format");
924 logger->debug(TAG, "Override Video Format is present");
926 if ( (!strcmp(config, "PAL") && (video->getFormat() != Video::PAL))
927 || (!strcmp(config, "NTSC") && (video->getFormat() != Video::NTSC))
928 || (!strcmp(config, "PAL_M") && (video->getFormat() != Video::PAL_M))
929 || (!strcmp(config, "NTSC_J") && (video->getFormat() != Video::NTSC_J))
932 // Oh sheesh, need to switch format. Bye bye TV...
934 // Take everything down
935 boxstack->removeAllExceptWallpaper();
936 boxstack->remove(wallpaper);
937 delete wallpaper_pict; wallpaper_pict = NULL; wallpaper = NULL;
944 inputMan->shutdown(); // need on raspberry shut not do any harm, hopefully
945 inputMan->init(); // FIXME this breaks badly now
947 // Get video and osd back up with the new mode
948 if (!strcmp(config, "PAL"))
950 logger->debug(TAG, "Switching to PAL");
951 video->init(Video::PAL);
953 else if (!strcmp(config, "NTSC"))
955 logger->debug(TAG, "Switching to NTSC");
956 video->init(Video::NTSC);
957 } else if (!strcmp(config, "PAL_M"))
959 logger->debug(TAG, "Switching to PAL_M");
960 video->init(Video::PAL_M);
961 } else if (!strcmp(config, "NTSC_J"))
963 logger->debug(TAG, "Switching to NTSC_J");
964 video->init(Video::NTSC_J);
969 //we do not init twice
973 // Put the wallpaper back
978 vi->setSize(400, 200);
980 if (video->getFormat() == Video::PAL)
981 vi->setPosition(170, 200);
983 vi->setPosition(160, 150);
985 vi->setOneLiner(tr("Connected, loading config"));
988 boxstack->update(vi);
992 logger->debug(TAG, "Already in requested mode, or request was not 'PAL' or 'NTSC'");
997 logger->debug(TAG, "Phew, no dangerous on-the-fly mode switching to do!");
1000 // Power off if first boot and config says so
1005 logger->debug(TAG, "Load power after boot");
1007 config = vdr->configLoad("General", "Power After Boot");
1011 if (!STRCASECMP(config, "On"))
1013 logger->info(TAG, "Config says Power After Boot = On");
1015 else if (!STRCASECMP(config, "Off"))
1017 logger->info(TAG, "Config says Power After Boot = Off");
1020 return; // quit here
1022 else if (!STRCASECMP(config, "Last state"))
1024 char* lastPowerState = vdr->configLoad("General", "Last Power State");
1027 if (!STRCASECMP(lastPowerState, "On"))
1029 logger->info(TAG, "Config says Last Power State = On");
1031 else if (!STRCASECMP(lastPowerState, "Off"))
1033 logger->info(TAG, "Config says Last Power State = Off");
1036 return; // quit here
1040 logger->info(TAG, "Config General/Last Power State not understood");
1045 logger->info(TAG, "Config General/Last Power State not found");
1050 logger->info(TAG, "Config/Power After Boot not understood");
1056 logger->info(TAG, "Config General/Power After Boot not found");
1061 // Go S-Video if config says so
1063 config = vdr->configLoad("TV", "Connection");
1067 if (!STRCASECMP(config, "S-Video"))
1069 logger->info(TAG, "Switching to S-Video as Connection={}", config);
1070 video->setConnection(Video::SVIDEO);
1071 } else if (!STRCASECMP(config, "HDMI"))
1073 logger->info(TAG, "Switching to HDMI as Connection={}", config);
1074 video->setConnection(Video::HDMI);
1075 } else if (!STRCASECMP(config, "HDMI3D"))
1077 logger->info(TAG, "Switching to HDMI3D as Connection={}", config);
1078 video->setConnection(Video::HDMI3D);
1082 logger->info(TAG, "Switching to RGB/Composite as Connection={}", config);
1083 video->setConnection(Video::COMPOSITERGB);
1089 logger->info(TAG, "Config TV/S-Video not found");
1092 // Set to shutdown VDR if config says
1094 config = vdr->configLoad("General", "VDR shutdown");
1097 if (!STRCASECMP(config, "On"))
1099 logger->info(TAG, "Shutdown VDR when shutting down vomp");
1100 vdr->setVDRShutdown(true);
1102 else if (!STRCASECMP(config, "Off"))
1104 logger->info(TAG, "Shutdown only vomp");
1105 vdr->setVDRShutdown(false);
1110 logger->info(TAG, "Default shutdown only vomp");
1111 vdr->setVDRShutdown(false); // Default
1114 // Get TV aspect ratio
1116 config = vdr->configLoad("TV", "Aspect");
1119 if (!STRCASECMP(config, "16:9"))
1121 logger->info(TAG, "/// Switching to TV aspect 16:9");
1122 video->setTVsize(Video::ASPECT16X9);
1126 logger->info(TAG, "/// Switching to TV aspect 4:3");
1127 video->setTVsize(Video::ASPECT4X3);
1133 logger->info(TAG, "Config TV/Aspect type not found, going 4:3");
1134 video->setTVsize(Video::ASPECT4X3);
1137 config = vdr->configLoad("TV", "Widemode");
1140 if (!STRCASECMP(config, "Letterbox"))
1142 logger->info(TAG, "Setting letterbox mode");
1143 video->setMode(Video::LETTERBOX);
1147 logger->info(TAG, "Setting chop-sides mode");
1148 video->setMode(Video::NORMAL);
1155 logger->info(TAG, "Config TV/Widemode not found, Setting letterbox mode");
1156 video->setMode(Video::LETTERBOX);
1158 logger->info(TAG, "Config TV/Widemode not found, Setting chop-sides mode");
1159 video->setMode(Video::NORMAL);
1163 config = vdr->configLoad("Advanced", "TCP receive window");
1166 size_t newTCPsize = atoi(config);
1169 logger->info(TAG, "Setting TCP window size %i", newTCPsize);
1170 vdr->setReceiveWindow(newTCPsize);
1174 logger->info(TAG, "TCP window size not found, setting 2048");
1175 if (DEFAULT_TCP_WINDOWSIZE) vdr->setReceiveWindow(2048); // Default
1178 config = vdr->configLoad("Advanced", "Font Name");
1181 Osd::getInstance()->setFont(config);
1182 logger->info(TAG, "Setting Font to %s", config);
1188 // Set recording list type
1190 #ifdef ADVANCED_MENUES
1191 config = vdr->configLoad("Advanced", "Menu type");
1195 if (!STRCASECMP(config, "Advanced"))
1197 logger->info(TAG, "Switching to Advanced menu");
1202 logger->info(TAG, "Switching to Classic menu");
1209 logger->info(TAG, "Config General/menu type not found");
1214 config = vdr->configLoad("Advanced", "Disable WOL");
1217 if (!STRCASECMP(config, "Yes"))
1219 logger->info(TAG, "Config says disable WOL");
1220 Wol::getInstance()->setEnabled(false);
1224 logger->info(TAG, "Config says enable WOL");
1225 Wol::getInstance()->setEnabled(true);
1232 logger->info(TAG, "By default, enable WOL");
1233 Wol::getInstance()->setEnabled(true);
1235 /* device dependend config */
1236 audio->loadOptionsFromServer(vdr);
1237 video->loadOptionsFromServer(vdr);
1238 inputMan->loadOptionsFromServer(vdr);
1240 video->executePendingModeChanges();
1243 // Save power state = on
1245 vdr->configSave("General", "Last Power State", "On");
1247 // Make sure connection didn't die
1248 if (!vdr->isConnected())
1250 Control::getInstance()->connectionLost();
1254 boxstack->remove(vi);
1256 VWelcome* vw = new VWelcome();
1259 boxstack->update(vw);
1261 // Enter pre-keys here
1262 // handleCommand(Input::OK);
1263 // handleCommand(Input::THREE);
1264 // handleCommand(Input::SIX);
1265 // handleCommand(Input::UP);
1266 // handleCommand(Input::OK);
1267 // handleCommand(Input::OK);
1268 // handleCommand(Input::PLAY);
1269 // handleCommand(Input::DOWN);
1270 // handleCommand(Input::DOWN);
1271 // handleCommand(Input::DOWN);
1272 // handleCommand(Input::RIGHT);
1273 // handleCommand(Input::RED);