Friday 28 January 2011

How to share a Bluetooth keyboard between Linux and Windows dual boots

I recently go myself the Microsoft Bluetooth Mobile Keyboard 6000. It is a really nice small little wireless keyboard (Bluetooth) with excellent tactile feel, which works in both Linux (Debian) and Windows.

However whenever I boot from Linux to Windows or back, I have to pair the keyboard again. This is rather inconvenient.

Just sharing the same Bluetooth pin between Windows and Linux is not sufficient. The keyboard and PC uses the pin to create a key. It is this key that is used to associate the keyboard with the PC.

For sharing to work, you need to copy this key from the one OS to the other. Here's how I did it.

.. a recent update: I wrote a small perl script: bluetoothkbkeys to help with this. It reads your registry, assuming windows drive is mounted under /c, /mnt/c, or mounted with ntfs-3g, and spits out the device ID and key if it finds it in the registry. The old steps are still listed below, and you still need to associate your keyboard under linux first, and then under windows, and then extract the key with the script:

eedesne:~/bin% ~/bin/bluetoothkbkeys 
* Trying to read file: /c/Windows/System32/config/SYSTEM as 'SYSTEM' registry.
* Seeing if this is the latest controlset...
* Latest controlset: CMI-CreateHive{xxxx}\ControlSet001 [2012-07-08T23:47:14Z]

/var/lib/bluetooth/xx:xx:xx:xx:xx:xx/linkkeys
        Bluetooth device: bb:bb:bb:bb:bb:bb key: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
Now, simply replace the key for bb:bb:bb:bb:bb:bb in /var/lib/bluetooth/xx:xx:xx:xx:xx:xx/linkkeys with the value found (displayed as XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX here).

As previously, I cannot guarantee any of this to work anywhere else, or even to work again. I cannot guarantee you won't lose data, completely corrupt your OS, etc. Use at your own risk.

* associate the device under Linux

I used blueman-manager, you may have other ways of doing this.

* Make a note of the device id

It should look something like this: 55:55:55:55:55:55 (with different hex numbers)

* Boot into, and associate the device with Windows

* Boot back into Linux, but do not associate the keyboard.

* Get the key from the Windows registry

I mounted my windows drive under /c, and exported the SYSTEM tree using the hivexml tool, which is part of the libhivex-bin package. It is probably safest to mount the windows drive read-only.

I found Windows to store the device id all in lower case, and without the colon characters between character pairs, so 555555555555.

  cd /c/Windows/System32/config
  hivexml SYSTEM | perl -ane 's/</\n</g; print' | grep -i 'key="555555555555"'
This should give you one or more lines similar to this:

  <value encoding="base64" key="555555555555" type="binary">XXXXXXXXXXXXXXXXXXXXXX==</value>
Where the 'XXXXXXXXXXXXXXXXXXXXXX==' part is your key base64 encoded.

* Decode and convert the key to hex

perl -MMIME::Base64 -e 'print unpack("H*", decode_base64("XXXXXXXXXXXXXXXXXXXXXX==")) . "\n";'
* Replace the Bluetooth key under Linux

The key should be stored under /var/lib/bluetooth/<host_id>/linkkeys

Just replace the key part with the hex format one you got from the registry. The key will be the same length, on a line staring with the keyboard's device id.

Restart bluetooth, and you should now have a working keyboard.

/etc/init.d/bluetooth restart
Also see: http://ubuntuforums.org/showthread.php?t=1479056

Tuesday 18 January 2011

doing CTRL-ALT-F1 from a script to adjust brighness

It is odd, but for some reason I have to swap terminals, using chvt to a text term,
to adjust brightness on my laptop.

So, what I have to do is: change to /dev/tty1, adjust brightness, change back into X.

I created a script called 'dim', and set sudo to allow it to be run without password
for me:

#!/bin/bash

if [ "x$1" == "x" ]
then
        cat /proc/acpi/video/PEGP/LCD/brightness
        exit;
fi

if [ "x$DISPLAY" != "x" ]
then
        chvt 1
fi

echo -n $1 > /proc/acpi/video/PEGP/LCD/brightness

if [ "x$DISPLAY" != "x" ]
then
        chvt 8
fi

Sunday 2 January 2011

Tuesday 14 September 2010

Converting from ogg to mp3 in Matroska (mkv) files

NB, this is very vague. Please do not just copy and paste, it probably won't work and will most likely cause you to lose the file you are working on. This is an example and you'll need
to alter it to your specific mkv file:


You'll need mkvtoolnix, and lame installed.

First, get information about the video file:

mkvinfo file.mkv

extract the video and audio files you want to convert:

mkvextract tracks 1:file.vid
mkvextract tracks 2:file.en.ogg

convert (just ogg to mp3 for me)

oggdec file.eng.ogg -R -b 16 -o - | lame -s 48 -b 16 -m s -x -r - -q 2 -b 128 file.eng.mp3

Merge back into the mkv container:


mkvmerge -o file.2.mkv file.vid file.eng.mp3

You can now check file.2.mkv to see if it works correct.

Tuesday 17 August 2010

Spread and Perl

If you are here, you have most likely run into the problem of message passing, or interprocess communications, of some form or another.

You want applications to be able to talk to each other ... without writing code that (should) scare you.

The Spread Toolkit is, to quote its homepage, an open source toolkit that provides a high performance messaging service that is resilient to faults across local and wide area networks

Now, that description is perhaps not buzzword, rad fuelled 'boom' sockets on steroids, but Spread has been around for a while, and Ubuntu and Debian comes with packages out of the box. Things I like.

Spread also has bindings for a host of languages, including C, Perl, Ruby and Python. So, as an alternative to 0mq, rabbitmq, etc, possibly requiring less commitment, it may be worth a look.

I'll go through running the daemon on Ubuntu, and a Perl script. It is dead simple, though the Perl Module documentation may obscure that a bit.

Install the Spread daemon


As root (or using sudo)

apt-get install spread libspread-perl

At least in Ubuntu 10.04 LTS, there is a problem with the package at the time of writing where the maintainer has specified the configuration file location incorrectly. Also, since the config file binds to localhost, you need to set the process name with the -n switch for it to run. If not it quits with an error message similar to:

[Tue 17 Aug 2010 14:59:41] Conf_init: My proc id (127.0.1.1) is not in configuration
 Exit caused by Alarm(EXIT)

There is a Ubuntu bug report, but here is a quick
rundown on how to fix this:

  • update /etc/init.d/spread

    change the line:
    DOPTIONS="-c /etc/spread.conf"
    
    to
    DOPTIONS="-c /etc/spread/spread.conf"
    
  • update the /etc/default/spread file to:

    # Change to enable spread
    ENABLED=1
    
    # Options, see spread.1 for list
    OPTIONS="-n localhost"
    
That should be that. You can now start the daemon with
/etc/init.d/spread start

Spread on Perl

The simplest demo I could create was as follows:
1 #!/usr/bin/perl
  2
  3 use strict;
  4 use warnings;
  5
  6 use Spread;
  7
  8 # connect
  9 my ( $mbox, $private_group ) = Spread::connect( {
 10         spread_name  => '4803@localhost',
 11         private_name => 'myname',
 12         group_membership => 0 # we don't want to hear who joins/leaves groups
 13         });
 14 die 'Unable to connect' unless (defined($mbox));
 15
 16 # join a group
 17 Spread::join($mbox, 'mygroup') or die 'Failed to join group';
 18
 19 # multicast message to group
 20 Spread::multicast( $mbox, AGREED_MESS, 'mygroup', 0, "this is your message" );
 21
 22 # poll for messages
 23 my ($messsize);
 24 while ($messsize = Spread::poll($mbox)) {
 25     print "--Next message: $messsize bytes\n";
 26     my ( $service_type, $sender, $groups, $mess_type, $endian, $message ) = Spread::receive($mbox);
 27     print "\tsender : $sender\n";
 28     print "\tgroups : " . join(',', @$groups) . "\n";
 29     print "\tmessage : [$message]\n";
 30 }
 31
 32 Spread::disconnect($mbox);
This should give you the following output:
--Next message: 100 bytes
        sender : #myname#localhost
        groups : mygroup
        message : [this is your message]
If you want to also have a look at the Message join/leave/etc messages, here's the same example slightly modified:
1 #!/usr/bin/perl
  2
  3 use strict;
  4 use warnings;
  5 use Data::Dumper;
  6 use Spread qw(:MESS);
  7
  8 my %types = (
  9     0x00000001 => 'UNRELIABLE_MESS',
 10     0x00000002 => 'RELIABLE_MESS',
 11     0x00000004 => 'FIFO_MESS',
 12     0x00000008 => 'CAUSAL_MESS',
 13     0x00000010 => 'AGREED_MESS',
 14     0x00000020 => 'SAFE_MESS',
 15     0x0000003f => 'REGULAR_MESS',
 16     0x00000040 => 'SELF_DISCARD',
 17     0x00000100 => 'CAUSED_BY_JOIN',
 18     0x00000200 => 'CAUSED_BY_LEAVE',
 19     0x00000400 => 'CAUSED_BY_DISCONNECT',
 20     0x00000800 => 'CAUSED_BY_NETWORK',
 21     0x00001000 => 'REG_MEMB_MESS',
 22     0x00002000 => 'TRANSITION_MESS',
 23     0x00003f00 => 'MEMBERSHIP_MESS',
 24     0x003fc000 => 'RESERVED',
 25     0x00400000 => 'REJECT_MESS',
 26     0x01000000 => 'DROP_RECV',
 27     0x80000080 => 'ENDIAN_RESERVED',
 28            );
 29
 30 # connect
 31 my ( $mbox, $private_group ) = Spread::connect( {
 32         spread_name  => '4803@localhost',
 33         private_name => 'myname',
 34         group_membership => 1
 35         });
 36 die 'Unable to connect' unless (defined($mbox));
 37
 38 # join a group
 39 Spread::join($mbox, 'mygroup') or die 'Failed to join group';
 40
 41 # multicast to group
 42 Spread::multicast( $mbox, AGREED_MESS, 'mygroup', 0, "this is your message" );
 43
 44 # Poll mailbox
 45 my ($messsize);
 46 while ($messsize = Spread::poll($mbox)) {
 47     print "--Next message: $messsize bytes\n";
 48     my ( $service_type, $sender, $groups, $mess_type, $endian, $message ) = Spread::receive($mbox);
 49     print "\tservice_type: $service_type (" .
 50         join('|', map { $types{$_} }  grep { $_ & $service_type } ( keys %types ) ) .
 51         ")\n";
 52     print "\tsender : $sender\n";
 53     print "\tgroups : " . Dumper($groups);
 54     print "\tmess_type : $mess_type\n";
 55     print "\tendian : $endian\n";
 56     $message =~ s/[^[:print:]]/./g;
 57     print "\tmessage : [$message]\n";
 58 }
 59
 60 Spread::disconnect($mbox);
Which outputs
--Next message: 228 bytes
        service_type: 4352 (MEMBERSHIP_MESS|REG_MEMB_MESS|CAUSED_BY_JOIN)
        sender : mygroup
        groups : $VAR1 = [
          '#myname#localhost'
        ];
        mess_type : 0
        endian :
        message : [......jL........#myname#localhost...............]
--Next message: 100 bytes
        service_type: 16 (REGULAR_MESS|AGREED_MESS)
        sender : #myname#localhost
        groups : $VAR1 = [
          'mygroup'
        ];
        mess_type : 0
        endian :
        message : [this is your message]

Note there is binary in the message returned, not handled by the Perl wrapper.

Have fun.

Sunday 2 May 2010

How to get Canon's Digital Photo Professional (dpp) to work under Linux

DPP can be made to work reasonably well under wine in Linux by using the version
under revision control, revert a patch, and apply another:

  1. Make sure you have git installed

    If you are running Debian you can do so with apt-get install git-core

  2. Get the build dependencies for wine.

    If you are using Debian, the simplest way is to add a sources list to /etc/apt/sources.list, and do:
    apt-get update
    apt-get build-dep wine
    

    I did not need everything for all the features, so I just installed some of these packages.
  3. Get wine from revision control:

    git clone git://source.winehq.org/git/wine.git wine-git
    

  4. Fix DPP wine issues

    The issues with DPP under wine are covered on http://appdb.winehq.org/, specifically, at the time of this writing: http://appdb.winehq.org/objectManager.php?sClass=version&iId=7813 Here you'll find problems and solutions. I only had 2 problems:

    12001 chemsketch won't display
    13344 DPP 3.4.1.1 - Images with "Fit to window" corrupted
     

    Follow the instructions on these pages to resolve the issues. For me, on git branch master 93f9c32, this was:

    git revert accfce21d3e042638a5eac8a8379eda2964fcd0a
    get http://www.winehq.org/pipermail/wine-patches/attachments/20100426/2c75de0d/attachment-0003.asc
    .. strip out just the first patch. Basically you want the bit starting with ---a/dlls/gdi32/dib.c till
    just before the next line starting with ---
    Save this as /tmp/patchfile, and then from the wine-git directory, do:
    cat /tmp/patchfile | patch -p1
    

    This should tell you it patched the file.

  5. Compile
    ./configure
    make
    

  6. Run from wine-git, or install system wide
    I have a script, called dpp, which checks for a locally modified wine. If it finds it under my home directory it runs dpp with that wine. This saves me from installing wine-git system wide:
    #!/bin/sh
    
    if [ -d /home/yourname/dl/w/wine-git ]
    then
            echo "Found locally compiled wine. Setting path."
            export PATH="/home/yourname/dl/w/wine-git:/home/yourname/dl/w/wine-git/tools$PATH"
    fi
    
    wine ~/.wine/drive_c/Program\ Files/Canon/Digital\ Photo\ Professional/DPPViewer.exe $1
    
    
    If you want to install wine system wide, do
    sudo make install
    

Friday 19 February 2010

New York 2009/10

These are some of the images from our visit to NY over new year.

Scenes of yellow cabs and street with mists rising from manhole covers reminisce of movies. It was cold and windy though ... so the mist was quickly blown away. I managed to get a shot or two of it though.





This was taken from The Top of the Rock, 30 Rockefeller Plaza.


A nice and grainy shot as we came up to the statue of liberty



Beautiful sky, leaving for Ellis Island



View from Ellis Island, towards Manhattan



Back on the boat



Whirlwind through the Museum of Natural History, and Central Park





Gold rush?




Dusk at the top of the Empire State



On the streets of New York, and under