#!/usr/bin/python # # wiicontrol: Control your Internet Tablet from your wiimote # (c) 2008 Jose Luis Diaz # # 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 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 General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . # ================================================================ # Configurable part (see README) wiimote_mac='00:1C:BE:11:8D:FC' # Use your own MAC. Get it with discover.py import dbus import dbus.glib import gobject import time import gtk import sys import string import os import hildon import osso from threading import Thread from time import sleep import sys global mapping, pressed, mapping_b, Wii, device, buttonmap mapping_gnurobbo = { 'U': ["a Left"], 'D': ["a Right"], 'L': ["a Down"], 'R': ["a Up"], 'A': ["k Return"], '+': ["k F7"], # Zoom/volume + '-': ["k F8"], # Zoom/volume - '1': ["a 1"], # Modifier 1 '2': ["a 2"], # Modifier 2 (shooting) 'H': ["k Return"], # Home button is broken. Do not use it 'GU': ["a Left"], 'GD': ["a Right"], 'GL': ["a Down"], 'GR': ["a Up"] } # Some useful key names: # Up, Down, Left, Right (D-pad) # Return (this is also the central button of the D-pad) # Escape # F6 (Fullscreen key) # F7 (Zoom/volume -) # F8 (Zoom/volume +) # F4 (Menu key) mapping_p={ 'U': ["k Up"], 'D': ["k Down"], 'L': ["k Left"], 'R': ["k Right"], 'A': ["k Return"], '+': ["k F7"], # Zoom/volume + '-': ["k F8"], # Zoom/volume - '1': ["k F4"], # Application Menu '2': ["t 25 25"], # Main desktop menu 'H': ["k Return"], # Home button is broken. Do not use it 'GU': ["a Up"], 'GD': ["a Down"], 'GL': ["a Left"], 'GR': ["a Right"] } mapping={ 'U': ["a Left"], 'D': ["a Right"], 'L': ["a Down"], 'R': ["a Up"], 'A': ["k F4"], # Application menu '+': ["k F7"], # Zoom/volume + '-': ["k F8"], # Zoom/volume - '1': ["a space"], '2': ["a Return"], 'H': ["k Return"], # Home button is broken. Do not use it 'GU': ["a Up"], 'GD': ["a Down"], 'GL': ["a Left"], 'GR': ["a Right"] } mapping_l={ 'U': ["a Left"], 'D': ["a Right"], 'L': ["a Down"], 'R': ["a Up"], 'A': ["k F4"], # Application menu '+': ["k F7"], # Zoom/volume + '-': ["k F8"], # Zoom/volume - '1': ["a space"], '2': ["a Return"], 'H': ["k Return"], # Home button is broken. Do not use it 'GU': ["a w"], 'GD': ["a s"], 'GL': ["a a"], 'GR': ["a d"] } mapping_snes={ 'U': ["a Left"], 'D': ["a Right"], 'L': ["a Down"], 'R': ["a Up"], 'A': ["k s"], # Application menu '+': ["k F7"], # Zoom/volume + '-': ["k F8"], # Zoom/volume - '1': ["a c"], '2': ["a d"], 'H': ["k Return"], # Home button is broken. Do not use it 'GU': ["a w"], 'GD': ["a s"], 'GL': ["a a"], 'GR': ["a d"] } pressed={ 'U': [False], 'D': [False], 'L': [False], 'R': [False], 'A': [False], '+': [False], '-': [False], '1': [False], '2': [False], 'H': [False], # Home button is broken. Do not use it 'GU': [False], 'GD': [False], 'GL': [False], 'GR': [False] } mapping_b={ 'U': ["k F6"], # Fullscreen 'D': ["t 770 25"], # Tap on close window icon 'L': ["k Escape"], # Escape key 'R': ["t 45 450"], # Tap on window-list icon 'A': ["t 25 25", "s 3", "t 25 25"], '+': ["k F6"], # Fullscreen '-': ["t 770 25"], # Tap on close window icon '1': ["a 1"], '2': ["a 2"], 'H': ["k Return"], # Home button is broken. Do not use it 'GU': ["a Up"], 'GD': ["a Down"], 'GL': ["a Left"], 'GR': ["a Right"] } #Make sure BT is open command="dbus-send --system --type=method_call --dest=org.bluez /org/bluez/hci0 org.bluez.Adapter.SetMode string:discoverable" os.system(command) forceEnabled=False class wiicontrolGUI(hildon.Program): def __init__(self): hildon.Program.__init__(self) self.saveOn=True self.window = hildon.Window() self.window.connect("destroy", gtk.main_quit) self.add_window(self.window) self.connect_button1 = gtk.Button("Gamepad mode") self.connect_button1.connect("clicked", self.setLandscape) self.connect_button2 = gtk.Button("Browser mode") self.connect_button2.connect("clicked", self.setPortrait) self.connect_button4 = gtk.Button("SNES") self.connect_button4.connect("clicked", self.setSnes) self.connect_button3 = gtk.Button("Gamepad + Gyro") self.connect_button3.connect("clicked", self.setLandscapeGyro) self.connect_button5 = gtk.Button("GNURobbo") self.connect_button5.connect("clicked", self.setGNURobbo) vbox = gtk.VBox(False, 0) self.window.add(vbox) vbox.show() hbox = gtk.HBox(False, 0) hbox2 = gtk.HBox(False, 0) hbox3 = gtk.HBox(False, 0) self.image = gtk.Image() #self.image.set_from_file("/tmp/f27.jpg") self.image.show() self.label = gtk.Label("Press 1+2 on your wiimote now.") vbox.pack_start(self.label, True, True, 0) self.label.show() vbox.pack_start(hbox) hbox.show() hbox.pack_start(self.connect_button1, True, True, 0) hbox.pack_start(self.connect_button2, True, True, 0) hbox.pack_start(self.connect_button4, True, True, 0) hbox.pack_start(self.connect_button3, True, True, 0) hbox.pack_start(self.connect_button5, True, True, 0) self.connect_button1.show() self.connect_button2.show() self.connect_button3.show() self.connect_button4.show() self.connect_button5.show() self.window.show_all() while gtk.events_pending(): gtk.main_iteration() while gtk.events_pending(): gtk.main_iteration() #gtk.main() #We won't start the mainloop yet here.... Maybe later on. def setLandscape(self, widget): global mapping, mapping_l print "setLandscape" mapping=mapping_l signalUser('Landscape using mapping_l') def setLandscapeGyro(self, widget): global mapping, mapping_l, forceEnabled, Wii print "setLandscape Gyro" mapping=mapping_l if not forceEnabled: forceEnabled=True Wii.enable_force() signalUser('Gyros up and running! Landscape using mapping_l ') def setPortrait(self, widget): global mapping, mapping_p print "setPortrait" mapping=mapping_p signalUser('Portrait using mapping_p') def setSnes(self, widget): global mapping, mapping_snes print "setPortrait" mapping=mapping_snes signalUser('Portrait using mapping_snes') def setGNURobbo(self, widget): global mapping, mapping_snes print "setGNURobbo" mapping = mapping_gnurobbo signalUser('GNURobbo') class keyEventThread(Thread): def __init__ (self): Thread.__init__(self) def handleForces(self, False, xpon, ypon, xnon, ynon): print "..." def run(self): global mapping, pressed, mapping_b, Wii, device, buttonmap buttons='+UDLRH-A12' self.Stop=False xpon=False ypon=False xnon=False ynon=False gyroTime=time.time() TOLERANCE=6 try: while not Wii.done and not self.Stop: Wii._getpacket() if forceEnabled and time.time()-gyroTime>0.10: gyroTime=time.time() #print Wii.force_str() gx=Wii.force_gx() gy=Wii.force_gy() if gx>90: gx=gx-128 if gy>90: gy=gy-128 #print str(gx)+ " " + str(gy) #X is positive if gx > TOLERANCE and not xpon: xpon = True ExecuteScript(mapping["GU"]) if xpon and gx < TOLERANCE and gx > -TOLERANCE: xpon = False ExecuteReleasedScript(mapping["GU"]) #X is negative if gx < -TOLERANCE and not xnon: xnon = True ExecuteScript(mapping["GD"]) if xnon and gx < TOLERANCE and gx > -TOLERANCE: xnon = False ExecuteReleasedScript(mapping["GD"]) #Y is positive if gy > TOLERANCE and not ypon: ypon = True ExecuteScript(mapping["GL"]) if ypon and gy < TOLERANCE and gy > -TOLERANCE: ypon = False ExecuteReleasedScript(mapping["GL"]) #Y is negative if gy < -TOLERANCE and not ynon: ynon = True ExecuteScript(mapping["GR"]) if ynon and gy < TOLERANCE and gy > -TOLERANCE: ynon = False ExecuteReleasedScript(mapping["GR"]) for bb in buttons: if (Wii.buttonmask & buttonmap[bb]): if (Wii.buttonmask & buttonmap["B"]): ExecuteScript(mapping_b[bb]) pressed[bb]=True else: ExecuteScript(mapping[bb]) pressed[bb]=True elif (not (Wii.buttonmask & buttonmap[bb])): if pressed[bb]==True: pressed[bb]=False ExecuteReleasedScript(mapping[bb]) device.display_state_on() print "Did you turn off the wiimote?" finally: Wii.disconnect() print "Wiimote connection closed" def signalUser(usertext): global app app.label.set_text(usertext) while gtk.events_pending(): gtk.main_iteration() print usertext def disc_started_signal(): signalUser('Press 1+2 in your wiimote and wait a moment') def rem_dev_found_signal(address, cls, rssi): pass def rem_dev_name_signal(address, name): global wiimote_mac print '%20s => %s' % (name, address) if name.find("Nintendo")>-1: signalUser( "NINTENDO WIIMOTE FOUND AT: " + address) wiimote_mac=address main_loop.quit() def disc_completed_signal(): print "No more bluetooth devices found" main_loop.quit() def do_Discovery(): bus = dbus.SystemBus() bus.add_signal_receiver(disc_started_signal, 'DiscoveryStarted', 'org.bluez.Adapter', 'org.bluez', '/org/bluez/hci0') bus.add_signal_receiver(rem_dev_found_signal, 'RemoteDeviceFound', 'org.bluez.Adapter', 'org.bluez', '/org/bluez/hci0') bus.add_signal_receiver(rem_dev_name_signal, 'RemoteNameUpdated', 'org.bluez.Adapter', 'org.bluez', '/org/bluez/hci0') bus.add_signal_receiver(disc_completed_signal, 'DiscoveryCompleted', 'org.bluez.Adapter', 'org.bluez', '/org/bluez/hci0') obj = bus.get_object('org.bluez', '/org/bluez/hci0') adapter = dbus.Interface(obj, 'org.bluez.Adapter') adapter.DiscoverDevices() gobject.threads_init() dbus.glib.init_threads() #Setting GUI and discovery app = wiicontrolGUI() do_Discovery() main_loop = gobject.MainLoop() main_loop.run() signalUser( "Locked to mote:"+wiimote_mac) # Use Wiimote module (from pyaxelwii project) from Wiimote import Wiimote, buttonmap # To generate X-window events, we use XTest library # Use XTest extensions, by directly loading the shared library from ctypes import CDLL Xtst = CDLL("libXtst.so.6") Xlib = CDLL("libX11.so.6") # Get the current display d = Xtst.XOpenDisplay(None) # Generate a keypress, given the keyname. def SendKey(key): sym = Xlib.XStringToKeysym(key) code = Xlib.XKeysymToKeycode(d, sym) Xtst.XTestFakeKeyEvent(d, code, True, 0) Xtst.XTestFakeKeyEvent(d, code, False, 0) Xlib.XFlush(d) def SendKeyDown(key): sym = Xlib.XStringToKeysym(key) code = Xlib.XKeysymToKeycode(d, sym) Xtst.XTestFakeKeyEvent(d, code, True, 0) Xlib.XFlush(d) def SendKeyUp(key): sym = Xlib.XStringToKeysym(key) code = Xlib.XKeysymToKeycode(d, sym) Xtst.XTestFakeKeyEvent(d, code, False, 0) Xlib.XFlush(d) def SendCtrlKey(key): SendKeyDown("Control_R") SendKey(key) SendKeyUp("Control_R") # Move the mouse to the given (absolute) coordinates def MouseMove(x, y): Xtst.XTestFakeMotionEvent(d, -1, x, y, 0); Xlib.XFlush(d) def MouseMoveRelative(x, y): Xtst.XTestFakeRelativeMotionEvent(d, -1, x, y, 0); Xlib.XFlush(d) # Click a mouse button (1:left, 2:right) def MouseClick(button): Xtst.XTestFakeButtonEvent( d, button, True, 0 ); Xtst.XTestFakeButtonEvent( d, button, False, 0 ); Xlib.XFlush(d) def StylusTap(x, y): Xtst.XTestFakeMotionEvent(d, -1, x, y, 0) Xtst.XTestFakeButtonEvent(d, 1, True, 0 ); Xtst.XTestFakeButtonEvent(d, 1, False, 0 ); Xlib.XFlush(d) # Given a list of strings, each one being a valid command, execute the script # Valid commands are: # "k name" -> Sendkey(name) # "m x y" -> MouseMove(x,y) # "b button" -> MouseClick(button) # "t x y" -> StylusTap(x,y) # "s time" -> sleep(time) def ExecuteScript(script): for c in script: cmd=c.split() if cmd[0]=='k': aux=cmd[1].split('-') if len(aux)==1: SendKey(cmd[1]) else: SendCtrlKey(aux[1]) elif cmd[0]=='a': SendKeyDown(cmd[1]) elif cmd[0]=='b': MouseClick(int(cmd[1])) elif cmd[0]=='m': MouseMove(int(cmd[1]), int(cmd[2])) elif cmd[0]=='r': MouseMoveRelative(int(cmd[1]), int(cmd[2])) elif cmd[0]=='t': StylusTap(int(cmd[1]), int(cmd[2])) elif cmd[0]=='s': sleep(float(cmd[1])) else: break def ExecuteReleasedScript(script): for c in script: cmd=c.split() if cmd[0]=='a': SendKeyUp(cmd[1]) else: break # Use osso library to activate the screen backlit on wiimote button import osso osso_c=osso.Context("wiicontrol", "0.0.8", False) device=osso.DeviceState(osso_c) Wii=Wiimote(wiimote_mac,0) print 'Press 1+2 in your wiimote' Wii.connect() signalUser( 'Wiimote connected. Have fun!') eventThread=keyEventThread() eventThread.start() gtk.main() Wii.disconnect() #Just making sure eventThread.Stop=True