Logo Search packages:      
Sourcecode: ardour version File versions

remote_kbd.cc

/*
    Copyright (C) 2001 Paul Davis
    
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.

    $Id: remote_kbd.cc,v 1.8 2003/01/26 05:36:21 trutkin Exp $
*/

#include <ncurses.h>
#include "compat.h"

#include <iostream>

#include <errno.h>
#include <sys/poll.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <linux/keyboard.h>
#include <sigc++/signal_system.h>
#include <netdb.h>

#include <pbd/error.h>
#include <pbd/failed_constructor.h>
#include <pbd/textreceiver.h>

#include "physical_keyboard.h"

#include "i18n.h"

PhysicalKeyboard *kbd;
int server_socket;
int client_socket;
int keyboard;
bool have_client = false;

int
key_press_handler (int keyboard_state, int key)

{
      if ((keyboard_state & PhysicalKeyboard::Control) &&
          (keyboard_state & PhysicalKeyboard::Shift) &&
          (key == 28 || key == '\\')) { /* print screen/sys rq */
            
            /* we're done */
            
            return 1;
      }

      if (! have_client) {
                // JHALL: we can't put this in key_event_handler and get useful results because
                // JHALL: keyboard_state isn't set yet.
            kbd->print_key(key);
      }

      return 0;
}

int
key_event_handler (unsigned char key)

{
      if (! have_client) {
            return 0;
      }

      if (write (client_socket, &key, 1) != 1) {
            error << compose(_("cannot write key to socket (%1)"), strerror (errno)) << endmsg;
            return -1;
      }
      return 0;
}

int
make_socket ()
{
      int fd;
      struct sockaddr_in addr;
      struct servent *srv;

      if ((fd = socket (AF_INET, SOCK_STREAM, 6)) < 0) {
            error << _("cannot create server socket") << endmsg;
            return -1;
      }

      addr.sin_family = AF_INET;
      if ((srv = getservbyname("remote_kbd", "tcp")) != 0) {
            addr.sin_port = srv->s_port;
      } else {
            addr.sin_port = htons(9763);
      }
      addr.sin_addr.s_addr=htonl(INADDR_ANY);

      if (bind (fd, (struct sockaddr *) &addr, sizeof (addr)) < 0) {
            error << compose(_("cannot bind server to socket (%1"), strerror (errno)) << endmsg;
            close (fd);
            return -1;
      }

      if (listen (fd, 1) < 0) {
            error << _("cannot enable listen on server socket") << endmsg;
            close (fd);
            return -1;
      }

      return fd;
}

void
io_loop ()

{
      bool done = false;
      struct pollfd pfd[3];
      char buf[256];
      struct sockaddr_in client_addr;
      socklen_t client_addrlen;

      while (!done) {
            
            pfd[0].fd = server_socket;
            pfd[0].events = POLLIN | POLLERR;

            pfd[1].fd = keyboard;
            pfd[1].events = POLLIN | POLLERR;

            if (have_client) {
                  pfd[2].fd = client_socket;
                  pfd[2].events = POLLIN | POLLERR | POLLHUP;
            } else {
                  pfd[2].revents = 0;
            }
            
            if (poll (pfd, have_client ? 3 : 2, 1000) < 0) {
                  if (errno == EINTR) {
                        cout << "poll interrupted\n";
                        // this happens mostly when run
                        // under gdb, or when exiting due to a signal
                        continue;
                  }

                  error << compose(_("tty: poll call failed (%1)"), strerror (errno)) << endmsg;
                  break;
            }
            
            if (pfd[0].revents & POLLERR) {
                  error << _("socket: poll reports error.") << endmsg;
                  break;
            }

            if (pfd[0].revents != 0) {
                  memset (&client_addr, 0, sizeof (client_addr));
                  client_addrlen = sizeof (client_addr);

                  if ((client_socket = accept (server_socket, (struct sockaddr *) &client_addr, &client_addrlen)) < 0) {
                        error << compose(_("cannot accept new connection (%1"), strerror (errno)) << endmsg;
                        continue;
                  } else {
                        have_client = true;
                  }

                  if (fcntl (client_socket, F_SETFL, O_NONBLOCK) < 0) {
                        error << _("cannot set non-block on client socket") << endmsg;
                        close (client_socket);
                        have_client = false;
                  }
            }

            if (pfd[1].revents != 0) {
                  if (kbd->handle_input ()) {
                        break;
                  }
            }

            if (pfd[2].revents & (POLLHUP|POLLERR)) {
                  break;
            }

            if (pfd[2].revents != 0) {
                  while (1) {
                        int n;

                        n = read (client_socket, buf, sizeof(buf));
                        
                        if (n == 0) {
                              have_client = false;
                              done = true;
                              break;
                        }

                        if (n < 0) {
                              if (errno != EAGAIN) {
                                    have_client = false;
                                    done = true;
                                    break;
                              } else {
                                    break;
                              }
                        }

                        if (write (1, buf, n) != n) {
                              error << compose(_("could not forward %1 bytes to stdout (%2)"), n, strerror (errno)) << endmsg;
                        }

                  }
            }
      }

      return;
}

Transmitter  error (Transmitter::Error);
Transmitter  info (Transmitter::Info);
Transmitter  fatal (Transmitter::Fatal);
Transmitter  warning (Transmitter::Warning);
TextReceiver text_receiver ("ksi");

int
main (int argc, char *argv[])

{
      text_receiver.listen_to (error);
      text_receiver.listen_to (info);
      text_receiver.listen_to (fatal);
      text_receiver.listen_to (warning);

      if ((server_socket = make_socket()) < 0) {
            exit (1);
      }

      initscr();
      cbreak();
      noecho();
      nonl();
      werase (stdscr);

      try {
            kbd = new PhysicalKeyboard;
      }

      catch (failed_constructor& err) {
            error << _("could not create keyboard object") << endmsg;
            goto out;
      }

      /* connect the raw event handler that forwards key events */
      
      kbd->key_event.connect (SigC::slot (key_event_handler));
      
      /* allow a little bit of keystroke interpretation */

      kbd->key_press.connect (SigC::slot (key_press_handler));

      keyboard = kbd->selectable();

      io_loop ();

      delete kbd;
  out:
      endwin ();
}

Generated by  Doxygen 1.6.0   Back to index