Physical Interaction with Digital Interfaces.

At the last evening of us flash geeks getting together at the monthly London Flash Platform User Group little over a week ago, Adam Robertson and Leif Løvgreen displayed some really inspiring stuff. Adam, of FWiidom, focussed on the WiiMote - Nintendo's Wii motion sensing controller - and how to make it work with flash on both PC and Wii, complete with an overview of what's supported and some tips on best APIs ( WiiFlash, GlovePie and Flosc )out there. Leif showed some really cool sensory input being converted into some lovely and interactive flash output using the makingthings kit.

I couldn't help myself and, with my bluetooth enabled little laptop, I decided to go out and get myself a WiiMote controller to try some of this stuff out for myself. After a little confusion at first on how to connect the WiiMote to the laptop, - I couldn't get it to work on my office-laptop with Belkin bluetooth dongle without installing the BlueSoleil drivers, so resorted to my personal laptop which worked without too much hassle -, I got it to work with GlovePie. The WiiFlash server doesn't work for me yet, so I'll have to do a little more fiddling with that before I can used 'the preferred' solution.

I'm also still without Flash CS3, so no AS3 for me yet.. So I just started playing with some of the GlovePIE scripts to control my laptop with the WiiMote for now, and I have to say, it's a lot of fun! GlovePIE's scripting language is a bit odd at first, very forgiving, but after reading through the documentation it started to make more sense.

I've started with reading through some of the scripts and shortly after, combining them - rewriting most of the code them so they're more consistent with ECMA, making them just that bit more sensible - and adding my own bits to make the controller do what I want it too. There's a few bugs in it still - just some keyboard keys that can't be unset -, but it works quite nicely, displaying the batterylevel, and 3 different modes for mouse emulation, media controls and presentation (powerpoint) controls.

I'm looking forward to start integrating the Flosc bit, and writing some AS2 code to connect - if anybody has a nice few AS2 Flosc classes, I'm happy to hear from you -.

Other things I'd like to look into are the Lego Mindstorms NXT sensors and the 3dconnexion space navigator..

Anyway, if you have GlovePIE, a WiiMote and a compatible bluetooth enabled PC, give this script try...

PIE Script:
  1. // customized from MouseAccel.PIE
  2. // 3 modes (4th browser mode todo)
  3.    // 1. mouse mode, for moving the mouse around the screen,
  4.    // with left, right buttons, scroll and cursor control
  5.    // 2. presentation mode, for controlling powerpoint
  6.    // open slideshow, click through slides, pen control, quick slide menu
  7.    // note: ctrl button is buggy, fix with clicking ctrl on the keyboard
  8.    // 3. media mode, for controlling media devices
  9.    // play/pause, prev and next, volume and mute support
  10. // voice confirmation of the selected mode
  11. // visual feedback through leds
  12. // batterylevel indication
  13.  
  14. // initiate script
  15.  
  16. if (var.inited == false){
  17.    var.inited = true;
  18.    //precision settings for mouse movement
  19.    var.sense0 = 500
  20.    var.thresh0x = 5
  21.    var.thresh0y = 2
  22.    var.sense1 = 300
  23.    var.thresh1x = 10
  24.    var.thresh1y = 5
  25.    var.sense2 = 100
  26.    var.thresh2x = 15
  27.    var.thresh2y = 8
  28.    var.sense3 = 50
  29.    var.thresh3x = 20
  30.    var.thresh3y = 12
  31.    // default delays for
  32.    var.longInterval = 200 ms;
  33.    var.shortInterval = 50 ms;
  34.    // wait for PIE to find WiiMote orientation
  35.    wait(var.longInterval);
  36.    // set initial zero point
  37.    var.initx = WiiMote.RawForceX;
  38.    var.inity = WiiMote.RawForceY;
  39.    var.initz = WiiMote.RawForceZ;
  40.    // wii control modes
  41.    var.mouseMode_id = 1;
  42.    var.mouseMode_say = "mouse";
  43.    var.pptMode_id = 2;
  44.    var.pptMode_say = "presentayshun";
  45.    var.penEnabled= false;
  46.    var.mediaMode_id = 3;
  47.    var.mediaMode_say = "media";
  48.    // todo
  49.    //var.browsemode = 4
  50.    //var.browsemodestr = "browser"
  51.    var.numModes = 3;
  52.    var.mode_say = " mode";
  53.    //set mouseMode_id as default
  54.    var.wiiMode_id = var.mouseMode_id;
  55.    WiiMote.leds = (2^var.wiiMode_id) - (2^(var.wiiMode_id-1));
  56.    var.wiiMode_say = var.mouseMode_say;
  57.    say var.wiiMode_say + var.mode_say;
  58.    var.showBatteryLevel = false;
  59.    wait(1000 ms);
  60.    var.showBatteryLevel = true;
  61. }
  62.  
  63. // switch control mode by pressing the home key
  64. if (pressed(WiiMote.Home)){
  65.  
  66.    var.showBatteryLevel = false;
  67.    // select next mode id
  68.    var.tmode = var.wiiMode_id + 1;
  69.  
  70.    if (var.tmode> var.numModes){
  71.       var.tmode = 1;
  72.    }
  73.  
  74.    //rumble to give feedback on change mode
  75.    WiiMote.Rumble= true;
  76.    wait(var.shortInterval);
  77.    WiiMote.Rumble= false;
  78.    var.wiiMode_id = var.tmode;
  79.    //light the led indicating the selected mode
  80.    var.led_id = (2^var.wiiMode_id) - (2^(var.wiiMode_id-1));
  81.    WiiMote.leds = var.led_id;
  82.  
  83.    //select the string to say
  84.    if(var.wiiMode_id == var.mouseMode_id){
  85.       var.wiiMode_say = var.mouseMode_say;
  86.    } else if(var.wiiMode_id == var.pptMode_id){
  87.       var.wiiMode_say = var.pptMode_say  ;
  88.    }else if(var.wiiMode_id == var.mediaMode_id){
  89.       var.wiiMode_say = var.mediaMode_say;
  90.    }else if(var.wiiMode_id == var.browsemode){
  91.       var.wiiMode_say = var.browsemodestr;
  92.    }
  93.  
  94.    //say the current mode
  95.    say(var.wiiMode_say + var.mode_say);
  96.    wait(1000 ms);
  97.    var.showBatteryLevel = true;
  98. }
  99.  
  100. // default key mapping for up, down, left, right
  101. if (WiiMote.Up){
  102.    Key.Up = true;
  103.    wait(var.longInterval);
  104.    Key.Up = false;
  105. } else if (WiiMote.Down){
  106.    Key.Down = true;
  107.    wait(var.longInterval);
  108.    Key.Down = false;
  109. }
  110.  
  111. if (WiiMote.Left){
  112.    Key.Left = true;
  113.    wait(var.longInterval);
  114.    Key.Left = false;
  115. } else if (WiiMote.Right){
  116.    Key.Right = true;
  117.    wait(var.longInterval);
  118.    Key.Right = false;
  119. }
  120.  
  121. // assign custom actions for each mode
  122. if (var.wiiMode_id == var.mouseMode_id){
  123.    // mouse mode
  124.    if (pressed(WiiMote.A)){
  125.       Mouse.LeftButton = true;
  126.       wait(var.longInterval);
  127.       Mouse.LeftButton = false;
  128.    }
  129.  
  130.    if (WiiMote.B){
  131.       var.mouseMoveEnabled = true;
  132.    }else{
  133.       var.mouseMoveEnabled = false;
  134.    }
  135.  
  136.    if (pressed(WiiMote.Minus)) {
  137.       Key.Enter = true;
  138.       wait(var.longInterval);
  139.       Key.Enter = false;
  140.    }
  141.  
  142.    if (pressed(WiiMote.Plus)){
  143.       Mouse.RightButton = true;
  144.       wait(var.longInterval);
  145.       Mouse.RightButton = false;
  146.    }
  147.  
  148.    Mouse.WheelUp = WiiMote.One
  149.  
  150.    Mouse.WheelDown = WiiMote.Two
  151.  
  152. }else if (var.wiiMode_id == var.pptMode_id){
  153.    //directional buttons:
  154.    //left & up to go back one slide
  155.    //right & down to go to the next slide and move trought the dialog window
  156.    // Press A to start the slide show &
  157.    // and to go to the next slide
  158.    if (WiiMote.A){
  159.       // press and hold B to move the mouse
  160.       if (WiiMote.B){
  161.           // A is left mouse button when in mouse mode
  162.           Mouse.LeftButton = true;
  163.           wait(var.longInterval);
  164.           Mouse.LeftButton = false;
  165.       }else {
  166.           // if the mouse is not moving, reassign A to the Enter Key
  167.           Key.Enter = true;
  168.           wait(var.longInterval);
  169.           Key.Enter = false;
  170.       }
  171.    }
  172.  
  173.    // press and hold B to move the mouse
  174.    if (WiiMote.B){
  175.       var.mouseMoveEnabled = true;
  176.    }else{
  177.       var.mouseMoveEnabled = false;
  178.    }
  179.  
  180.    // start slideshow / go to the first slide
  181.    if (pressed(WiiMote.Minus)) {
  182.       Key.Home = true;
  183.       Key.F5 = true;
  184.       wait(var.shortInterval);
  185.       Key.Home = false;
  186.       Key.F5 = false;
  187.    }
  188.  
  189.    // show contextmenu
  190.    if (pressed(WiiMote.Plus)){
  191.       Mouse.RightButton = true;
  192.       wait(var.shortInterval);
  193.       Mouse.RightButton = false;
  194.    }
  195.  
  196.    // press '1' to show the select slide dialog
  197.    // (press A to select)
  198.    if (WiiMote.One) {
  199.       Key.Ctrl = true;
  200.       Key.S = true;
  201.       wait(var.shortInterval);
  202.       Key.S = false;
  203.       Key.Ctrl = false; // ctrl doesn't get unset properly, so press ctrl if you experience problems while or after running thie PIE
  204.    }
  205.  
  206.    // switch penEnabled
  207.    if (WiiMote.Two)
  208.       if(var.penEnabled == false){
  209.          var.penEnabled = true;
  210.          Key.Ctrl = true;
  211.          Key.P = true;
  212.          wait(var.shortInterval);
  213.          Key.P = false;
  214.          Key.Ctrl = false;
  215.       }else if(var.penEnabled == true){
  216.          var.penEnabled = false;
  217.          Key.Ctrl = true;
  218.          Key.A = true;
  219.          wait(var.shortInterval);
  220.          Key.A = false;
  221.          Key.Ctrl = false// ctrl doesn't get unset properly, so press ctrl if you experience problems while or after running thie PIE
  222.       }
  223.    }
  224.  
  225.    wait(var.longInterval);
  226.    Key.Ctrl = false;
  227.  
  228. }else if (var.wiiMode_id == var.mediaMode_id){
  229.    //Plus and Minus handle Volume
  230.    if (WiiMote.One){
  231.       Key.VolumeUp = true;
  232.       wait(var.shortInterval);
  233.       Key.VolumeUp = false;
  234.    }
  235.  
  236.    if (WiiMote.Two){
  237.       Key.VolumeDown = true;
  238.       wait(var.shortInterval);
  239.       Key.VolumeDown = false;
  240.    }
  241.  
  242.    if (pressed(WiiMote.A)){
  243.       Key.PlayPause = true;
  244.       wait(var.longInterval);
  245.       Key.PlayPause = false;
  246.    }
  247.  
  248.    Key.Mute = WiiMote.B;
  249.    if (pressed(WiiMote.Minus)){
  250.       Key.Prevtrack = true;
  251.       wait(var.longInterval);
  252.       Key.Prevtrack = false;
  253.    }
  254.  
  255.    if (pressed(WiiMote.Plus)){
  256.       Key.NextTrack = true;
  257.       wait(var.longInterval);
  258.       Key.NextTrack = false;
  259.    }
  260. }
  261.  
  262. //If the mouse reaches the end, rumble for 200 milliseconds
  263. if (var.mouseX == 0 or var.mouseX == 1 or var.mouseY == 0 or var.mouseY == 1){
  264.    if (var.rmbl == false){
  265.       WiiMote.Rumble = true;
  266.       wait(var.longInterval);
  267.       WiiMote.Rumble = false;
  268.    }
  269.    var.rmbl = true;
  270. }else{
  271.    var.rmbl = false;
  272. }
  273.  
  274. // ##taken from WiiMouseAccel.PIE##
  275. // set these to the offsets when the WiiMote is at rest
  276. // will be different for each WiiMote most likely
  277. var.posX = WiiMote.RawForceX - var.initx //trim to 0
  278. var.posY = WiiMote.RawForceY - var.inity // trim to 0
  279. var.posZ = WiiMote.RawForceZ - var.initz //trim to 0
  280.  
  281. if (var.mouseMoveEnabled == true){
  282.       //first sensitivity setting
  283.       //xaxis
  284.       var.mouseX = Mouse.x;
  285.       var.mouseY = Mouse.y;
  286.       if (var.posX> var.thresh0x){
  287.          var.mouseX = var.mouseX - 1/var.sense0;
  288.       }else if (var.posX <-var.thresh0x){
  289.          var.mouseX = var.mouseX + 1/var.sense0;
  290.       }
  291.  
  292.       //yaxis
  293.       if (var.posZ> var.thresh0y){
  294.          var.mouseY = var.mouseY - 1/var.sense0;
  295.       }else if (var.posZ <-var.thresh0y){
  296.          var.mouseY = var.mouseY + 1/var.sense0;
  297.       }
  298.  
  299.       //second sensitivity setting
  300.       //xaxis
  301.       if (var.posX> var.thresh1x){
  302.          var.mouseX = var.mouseX - 1/var.sense1;
  303.       }else if (var.posX <-var.thresh1x){
  304.          var.mouseX = var.mouseX + 1/var.sense1;
  305.       }
  306.  
  307.       //yaxis
  308.       if (var.posZ> var.thresh1y) {
  309.          var.mouseY = var.mouseY - 1/var.sense1;
  310.       }else if (var.posZ <-var.thresh1y){
  311.          var.mouseY = var.mouseY + 1/var.sense1;
  312.       }
  313.  
  314.       //third sensitivity setting
  315.       //xaxis
  316.       if (var.posX> var.thresh2x){
  317.          var.mouseX = var.mouseX - 1/var.sense2;
  318.       }else if (var.posX <-var.thresh2x){
  319.          var.mouseX = var.mouseX + 1/var.sense2;
  320.       }
  321.  
  322.       //yaxis
  323.       if (var.posZ> var.thresh2y){
  324.          var.mouseY = var.mouseY - 1/var.sense2;
  325.       }else if (var.posZ <-var.thresh2y){
  326.          var.mouseY = var.mouseY + 1/var.sense2;
  327.       }
  328.  
  329.       //fourth sensitivity setting