--- /dev/null
+# -*- coding: utf-8 -*-
+
+# ****************************************************************************
+# Copyright (c) 2008 INdT/Fucapi.
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Lesser General Public License as published by
+# the Free Software Foundation, either version 3 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 Lesser General Public License for more details.
+
+# You should have received a copy of the GNU Lesser General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+# ============================================================================
+# Project Name : PC Remote
+# Author : Jônatas Isvi
+# Email : jonatas.nona@gmail.com
+# Version : 1.0
+# Description : BluetoothConnectionManager
+# ============================================================================
+
+
+import bluetooth
+from exceptions import *
+from genericconnectionmanager import *
+
+class BluetoothConnectionError(Exception):
+ pass
+
+class BluetoothConnectionManager(GenericConnectionManager):
+
+ def __init__(self):
+ GenericConnectionManager.__init__(self)
+ print "BluetoothConnectionManager iniciado."
+ # globals data variables
+ self.sock = None
+ self.port = None
+ self.address = None
+ self.client_sock = None
+ self.client_address = None
+
+ # fast way to create a simple server
+ def create_server(self, protocol, port):
+ self.create_socket(protocol)
+ self.set_port(port)
+ self.bind()
+ self.listen()
+ self.accept()
+
+ # fast way to create a simple client
+ def create_client(self, protocol, address, port):
+ self.create_socket(protocol)
+ self.set_address(address)
+ self.set_port(port)
+ self.connect()
+
+ # search for all devices
+ def find_devices(self, time=8):
+ list_devices = bluetooth.discover_devices(lookup_names = True, duration=time)
+ if list_devices:
+ return list_devices
+ else:
+ raise BluetoothConnectionError, "Device were not found."
+
+ # search the device port
+ def find_port(self, addr):
+ port = None
+ aux = addr.split(":")
+ if len(aux) == 6:
+ services = bluetooth.find_service(address=addr)
+ for i in range(len(services)):
+ port = services[i]['port']
+
+ if port != None:
+ return port
+ else:
+ raise BluetoothConnectionError, "Port not found."
+
+ else:
+ raise BluetoothConnectionError, "Invalid address."
+
+ # search device services
+ def find_services(self, service=None, addr=None):
+ if service == None and addr == None:
+ list = bluetooth.find_service()
+ # returns all services
+ return list
+ elif service != None and addr == None:
+ list = bluetooth.find_service(name=service)
+ # returns only the device services indicated by name
+ if list != []:
+ return list
+ else:
+ raise BluetoothConnectionError, "Name of the service does not exist."
+ elif service == None and addr != None:
+ number = addr.split(":")
+ # returns only the device services indicated by address
+ if(len(number) == 6):
+ list = bluetooth.find_service(address=addr)
+ if list != []:
+ return list
+ else:
+ raise BluetoothConnectionError, "Services not found."
+ else:
+ raise BluetoothConnectionError, "Invalid address."
+ elif service != None and addr != None:
+ number = addr.split(":")
+ # returns only the device service indicated by address
+ if(len(number) == 6):
+ list = bluetooth.find_service(name=service, address=addr)
+ if list != []:
+ return list
+ else:
+ raise BluetoothConnectionError, "Services not found."
+ else:
+ raise BluetoothConnectionError, "Invalid address."
+
+
+ # search the device indicated by name
+ def find_device_address_by_name(self, device_name):
+ list = bluetooth.discover_devices()
+ addr = None
+
+ for address in list:
+ if device_name == bluetooth.lookup_name(address):
+ addr = address
+ break
+ if addr:
+ return addr
+ else:
+ raise BluetoothConnectionError, "Device name not found."
+
+
+ def find_devices_only_names(self):
+ list = self.find_devices()
+ list_names = []
+ for address, names in list:
+ list_names += [names]
+
+ if list_names:
+ return list_names
+ else:
+ raise BluetoothConnectionError, "Devices were not found."
+
+ # get the client address
+ def get_client_address(self):
+ return self.client_address
+
+ # set the port to communicate
+ def set_port(self, port):
+ self.port = port
+
+ # get the port to communicate
+ def get_port(self):
+ return self.port
+
+ # set the device address
+ def set_address(self, address):
+ aux = address.split(":")
+ if len(aux) == 6:
+ self.address = address
+ else:
+ raise BluetoothConnectionError, "Invalid address."
+
+ # get the device address
+ def get_address(self):
+ return self.address
+
+ # create a socket with a determinated protocol
+ def create_socket(self, protocol=None):
+ if protocol == 'rfcomm' or protocol == 'RFCOMM':
+ self.sock = bluetooth.BluetoothSocket(bluetooth.RFCOMM)
+ elif protocol == 'l2cap' or protocol == 'L2CAP':
+ self.sock = bluetooth.BluetoothSocket(bluetooth.L2CAP)
+ else:
+ raise BluetoothConnectionError, "Undefined Protocol."
+
+ # bind the communication
+ def bind(self):
+ self.sock.bind(("", self.get_port()))
+
+ # just listen the tube, only to server
+ def listen(self):
+ self.sock.listen(1)
+
+ # accept the client communication
+ # returns an object
+ def accept(self):
+ self.client_sock, self.client_address = self.sock.accept()
+
+ # connect devices
+ def connect(self):
+ self.sock.connect((self.get_address(), self.get_port()))
+
+ # send string message
+ def send_message(self, msg=None):
+ self.sock.send(msg)
+
+ # receive string message
+ def received_message(self):
+ return self.client_sock.recv(1024)
+
+ # close connection
+ def close(self):
+ if self.sock != None and self.client_sock != None:
+ self.client_sock.close()
+ self.sock.close()
+ elif self.sock != None and self.client_sock == None:
+ self.sock.close()
+ else:
+ self.client_sock.close()
+
--- /dev/null
+# -*- coding: utf-8 -*-
+
+# ****************************************************************************
+# Copyright (c) 2008 INdT/Fucapi.
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Lesser General Public License as published by
+# the Free Software Foundation, either version 3 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 Lesser General Public License for more details.
+
+# You should have received a copy of the GNU Lesser General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+# ============================================================================
+# Project Name : PC Remote
+# Author : André Portela
+# Email : andre_portela@hotmail.com
+# Version : 1.0
+# Description : GenericConnectionManager Class
+# ============================================================================
+
+
+class GenericConnectionManager:
+
+ def __init__(self):
+ print "GenericConnectionManager iniciado."
+ self.tipo = "generico"
+
+ def identify_app(self):
+ print "identify_app"
--- /dev/null
+# -*- coding: utf-8 -*-
+
+# ****************************************************************************
+# Copyright (c) 2008 INdT/Fucapi.
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Lesser General Public License as published by
+# the Free Software Foundation, either version 3 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 Lesser General Public License for more details.
+
+# You should have received a copy of the GNU Lesser General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+# ============================================================================
+# Project Name : PC Remote
+# Author : André Portela
+# Email : andre_portela_@hotmail.com
+# Reviewer : Jônatas Isvi
+# Email : jonatas.nona@gmail.com
+# Version : 1.0
+# Description : Interface Class, connection manager
+# ============================================================================
+
+from wirelessconnectionmanager import *
+from bluetoothconnectionmanager import *
+from exceptions import *
+
+
+# connections aliases
+_btconst = ['bluetooth', 'BLUETOOTH', 'blue']
+_wificonst = ['wireless', 'WIRELESS', 'wifi']
+
+class Iconnection:
+ def __init__(self, string):
+ self.string = string
+ if(self.string in _btconst):
+ self.obj = BluetoothConnectionManager()
+ elif(self.string in _wificonst):
+ self.obj = WirelessConnectionManager()
+ else:
+ raise IconnectionError, "Undefined type."
+
+
+ # ********************************************************************************
+ # Generic methods -> Wireless and Bluetooth *
+ # ********************************************************************************
+
+ # create a socket with defined protocol
+ def create_socket(self, protocol=None):
+ self.obj.create_socket(protocol)
+
+ # connect device
+ def connect(self):
+ self.obj.connect()
+
+ # accept the connection
+ def accept(self):
+ return self.obj.accept()
+
+ # send a message to device
+ def send_message(self, msg=None):
+ self.obj.send_message(msg)
+
+ # received a message
+ def received_message(self):
+ return self.obj.received_message()
+
+ # bind the connection
+ def bind(self):
+ self.obj.bind()
+
+ # listen the connection
+ def listen(self):
+ self.obj.listen()
+
+ # close connection
+ def close(self):
+ self.obj.close()
+
+ # set the port to communicate
+ def set_port(self, port):
+ self.obj.set_port(port)
+
+ # get the port to communicate
+ def get_port(self):
+ return self.obj.get_port()
+
+ # set the device address
+ def set_address(self, address):
+ self.obj.set_address(address)
+
+ # get the device address
+ def get_address(self):
+ return self.obj.get_address()
+
+ # get the client address
+ def get_client_address(self):
+ return self.obj.get_client_address()
+
+ # ************************************************************************************
+ # Bluetooth methods - All methods for bluetooth services *
+ # ************************************************************************************
+
+ # fast way to create a simple server
+ def bt_create_server(self, protocol, port):
+ if self.string in _btconst:
+ return self.obj.create_server(protocol, port)
+ else:
+ raise IconnectionError, "Only method used by Bluetooth connections."
+
+ # fast way to create a simple client
+ def bt_create_client(self, protocol, address, port):
+ if self.string in _btconst:
+ return self.obj.create_client(protocol, address, port)
+ else:
+ raise IconnectionError, "Only method used by Bluetooth connections."
+
+ # search for all devices
+ def bt_find_devices(self, time=8):
+ if self.string in _btconst:
+ return self.obj.find_devices(time)
+ else:
+ raise IconnectionError, "Only method used by Bluetooth connections."
+
+ # search only devices names
+ def bt_find_devices_only_names(self):
+ if self.string in _btconst:
+ return self.obj.find_devices_only_names()
+ else:
+ raise IconnectionError, "Only method used by Bluetooth connections."
+
+
+ # search the device port
+ def bt_find_port(self, addr):
+ if self.string in _btconst:
+ return self.obj.find_port(addr)
+ else:
+ raise IconnectionError, "Only method used by Bluetooth connections."
+
+
+ # search device services
+ def bt_find_services(self, service=None, addr=None):
+ if self.string in _btconst:
+ return self.obj.find_services(service, addr)
+ else:
+ raise IconnectionError, "Only method used by Bluetooth connections."
+
+
+ # search the device indicated by name
+ def bt_find_device_address_by_name(self, device_name=None):
+ if self.string in _btconst:
+ return self.obj.find_device_address_by_name(device_name)
+ else:
+ raise IconnectionError, "Only method used by Bluetooth connections."
+
+
+
+ # ***********************************************************************************
+ # Wireless method - All methods for wireless services *
+ # ***********************************************************************************
--- /dev/null
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+# ****************************************************************************
+# Copyright (c) 2008 INdT/Fucapi.
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Lesser General Public License as published by
+# the Free Software Foundation, either version 3 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 Lesser General Public License for more details.
+
+# You should have received a copy of the GNU Lesser General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+# ============================================================================
+# Project Name : PC Remote
+# Author : André Portela
+# Email : andre_portela_@hotmail.com
+# Version : 0.1
+# Description : Tablet Application Wireless Connection Manager Class
+# ============================================================================
+
+from genericconnectionmanager import *
+
+class WirelessConnectionManager(GenericConnectionManager):
+ def __init__(self):
+ GenericConnectionManager.__init__(self)
+ #para acessar facilmente qualquer metodo generico
+ #self.super = generico()
+ print "init do Wireless"
+ self.tipo = "wireless"
+
+ def metodo(self):
+ print "(Wireless)Metodo do", self.tipo
+
+
--- /dev/null
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+# ****************************************************************************
+# Copyright (c) 2008 INdT/Fucapi.
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Lesser General Public License as published by
+# the Free Software Foundation, either version 3 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 Lesser General Public License for more details.
+
+# You should have received a copy of the GNU Lesser General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+# ============================================================================
+# Project Name :PC Remote
+# Author :André Portela
+# Email :andre_portela_@hotmail.com
+# Version :1.0
+# Module :main
+# Class :PCRemote custom Edje object with it's own call backs for the
+# main screen
+# ============================================================================
+
+import thread
+import ecore
+import ecore.evas
+import evas.decorators
+import edje
+import edje.decorators
+import time
+from connection.iconnection import Iconnection
+from kineticlist import *
+
+class EvasCanvas(object):
+
+ def __init__(self, fullscreen, engine, size):
+ #f = ecore.evas.SoftwareX11
+ self.evas_obj = engine(w=size[0], h=size[1])
+ self.evas_obj.callback_delete_request = self.on_delete_request
+ self.evas_obj.callback_resize = self.on_resize
+
+ self.evas_obj.title = "PCRemote"
+ self.evas_obj.name_class = ('PC Remote', 'main')
+ self.evas_obj.fullscreen = fullscreen
+ self.evas_obj.size = size
+ self.evas_obj.show()
+
+ def on_resize(self, evas_obj):
+ x, y, w, h = evas_obj.evas.viewport
+ size = (w, h)
+ for key in evas_obj.data.keys():
+ evas_obj.data[key].size = size
+
+ def on_delete_request(self, evas_obj):
+ ecore.main_loop_quit()
+
+ def show(self):
+ self.evas_obj.show()
+
+class EdjeObject(edje.Edje):
+
+ def __init__(self, canvas_class, file, group='main',name='edje'):
+ self.canvas_class = canvas_class
+ self.x11 = canvas_class.evas_obj
+ self.canvas = self.x11.evas
+ edje.Edje.__init__(self, self.canvas, file = file, group = group)
+ self.size = self.canvas.size
+ self.x11.data[name] = self
+
+class MainScreen(EdjeObject):
+
+ def __init__(self, canvas, file, group, name, connection):
+ EdjeObject.__init__(self, canvas, file = file, group = group,name = name)
+
+ self.file = file
+ self.on_key_down_add(self.key_down_cb, self.x11)
+ self.sock_address = None
+ #flag that sync the discovery device's thread
+ self.flag = False
+ #flag that sync the connecting device's thread
+ self.connecting_flag = False
+ #lista de dispositivos descobertos
+ self.lista_dispositivos = []
+ #objeto que cria a conexao bluetooth
+ self.conexao = connection
+ self.kineticlist = False
+ #portela mock object
+ self.lista_teste = ['Andre Portela', 'Juliana Dias', 'Victor Hugo', 'Lucina Dias', 'Rosa Dias', 'James Italiano', 'Nona Izvi', 'Fergus Mao', 'Mauricio Brilhante', 'Edward Ordonez', 'Brankinhu', 'Banco Real', 'Banco Itaú', 'ABN-AMRO BANK']
+
+ def key_down_cb(self, bg, event, ee):
+ k = event.key
+ if k == "Escape":
+ ecore.main_loop_quit()
+ elif k == "F6":
+ ee.fullscreen = not ee.fullscreen
+ elif k == "F8":
+ print "-"
+ elif k == "F7":
+ print "+"
+
+ def mkKineticList(self):
+ #kinetic list (the item values are tied with the part "item_background" of the "list_item" group)
+ #self.kineticlist = KineticList(self.canvas, file=self.file, item_width=407, item_height=38, father=self)
+ self.kineticlist = KineticList(self.canvas, file=self.file, item_height=57, father=self)
+ self.kineticlist.freeze()
+ #portela - test kinetic list with several devices
+ #for item in self.lista_teste:
+ #populates the list with the device's names
+ for item in self.lista_dispositivos:
+ self.kineticlist.row_add(item)
+ #reorganize and draw the list
+ self.kineticlist.thaw()
+ #embed the list in the edje object
+ self.part_swallow("list", self.kineticlist);
+
+ @edje.decorators.signal_callback("connect_to","choice")
+ def connect_to(self, emission, source):
+ self.sock_address = self.part_text_get(source)
+ #flag that sync the connecting device's thread
+ self.connecting_flag = False
+ self.signal_emit("start","device_connect")
+ thread.start_new_thread(MainScreen.threaded_connection,(self,))
+
+ def threaded_connection(self):
+ self.conexao.create_socket('l2cap')
+ print 'connecting to: %s' % self.sock_address
+ self.conexao.set_address(self.conexao.bt_find_device_address_by_name(self.sock_address))
+ self.conexao.set_port(0x1001)
+ self.conexao.connect()
+ self.connecting_flag = True
+
+ @edje.decorators.signal_callback("connecting","device")
+ def connecting_check(self, emission, source):
+ if self.connecting_flag:
+ self.connecting_flag = False
+ self.signal_emit("stop","device_connect")
+ #we are sending a signal to main edje (there is time to animate the device locking)
+ self.signal_emit("begin","init")
+
+ @edje.decorators.signal_callback("animation_still_loading", "loading")
+ def still_loading_cb(self, emission, source):
+ if self.flag:
+ self.flag = False
+ self.signal_emit("program,stop","loading")
+ if self.lista_dispositivos != []:
+ self.mkKineticList()
+ else:
+ self.no_device_found()
+
+ @edje.decorators.signal_callback("animation_sair_ended", "sair")
+ def saida(self, signal, source):
+ ecore.main_loop_quit()
+
+ @edje.decorators.signal_callback("animation_rastrear_ended", "rastrear")
+ def rastrear_key_down(self, signal, source):
+ thread.start_new_thread(MainScreen.rastrear_dispositivos,(self,None))
+
+ @edje.decorators.signal_callback("program,start", "novodevice")
+ def search_devices_again(self, signal, source):
+ self.part_unswallow(self.kineticlist)
+ del self.kineticlist
+ MainScreen.rastrear_key_down(self, None, None)
+
+ def rastrear_dispositivos(self,arg):
+ try:
+ self.lista_dispositivos = self.conexao.bt_find_devices_only_names()
+ except:
+ self.lista_dispositivos = []
+ self.flag = True
+
+ def no_device_found(self):
+ self.signal_emit("program,start","no_device")
+
+class TabletScreen(EdjeObject):
+
+ def __init__(self, canvas, file, group,name, connection):
+ EdjeObject.__init__(self, canvas, file = file, group = group,name = name)
+ self.on_key_down_add(self.key_down_cb, self.x11)
+ #emitt events only if the mouse is inside the touch object area
+ (self.part_object_get('touch')).pointer_mode_set(evas.EVAS_OBJECT_POINTER_MODE_NOGRAB)
+ #assign the mouse_move_cb method as a mouse move callback for the touch part of the edje object
+ (self.part_object_get('touch')).on_mouse_move_add(self.mouse_move_cb)
+ #self.on_mouse_move_add(TabletScreen.mouse_move_cb)
+ self.sock = connection
+ #this flag indicates either the user are grabing something or not on the target
+ self.drag_flag = False
+ #this float indicates the wich the method left_click_down was called, and will be
+ #calculated against lcu_time in left_click_up method
+ self.lcd_time = 0.0
+ #tecla alt
+ self.alt_flag = False
+ #tecla shift
+ self.iso_shift_flag = False
+ #lista de aliases das teclas de comando Alt+F(x)
+ #self.fletters = ['p', 'q', 'w', '', 'r', '', '', '', '', 'o']
+ self.keys_dict = {'q':1, 'w':2, 'e':3, 'r':4, 't':5, 'y':6, 'u':7, 'i':8, 'o':9, 'p':0, \
+ 'a':'Shift_L+1', 's':'', 'd':'Shift_L+2', 'f':'Shift_L+3', 'g':'backslash', \
+ 'h':'slash', 'j':'Shift_L+9', 'k': 'Shift_L+0', 'l':'Shift_L+8', '\'':'Shift_L+slash',\
+ 'z':'', 'x':'Shift_L+6', 'c':'', 'v':'Shift_L+5', 'b':'Shift_L+7', 'n':'Shift_L+4', \
+ 'm':'', ';':'', '-':'Shift_L+minus', '+':'equal'}
+
+ @edje.decorators.signal_callback('mouse,down,1', 'tablet_bt-L_area')
+ def left_click_down(self, signal, source):
+ self.lcd_time = time.time()
+ #if the user are grabing something, release it
+ if self.drag_flag:
+ self.drag_flag = False
+ self.sock.send_message("Mouse:#left_click")
+
+ @edje.decorators.signal_callback('mouse,up,1', 'tablet_bt-L_area')
+ def left_click_up(self, signal, source):
+ lcu_time = time.time()
+ #threshold of 0.5 seconds to grab something on the target
+ elapsed_time = lcu_time - self.lcd_time
+ if elapsed_time < 0.5:
+ #do a simple click
+ self.sock.send_message("Mouse:#left_click")
+ self.sock.send_message("Mouse:#left_click")
+ else:
+ #do mouse grab
+ self.sock.send_message("Mouse:#left_click")
+ self.drag_flag = True
+
+ @edje.decorators.signal_callback('mouse,up,1', 'tablet_bt-R_area')
+ def rigth_click(self, signal, source):
+ self.sock.send_message("Mouse:#right_click")
+ self.sock.send_message("Mouse:#right_click")
+
+ def key_down_cb(self, bg, event, ee):
+ k = event.key
+ print k
+ if k == "Escape":
+ self.sock.send_message("Keyboard:Escape")
+ elif k == "F6":
+ ee.fullscreen = not ee.fullscreen
+ elif k == "F8":
+ self.sock.send_message("Keyboard:Up")
+ elif k == "F7":
+ self.sock.send_message("Keyboard:Down")
+ elif k == "Return":
+ self.alt_flag = True
+ elif k == "ISO_Level3_Shift":
+ self.iso_shift_flag = True
+ else:
+ if self.alt_flag:
+ #if k in self.fletters:
+ # self.sock.send_message("Keyboard:Alt+F%s" % (self.fletters.index(k)))
+ # self.alt_flag = False
+ #elif k == 'space':
+ # self.sock.send_message("Keyboard:Alt+Space")
+ # self.alt_flag = False
+ #else:
+ # self.alt_flag = False
+ if self.keys_dict.has_key(k) and isinstance(self.keys_dict[k], int):
+ self.sock.send_message("Keyboard:Alt_L")
+ self.sock.send_message("Keyboard:F%s" % (self.keys_dict[k]))
+ self.alt_flag = False
+ elif k == 'space':
+ self.sock.send_message("Keyboard:Alt_L")
+ self.sock.send_message("Keyboard:space")
+ self.alt_flag = False
+ else:
+ self.alt_flag = False
+ #else:
+ #self.sock.send_message("Keyboard:%s" % k)
+ elif self.iso_shift_flag:
+ if self.keys_dict.has_key(k) and self.keys_dict[k] and isinstance(self.keys_dict[k], str):
+ lst = self.keys_dict[k].split('+')
+ for cmd in lst:
+ self.sock.send_message("Keyboard:%s" % cmd)
+ self.iso_shift_flag = False
+ elif self.keys_dict.has_key(k) and self.keys_dict and isinstance(self.keys_dict[k], int):
+ self.sock.send_message("Keyboard:%s" % self.keys_dict[k])
+ self.iso_shift_flag = False
+ else:
+ self.iso_shift_flag = False
+ else:
+ self.sock.send_message("Keyboard:%s" % k)
+
+ def mouse_move_cb(self, part, event):
+ x, y = event.position.output[0], event.position.output[1]
+ self.sock.send_message("Mouse:"+str(x)+","+str(y))
+
+class SlideScreen(EdjeObject):
+
+ def __init__(self, canvas, file, group,name, connection):
+ EdjeObject.__init__(self, canvas, file = file, group = group,name = name)
+ self.on_key_down_add(self.key_down_cb, self.x11)
+ #emitt events only if the mouse is inside the touch object area
+ (self.part_object_get('touch')).pointer_mode_set(evas.EVAS_OBJECT_POINTER_MODE_NOGRAB)
+ #assign the mouse_move_cb method as a mouse move callback for the touch part of the edje object
+ (self.part_object_get('touch')).on_mouse_move_add(self.mouse_move_cb)
+ #self.on_mouse_move_add(TabletScreen.mouse_move_cb)
+ self.sock = connection
+ #this flag indicates either the user are grabing something or not on the target
+ self.drag_flag = False
+ #helps to coordenate presentation
+ self.keyboard_flag = True
+ #this float indicates the wich the method left_click_down was called, and will be
+ #calculated against lcu_time in left_click_up method
+ self.lcd_time = 0.0
+
+ @edje.decorators.signal_callback('mouse,down,1', 'slide_bt-left_area')
+ def left_click_down(self, signal, source):
+ if self.keyboard_flag:
+ self.lcd_time = time.time()
+ #if the user are grabing something, release it
+ if self.drag_flag:
+ self.drag_flag = False
+ self.sock.send_message("Mouse:#left_click")
+
+ @edje.decorators.signal_callback('mouse,up,1', 'slide_bt-left_area')
+ def left_click_up(self, signal, source):
+ if self.keyboard_flag:
+ lcu_time = time.time()
+ #threshold of 0.5 seconds to grab something on the target
+ elapsed_time = lcu_time - self.lcd_time
+ if elapsed_time < 0.5:
+ #do a simple click
+ self.sock.send_message("Mouse:#left_click")
+ self.sock.send_message("Mouse:#left_click")
+ else:
+ #do mouse grab
+ self.sock.send_message("Mouse:#left_click")
+ self.drag_flag = True
+ else:
+ self.sock.send_message("Keyboard:%s" % "Left")
+
+ @edje.decorators.signal_callback('mouse,up,1', 'slide_bt-right_area')
+ def rigth_click(self, signal, source):
+ if self.keyboard_flag:
+ self.sock.send_message("Mouse:#right_click")
+ self.sock.send_message("Mouse:#right_click")
+ else:
+ self.sock.send_message("Keyboard:%s" % "Right")
+
+ def key_down_cb(self, bg, event, ee):
+ k = event.key
+ print k
+ if k == "Escape":
+ self.sock.send_message("Keyboard:Escape")
+ elif k == "F6":
+ self.keyboard_flag = not self.keyboard_flag
+ self.sock.send_message("Keyboard:F5")
+ elif k == "F8":
+ self.sock.send_message("Keyboard:Up")
+ elif k == "F7":
+ self.sock.send_message("Keyboard:Down")
+ else:
+ self.sock.send_message("Keyboard:%s" % k)
+
+ def mouse_move_cb(self, part, event):
+ x, y = event.position.output[0], event.position.output[1]
+ self.sock.send_message("Mouse:"+str(x)+","+str(y))
--- /dev/null
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+# ****************************************************************************
+# Copyright (c) 2008 INdT/Fucapi.
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Lesser General Public License as published by
+# the Free Software Foundation, either version 3 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 Lesser General Public License for more details.
+
+# You should have received a copy of the GNU Lesser General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+# ============================================================================
+# Project Name :PC Remote
+# Author :Gustavo Sverzut Barbieri ; André Luiz do Canto Portela
+# Email :barbieri@gmail.com ; andre_portela_@hotmail.com
+# Version :1.0
+# Module :main
+# Class :This class are an adaptation of barbieri's demo 03 of edje
+# :python-bindings
+# ============================================================================
+
+import evas
+import edje
+import ecore
+import time
+
+class KineticList(evas.ClippedSmartObject):
+ (
+ SCROLL_PAGE_FORWARD,
+ SCROLL_PAGE_BACKWARD,
+ SCROLL_STEP_FORWARD,
+ SCROLL_STEP_BACKWARD,
+ SCROLL_PIXELS_DOWN,
+ SCROLL_PIXELS_UP
+ ) = range(6)
+
+
+ def __init__(self, ecanvas, file, item_width=-1, item_height=-1, father=None):
+ '''
+ if item_width or item_height is left out the width (resp. height)
+ of the List element is used.
+ '''
+ self.father = father
+ evas.ClippedSmartObject.__init__(self, ecanvas)
+ self.elements = []
+ self.objects = []
+ self.w = 32
+ self.h = 32
+
+ self.realized = False
+
+ self.top_pos = 0
+ self.last_top_pos = 0
+ self.last_start_row = -1
+
+ self.canvas = ecanvas
+ self.edje_file = file
+
+ self.row_width = item_width
+ self.row_height = item_height
+
+ self.__manage_objects()
+
+ self.mouse_down = False
+ self.last_y_pos = 0
+ self.start_pos = 0
+ self.mouse_moved = False
+ self.continue_scrolling = False
+ self.is_scrolling = False
+ self.do_freeze = False
+
+ def freeze(self):
+ self.do_freeze = True
+
+ def thaw(self):
+ self.do_freeze = False
+ if self.realized:
+ self.__update_variables_after_new_elements()
+ self.__update_screen()
+
+ def scroll(self, scroll_type, amount=1):
+ self.continue_scrolling = False
+
+ if scroll_type == self.SCROLL_PAGE_FORWARD:
+ self.top_pos += amount * self.row_height * self.max_visible_rows
+ elif scroll_type == self.SCROLL_PAGE_BACKWARD:
+ self.top_pos -= amount * self.row_height * self.max_visible_rows
+ elif scroll_type == self.SCROLL_STEP_FORWARD:
+ self.top_pos += amount * self.row_height
+ elif scroll_type == self.SCROLL_STEP_BACKWARD:
+ self.top_pos -= amount * self.row_height
+ elif scroll_type == self.SCROLL_PIXELS_DOWN:
+ self.top_pos += amount
+ elif scroll_type == self.SCROLL_PIXELS_UP:
+ self.top_pos -= amount
+ else:
+ return
+
+ self.__update_screen()
+
+ def __on_mouse_clicked(self, edje_obj, emission, source, data=None):
+ #for obj in self.objects:
+ # if obj != edje_obj:
+ # obj.signal_emit("fadeout", "")
+
+ #edje_obj.signal_emit("open", "")
+ #TODO:portela - it works! :D
+ edje_obj.signal_emit("program,start","label")
+ #we are setting up the choice's text on the main edje object
+ self.parent_get().part_text_set("choice",edje_obj.part_text_get("label"))
+
+ def __on_mouse_move(self, edje_obj, emission, source, data=None):
+ if self.mouse_down:
+ x_pos, y_pos = self.canvas.pointer_canvas_xy
+ diff = int(self.last_y_pos - y_pos)
+
+ if diff == 0:
+ return
+
+ self.mouse_moved = True
+
+ # Reset the data if the direction of the mouse move is changed
+ if self.last_diff != -1 and (diff < 0) != (self.last_diff < 0):
+ self.last_y_pos = y_pos
+ self.start_pos = y_pos
+ self.start_time = time.time()
+
+ self.last_diff = diff
+ self.top_pos += diff
+
+ self.last_y_pos = y_pos
+ self.__update_screen()
+ self.last_update_time = time.time()
+
+ #TODO: portela mod
+ def __on_blink_ended(self, edje_obj, emission, source, data=None):
+ for obj in self.objects:
+ obj.signal_emit("program,start,fade,out","label")
+ #we are sending a signal for the application connect the target
+ self.parent_get().signal_emit("connect_to","choice")
+
+ #TODO: portela mod
+
+ def show_list(self):
+ for obj in self.objects:
+ obj.signal_emit("program,start,fade,in","label")
+
+ def __on_mouse_down(self, edje_obj, emission, source, data=None):
+ if not self.is_scrolling:
+ self.mouse_moved = False
+
+ self.continue_scrolling = False
+ self.mouse_down = True
+
+ x_pos, y_pos = self.canvas.pointer_canvas_xy
+
+ self.last_diff = -1
+ self.last_y_pos = y_pos
+ self.start_pos = y_pos
+ self.start_time = time.time()
+ self.last_update_time = time.time()
+
+ def __on_mouse_up(self, edje_obj, emission, source, data=None):
+ if self.mouse_down:
+ self.mouse_down = False
+
+ x_pos, end_pos = self.canvas.pointer_canvas_xy
+
+ if not self.mouse_moved and not self.is_scrolling:
+ #self.__on_mouse_clicked(edje_obj, emission, source)
+ return
+
+ self.mouse_moved = False
+ self.is_scrolling = False
+
+ # do not scroll automatically if the finger was paused
+ if time.time() - self.last_update_time > 0.1:
+ return
+
+ end_time = time.time()
+
+ pos_diff = end_pos - self.start_pos
+ time_diff = end_time - self.start_time
+
+ self.pixel_per_sec = pos_diff / time_diff
+ self.continue_scrolling = True
+ self.__do_scroll()
+
+ def __do_scroll(self):
+ self.is_scrolling = True
+
+ if self.continue_scrolling == False:
+ return
+
+ diff = int(self.pixel_per_sec / 10)
+
+ if abs(self.pixel_per_sec) - diff <= self.row_height:
+ offset = self.top_pos % self.row_height
+
+ if offset >= self.row_height / 2:
+ self.sign = 1
+ offset = self.row_height - offset
+ else:
+ self.sign = -1
+
+ self.pixels_left = offset
+ self.__do_magnetic_scroll()
+
+ return
+
+ if diff != 0:
+ self.top_pos -= diff
+ self.pixel_per_sec -= self.pixel_per_sec / 10
+ self.__update_screen()
+
+ ecore.timer_add(0.02, self.__do_scroll)
+
+ def __do_magnetic_scroll(self):
+ if self.pixels_left <= 0 or abs(self.pixel_per_sec) < 1:
+ self.mouse_moved = False
+ self.is_scrolling = False
+ return
+
+ self.pixel_per_sec -= (self.pixel_per_sec / 10)
+
+ pixels_to_substract = int(abs(self.pixel_per_sec / 10))
+ if abs(pixels_to_substract) < 1:
+ pixels_to_substract = 1
+
+ if self.pixels_left - pixels_to_substract > 0:
+ self.pixels_left -= pixels_to_substract
+ self.top_pos += self.sign * pixels_to_substract
+ else:
+ self.top_pos += self.sign * self.pixels_left
+ self.pixels_left = 0
+
+ self.__update_screen()
+ ecore.timer_add(0.1, self.__do_magnetic_scroll)
+
+ def row_add(self, label):
+ self.elements.append(label)
+
+ if not self.do_freeze:
+ self.__update_variables_after_new_elements()
+ self.__update_screen()
+
+ def __manage_objects(self):
+ remain = (self.h % self.row_height) > 1
+ needed_objects = ((self.h / self.row_height) + 1 + remain) * (self.w / self.row_width)
+ current_objects = len(self.objects)
+
+ if current_objects < needed_objects:
+ for i in range(current_objects, needed_objects):
+ obj = edje.Edje(self.canvas);
+ obj.file_set(self.edje_file, "list_item");
+
+ obj.signal_callback_add("mouse,move", "*",
+ self.__on_mouse_move)
+ obj.signal_callback_add("mouse,down,*", "*",
+ self.__on_mouse_down)
+ obj.signal_callback_add("mouse,up,*", "*",
+ self.__on_mouse_up)
+ #TODO: portela mod
+ obj.signal_callback_add("animation_blink_ended", "label",
+ self.__on_blink_ended)
+ obj.signal_callback_add("mouse,clicked,*", "label",
+ self.__on_mouse_clicked)
+ obj.size = (self.row_width, self.row_height)
+ obj.clip = self
+ self.objects.append(obj)
+
+ elif needed_objects < current_objects:
+ for i in range(needed_objects, current_objects):
+ pass # Make this work, it throws exception that makes
+ # things stop working properly
+ #del self.objects[i]
+
+ def __update_variables_after_resize(self):
+ self.max_visible_rows = (self.h / self.row_height) + 1
+ self.max_horiz_elements = (self.w / self.row_width)
+ self.max_visible_elements = self.max_visible_rows * \
+ self.max_horiz_elements
+
+ # Invalidate variable in order to repaint all rows
+ # Some might not have been painted before (Didn't
+ # fit on the screen
+ self.last_start_row = -1
+
+ self.__update_variables_after_new_elements()
+
+ def __update_variables_after_new_elements(self):
+ if not self.realized:
+ return
+
+ self.min_pos = 0
+ remainer1 = (len(self.elements) % self.max_horiz_elements) > 0
+ remainer2 = (self.h % self.row_height) > 0
+ self.row_amount = (len(self.elements) / self.max_horiz_elements) + \
+ remainer1 + remainer2
+ self.max_pos = self.row_height * \
+ (self.row_amount - self.max_visible_rows + 1)
+
+ def __update_screen(self):
+ remainer = (self.h % self.row_height) > 0
+ row_offset = (self.top_pos / self.row_height)
+ pixel_offset = - (self.top_pos % self.row_height)
+ start_row = row_offset
+ end_row = self.max_visible_rows + row_offset + remainer
+
+ SCROLL_DOWN = self.top_pos > self.last_top_pos
+ SCROLL_UP = self.top_pos < self.last_top_pos
+
+ # Let's not move over the last element
+ if SCROLL_DOWN and self.last_top_pos >= self.max_pos:
+ self.top_pos = self.max_pos
+ self.last_top_pos = self.top_pos
+ self.continue_scrolling = False
+ return
+
+ # Let's not move over the first element
+ if SCROLL_UP and self.last_top_pos <= self.min_pos:
+ self.top_pos = self.min_pos
+ self.last_top_pos = self.top_pos
+ self.continue_scrolling = False
+ return
+
+ # Overflow scrolling down
+ if SCROLL_DOWN and end_row > self.row_amount:
+ offset = end_row - self.row_amount
+ end_row -= offset
+ start_row -= offset
+ row_offset -= offset - 1
+ self.top_pos = self.max_pos
+ pixel_offset = 0
+
+ # Overflow scrolling up
+ if SCROLL_UP and start_row < 0:
+ self.top_pos = self.min_pos
+ end_row -= start_row
+ start_row = 0
+ row_offset = 0
+ pixel_offset = 0
+
+ self.last_top_pos = self.top_pos
+
+ if start_row != self.last_start_row:
+ for i in range(0, len(self.objects)):
+ self.objects[i].hide()
+
+ for i in range(start_row, end_row):
+ row_iter = i - start_row
+
+ for k in range(self.max_horiz_elements):
+ obj_iter = row_iter * self.max_horiz_elements + k
+ data_iter = i * self.max_horiz_elements + k
+
+ try:
+ label = self.elements[data_iter]
+ except Exception, e:
+ break;
+
+ offset = (self.w %
+ (self.row_width * self.max_horiz_elements)) / 2
+ x = self.row_width * k + self.top_left[0] + offset
+ y = self.top_left[1] + self.row_height * (i - row_offset) - \
+ 5 + pixel_offset
+
+ self.objects[obj_iter].move(x, y)
+
+ if start_row != self.last_start_row:
+ self.objects[obj_iter].part_text_set("label", label)
+ self.objects[obj_iter].show()
+
+ self.last_start_row = start_row
+
+ def resize(self, w, h):
+ if self.row_width == -1 or self.row_width == self.w:
+ self.row_width = w
+
+ if self.row_height == -1 or self.row_height == self.h:
+ self.row_height = h
+
+ self.w = w
+ self.h = h
+
+ self.__manage_objects()
+
+ for obj in self.objects:
+ obj.size = (self.row_width, self.row_height)
+
+ self.realized = True
+ self.__update_variables_after_resize()
+ self.__update_screen()
--- /dev/null
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+# ****************************************************************************
+# Copyright (c) 2008 Zagaia - INdT/Fucapi.
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Lesser General Public License as published by
+# the Free Software Foundation, either version 3 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 Lesser General Public License for more details.
+
+# You should have received a copy of the GNU Lesser General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+# ============================================================================
+# Project Name :PC Remote
+# Author :Andre Portela
+# Email :andre_portela_@hotmail.com
+# Version :1.0
+# Module :main
+# Class :PCRemote custom Edje object with it's own call backs for the
+# main screen
+# ============================================================================
+
+from ecore import main_loop_begin
+import ecore.evas
+import sys
+import os
+from edje_objects import *
+from connection.iconnection import Iconnection
+from screenmanager import ScreenManager
+
+width, height = 800, 480
+
+#any argument deactivates fullscreen
+if sys.argv.__len__() > 1:
+ screen = False
+else:
+ screen = True
+#if x11_16 is present, get it, otherwise get x11
+if ecore.evas.engine_type_supported_get("software_x11_16"):
+ engine = ecore.evas.SoftwareX11_16
+else:
+ engine = ecore.evas.SoftwareX11
+#create the evas canvas
+canvas = EvasCanvas(fullscreen=screen,engine=engine,size=(width, height))
+#main .edj path
+edje_file = os.path.join(os.path.dirname(sys.argv[0]), "pcremote.edj")
+#the bluetooth socket object shared by all screens
+sock = Iconnection('bluetooth')
+#main edje object
+main = MainScreen(canvas=canvas, file=edje_file, group="Main",name="Main", connection = sock)
+main.show()
+#future edje objects
+tablet, slide, player, torrent = None, None, None, None
+#focus on main edje object
+main.focus = True
+#this object connects all screens together
+manager = ScreenManager(main, tablet, slide, player, torrent, sock)
+
+ecore.main_loop_begin()
+
--- /dev/null
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+# ****************************************************************************
+# Copyright (c) 2008 INdT/Fucapi.
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Lesser General Public License as published by
+# the Free Software Foundation, either version 3 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 Lesser General Public License for more details.
+
+# You should have received a copy of the GNU Lesser General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+# ============================================================================
+# Project Name :PC Remote
+# Author :André Portela
+# Email :andre_portela_@hotmail.com
+# Version :1.0
+# Module :main
+# Class :PCRemote ScreenManager handles the finite state machine which
+# controls the navigation between screens.
+# ============================================================================
+
+from edje_objects import *
+import os
+import sys
+
+class ScreenManager(object):
+ '''
+ classdocs
+ '''
+ def __init__(self, main, tablet, slide, player, torrent,socket):
+ '''
+ Constructor
+ '''
+ self.main = main
+ self.tablet = tablet
+ self.slide = slide
+ self.player = player
+ self.torrent = torrent
+ self.sock = socket
+ main.signal_callback_add("mouse,up,1", "Tablet",self.run_tablet)
+ main.signal_callback_add("mouse,up,1", "Slideshow",self.run_slide)
+ main.signal_callback_add("mouse,up,1", "Player",self.run_player)
+ main.signal_callback_add("mouse,up,1", "Torrent",self.run_torrent)
+
+ def run_tablet(self, edje, emission, source):
+ self.sock.send_message(source+":#start")
+ print 'entrou no tablet'
+ #main edje object
+ edje.focus_set(False)
+ edje.hide()
+ if self.tablet is None:
+ edje_file = os.path.join(os.path.dirname(sys.argv[0]), "tablet.edj")
+ self.tablet = TabletScreen(edje.canvas_class, edje_file, 'main', 'tablet', self.sock)
+ self.tablet.signal_callback_add("mouse,up,1","tablet_bt-voltar_area",self.tablet_back)
+ self.tablet.part_text_set('pc_name',edje.sock_address)
+ self.tablet.show()
+ self.tablet.focus_set(True)
+
+ def tablet_back(self, edje, emission, source):
+ #tablet edje object
+ edje.focus_set(False)
+ edje.hide()
+ self.sock.send_message("Tablet:#stop")
+ self.main.show()
+ self.main.focus_set(True)
+
+ def run_slide(self, edje, emission, source):
+ self.sock.send_message(source+":#start")
+ print 'entrou no slide'
+ #main edje object
+ edje.focus_set(False)
+ edje.hide()
+ if self.slide is None:
+ edje_file = os.path.join(os.path.dirname(sys.argv[0]), "slide.edj")
+ self.slide = SlideScreen(edje.canvas_class, edje_file, 'main', 'slide', self.sock)
+ self.slide.signal_callback_add("unselected","slide_bt-voltar",self.slide_back)
+ #self.slide.part_text_set('pc_name',edje.sock_address)
+ #this rotates the screen 90 degrees (to fit text in vertical orientation)
+ #self.slide.x11.rotation_set(90)
+ self.slide.show()
+ self.slide.focus_set(True)
+
+ def slide_back(self, edje, emission, source):
+ #slide edje object
+ edje.focus_set(False)
+ edje.hide()
+ self.sock.send_message("Slideshow:#stop")
+ #this rotates the screen from 90 to 0 degrees (to fit text in horizontal orientation again)
+ #self.main.x11.rotation_set(0)
+ self.main.show()
+ self.main.focus_set(True)
+
+ def run_player(self, edje, emission, source):
+ print 'not implemented yet'
+
+ def player_back(self, edje, emission, source):
+ print 'not implemented yet'
+
+ def run_torrent(self, edje, emission, source):
+ print 'not implemented yet'
+
+ def torrent_back(self, edje, emission, source):
+ print 'not implemented yet'
+
--- /dev/null
+# -*- coding: utf-8 -*-
+
+# ****************************************************************************
+# Copyright (c) 2008 INdT/Fucapi.
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Lesser General Public License as published by
+# the Free Software Foundation, either version 3 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 Lesser General Public License for more details.
+
+# You should have received a copy of the GNU Lesser General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+# ============================================================================
+# Project Name : PC Remote
+# Author : Jônatas Isvi
+# Email : jonatas.nona@gmail.com
+# Version : 1.0
+# Description : Labels
+# ============================================================================
+
+
+# GENERIC LABELS FOR MULTIMEDIA APPLICATIONS
+
+PLAY = "#play"
+STOP = "#stop"
+PAUSE = "#pause"
+NEXT = "#next"
+PREVIOUS = "#previous"
+VOL_UP = "#vol_up"
+VOL_DOWN = "#vol_down"
+TLINE_LEFT = "#tline_left"
+TLINE_RIGHT = "#tline_right"
+RECORD = "#record"
+#------------------------------------------>
+
+# GENERIC LABELS FOR APPLICATIONS
+
+START = "#start"
+CLOSE = "#close"
+FULL = "#fullscreen"
+UPLOAD = "#upload"
+DOWNLOAD = "#download"
+SAVE = "#save"
+DELETE = "#delete"
+#-------------------------------->
+
+# GENERAL MOUSE LABELS
+
+CLICK = "#click"
+DOUBLE_CLICK = "#double_click"
+TRIPLE_CLICK = "#triple_click"
+LEFT_CLICK = "#left_click"
+RIGHT_CLICK = "#right_click"
+MIDDLE_CLICK = "#middle_click"
+#-------------------------------->
+
+