+static const char * const display_filename_default_ =
+#ifdef HAVE_LIBPNG
+ "dcpu16-display.png"
+#else /* HAVE_LIBPNG */
+ "dcpu16-display.pnm"
+#endif /* HAVE_LIBPNG */
+;
+COMMAND_IMPL(display) {
+ struct dcpu16_hw *hw;
+ const char *renderer = arg_vector[1];
+ const char *renderer_arg = NULL;
+ void *renderer_data;
+
+ if (arg_count == 3)
+ renderer_arg = arg_vector[2];
+
+ hw = dcpu16_hw_new(vm, &dcpu16_hw_module_lem1802, NULL);
+ if (hw == NULL) {
+ fprintf(stderr, "failed to initialize new display\n");
+ return 0;
+ }
+
+ /* handle per-renderer setup of data.. */
+ /* FIXME: these are awkward */
+ if (strcmp(renderer, "pnm") == 0) {
+ renderer_data = (void *)(renderer_arg ? renderer_arg : display_filename_default_);
+ }
+
+#ifdef HAVE_LIBPNG
+ if (strcmp(renderer, "png") == 0) {
+ renderer_data = (void *)(renderer_arg ? renderer_arg : display_filename_default_);
+ }
+#endif /* HAVE_LIBPNG */
+
+#ifdef HAVE_LIBVNCSERVER
+ if (strcmp(renderer, "vnc") == 0) {
+ int argc = 1;
+ char *argv[] = { "vm-dcpu16", NULL };
+ struct rfb_instance_ *s;
+
+ s = rfbScreen_next_available_(NEXT_DISPLAY, &rfbScreens_, argc, argv);
+ if (s == NULL) {
+ fprintf(stderr, "failed to initialize vnc\n");
+ dcpu16_hw_del(&hw);
+ return 0;
+ }
+
+ if (dcpu16_hw_ctl(hw, "associate_rfbScreen", s->screen, NULL)) {
+ fprintf(stderr, "failed to configure display/vnc");
+ dcpu16_hw_del(&hw);
+ return 0;
+ }
+ s->attached_display = hw;
+ rfbScreen_start(s->screen);
+ renderer_data = s->screen;
+
+ DEBUG_PRINTF("attached display to rfb (frameBuffer:%p)\n", s->screen->frameBuffer);
+ }
+#endif /* HAVE_LIBVNCSERVER */
+
+ dcpu16_hw_ctl(hw, "renderer", (char *)renderer, NULL);
+ dcpu16_hw_ctl(hw, "renderer_data", renderer_data, NULL);
+
+ if (dcpu16_hw_attach(vm, hw)) {
+ fprintf(stderr, "failed to attach new display\n");
+ dcpu16_hw_del(&hw);
+ return 0;
+ }
+
+ return 0;
+}
+COMMAND_HELP(display) {
+ struct renderer_ {
+ char *name;
+ char *args;
+ } renderer;
+ void *iter;
+
+ fprintf(f, "\tdisplay renderer [renderer data]\n");
+ if (summary) return;
+
+ fprintf(f, "Attaches new display unit, using 'renderer' as back-end output.\n"
+ );
+
+ fprintf(f, "Supported renderers:\n");
+
+ iter = NULL;
+ do {
+ if (dcpu16_hw_module_lem1802.ctl(NULL, "renderers_iter", &iter, &renderer)) {
+ fprintf(stderr, "error fetching next renderer\n");
+ break;
+ }
+ if (iter == NULL || renderer.name == NULL)
+ break;
+
+ fprintf(f, "\t%s %s\n", renderer.name, renderer.args);
+ } while (iter);
+}
+
+COMMAND_IMPL(keyboard) {
+ struct dcpu16_hw *hw;
+
+ (void)arg_count, (void)arg_vector;
+
+ hw = dcpu16_hw_new(vm, &dcpu16_hw_module_keyboard, NULL);
+ if (hw == NULL) {
+ fprintf(stderr, "failed to initialize new keyboard\n");
+ return 0;
+ }
+
+#ifdef HAVE_LIBVNCSERVER
+ struct rfb_instance_ *s;
+ int argc = 1;
+ char *argv[] = { "vm-dcpu16", NULL };
+
+ s = rfbScreen_next_available_(NEXT_KEYBOARD, &rfbScreens_, argc, argv);
+ if (s == NULL) {
+ fprintf(stderr, "failed to initialize vnc\n");
+ dcpu16_hw_del(&hw);
+ return 0;
+ }
+ if (dcpu16_hw_ctl(hw, "associate_rfbScreen", s->screen, NULL)) {
+ fprintf(stderr, "failed to configure keyboard/vnc\n");
+ dcpu16_hw_del(&hw);
+ return 0;
+ }
+ s->attached_keyboard = hw;
+
+ if (dcpu16_hw_attach(vm, hw)) {
+ fprintf(stderr, "failed to attach new keyboard\n");
+ dcpu16_hw_del(&hw);
+ return 0;
+ }
+#endif /* HAVE_LIBVNCSERVER */
+
+ return 0;
+}
+COMMAND_HELP(keyboard) {
+ fprintf(f, "\tkeyboard\n");
+ if (summary) return;
+
+ fprintf(f, "Attaches new keyboard unit.\n");
+}
+