#!/usr/bin/python
#licence GPL
import time
import serial
import os
import sys
import termios
import tty

wait_between_strokes=0
serial_port='/dev/ttyS0'
serial_baudrate=19200

# This program reads a file, ignores all non-printable characters except ENTER and TAB,
# converts characters to ps2 keyboard scancodes (US keymap) and sends them via /dev/ttyS0
# serial line out. It needs to have permission to write to ttyS0 or run as root.
#
# The baud rate is 19200 and it MUST use 8-bit because scancodes are 8-bit.
#
# The other side should run this as root:
# inputattach --baud 19200 --ps2serkbd /dev/ttyUSB0
# You can notice, that serial port over USB works.
#
# The hardware needed is simple - just null modem cable
#
# It would run via bluetooth probably, but there is no encryption, therefore it isn't 
# wise in most scenarios.

#The relevant set seems to be Scan Code Set 2 
keyboard=[[0, 0], #0
          [0, 0],
          [0, 0],
          [0, 0],
          [0, 0],
          [0, 0],
          [0, 0],
          [0, 0],
          [0, 0],
          [0x0d, 0], #tab
          [0, 0], #10
          [0, 0],
          [0, 0],
          [0x5a, 0],
          [0, 0],
          [0, 0],
          [0, 0],
          [0, 0],
          [0, 0],
          [0, 0],
          [0, 0], #20
          [0, 0],
          [0, 0],
          [0, 0],
          [0, 0],
          [0, 0],
          [0, 0],
          [0, 0],
          [0, 0],
          [0, 0],
          [0, 0], #30
          [0, 0],
          [0x29, 0], #space #?
          [0x12, 0x16], #!
          [0x12, 0x52], #"
          [0x12, 0x26], ##
          [0x12, 0x25], #$
          [0x12, 0x2e], #%
          [0x12, 0x3d], #&
          [0x52, 0], #'
          [0x12, 0x46], #( #40
          [0x12, 0x45], #)
          [0x12, 0x3e], #*
          [0x12, 0x55], #+ #?
          [0x41, 0x41], #,
          [0x4e, 0], #-
          [0x49, 0], #.
          [0x4a, 0], #/
          [0x45, 0], #0
          [0x16, 0], #1
          [0x1e, 0], #2 #50
          [0x26, 0], #3
          [0x25, 0], #4
          [0x2E, 0], #5
          [0x36, 0], #6
          [0x3d, 0], #7
          [0x3e, 0], #8
          [0x46, 0], #9
          [0x12, 0x4c], #:
          [0x4c, 0], #;
          [0x12, 0x41], #<
          [0x55, 0], #= 
          [0x12, 0x49], #>
          [0x12, 0x4a], #?
          [0x12, 0x1e], #@
          [0x12, 0x1c], #A
          [0x12, 0x32], #B
          [0x12, 0x21], #C
          [0x12, 0x23], #D
          [0x12, 0x24], #E
          [0x12, 0x2b], #F
          [0x12, 0x34], #G
          [0x12, 0x33], #H
          [0x12, 0x43], #I
          [0x12, 0x3b], #J
          [0x12, 0x42], #K
          [0x12, 0x4b], #L
          [0x12, 0x3a], #M
          [0x12, 0x31], #N
          [0x12, 0x44], #O
          [0x12, 0x4d], #P
          [0x12, 0x15], #Q
          [0x12, 0x2d], #R
          [0x12, 0x1b], #S
          [0x12, 0x2c], #T
          [0x12, 0x3c], #U
          [0x12, 0x2a], #V
          [0x12, 0x1d], #W
          [0x12, 0x22], #X
          [0x12, 0x35], #Y
          [0x12, 0x1a], #Z
          [0x54, 0], #[
          [0x5d, 0], #\
          [0x5b, 0], #]
          [0x12, 0x36], #^
          [0x12, 0x4e], #_
          [0x0e, 0], #`
          [0x1c, 0], #a
          [0x32, 0], #b
          [0x21, 0], #c
          [0x23, 0], #d
          [0x24, 0], #e
          [0x2b, 0], #f
          [0x34, 0], #g
          [0x33, 0], #h
          [0x43, 0], #i
          [0x3b, 0], #j
          [0x42, 0], #k
          [0x4b, 0], #l
          [0x3a, 0], #m
          [0x31, 0], #n
          [0x44, 0], #o
          [0x4d, 0], #p
          [0x15, 0], #q
          [0x2d, 0], #r
          [0x1b, 0], #s
          [0x2c, 0], #t
          [0x3c, 0], #u
          [0x2a, 0], #v
          [0x1d, 0], #w
          [0x22, 0], #x
          [0x35, 0], #y
          [0x1a, 0], #z
          [0x12, 0x54], #{
          [0x12, 0x5d], #|
          [0x12, 0x5b], #}
          [0x12, 0x0e]] #~

#use UCW Czech keyboard or Right-Alt switched us/cz keymap for Czech symbols

def getch():
	fd = sys.stdin.fileno()
	old_settings = termios.tcgetattr(fd)
	try:
		tty.setraw(fd)
		ch = sys.stdin.read(1)
	finally:
		termios.tcsetattr(fd, termios.TCSADRAIN, old_settings)
	return ch



#if len(sys.argv) < 2:
#	print 'Usage: serialkbd.py filename'
#	sys.exit(1)
#else:
#        filename=str(sys.argv[1])
#	file_to_push=open(filename, 'r')
          

# configure the serial connections
ser = serial.Serial(
	#port='/dev/ttyS0',
	port=serial_port,   
	#baudrate=19200,
	baudrate=serial_baudrate,
	parity=serial.PARITY_ODD,
	stopbits=serial.STOPBITS_TWO,
	bytesize=serial.EIGHTBITS
)

ser.isOpen()

while 1 :
    input = getch()
    if input == 'q':
        ser.close()
        exit()
    else:
	print '##: ', input, ' :##: ',
	try:
		file_to_push=open(input, 'r') #yeah, the filename is just one character - ugly way, I know
		for line in file_to_push:
			print line
			for i in range(0, len(line)):
				#print line[i], ' :', 
				ascii=ord(line[i])
				if (ascii == 9) or (ascii == 13) or ((ascii >= 32) and (ascii <=126)):
					if (keyboard[ascii][0] != 0):
						ser.write(chr(keyboard[ascii][0]))
						#print keyboard[ascii][0], ' ',
						if (keyboard[ascii][1] != 0):
							ser.write(chr(keyboard[ascii][1]))
							#print keyboard[ascii][1], ' ',
							ser.write(chr(0xf0))
							#print 0xf0, ' ',
							ser.write(chr(keyboard[ascii][1]))
							#print keyboard[ascii][1], ' ',
						ser.write(chr(0xf0))
						#print 0xf0, ' ',
						ser.write(chr(keyboard[ascii][0]))		
						#print keyboard[ascii][0], ' '
						if (wait_between_strokes!=0): 
							time.sleep(wait_between_strokes)
			
			#ser.write(chr(0x5a))
			#ser.write(chr(0xf0))
			#ser.write(chr(0x5a))
			if (wait_between_strokes!=0): 
				time.sleep(wait_between_strokes)
	except:
		print "The file doesn't exist."
