#!/bin/bash

### Enter the Tiger: Enter Key Remapper for OS X 10.4.x
### by Michael 'Curby' Lee
### v0.00.00, 2007-02-17

###   Description
#
#  Remaps the Enter key, located betweeh the Right-Command key and
#  the Left Arrow key on Apple laptop computers, to a modifier key
#  of your choice.  Errs on the side of caustion and performs tests 
#  to warn the user of possible trouble.
#

###   Usage
#
#  EnterTheTiger.sh <desired_key> [plist_file]
#
#  Desired key can be:
#    command              Command/Apple key
#    shift                Shift key
#    option               Alt/Option key
#    control              Control key
#    enter                Enter key (revert to OS X default)
#    fdelete              Forward delete
#
#  Optionally, specify the file to be modified.
#  By default, the script modifies the system's plist file.
#

###   License
#
#  Copyright (C) 2007  Michael Lee <kirbysdl@hotmail.com>
#
#  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 2
#  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, write to the Free Software
#  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
#

defaulttarget="/System/Library/Extensions/AppleADBKeyboard.kext/Contents/Info.plist"
expected='<string>0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D,0x0E,0x0F,0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1A,0x1B,0x1C,0x1D,0x1E,0x1F,0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x29,0x2A,0x2B,0x2C,0x2D,0x2E,0x2F,0x30,0x31,0x32,0x33,0x..,0x35,0x3B,0x37,0x38,0x39,0x3A,0x7B,0x7C,0x7D,0x7E,0x3F,0x40,0x41,0x42,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4A,0x4B,0x4C,0x4D,0x4E,0x4F,0x50,0x51,0x52,0x53,0x54,0x55,0x56,0x57,0x58,0x59,0x5A,0x5B,0x5C,0x5D,0x5E,0x5F,0x60,0x61,0x62,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6A,0x6B,0x6C,0x6D,0x6E,0x6F,0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7A,0x3C,0x3D,0x3E,0x36,0x7F</string>'
expectedkey="ADBVirtualKeys"
expectedsed="\(<string>0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D,0x0E,0x0F,0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1A,0x1B,0x1C,0x1D,0x1E,0x1F,0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x29,0x2A,0x2B,0x2C,0x2D,0x2E,0x2F,0x30,0x31,0x32,0x33,0x\)..\(,0x35,0x3B,0x37,0x38,0x39,0x3A,0x7B,0x7C,0x7D,0x7E,0x3F,0x40,0x41,0x42,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4A,0x4B,0x4C,0x4D,0x4E,0x4F,0x50,0x51,0x52,0x53,0x54,0x55,0x56,0x57,0x58,0x59,0x5A,0x5B,0x5C,0x5D,0x5E,0x5F,0x60,0x61,0x62,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6A,0x6B,0x6C,0x6D,0x6E,0x6F,0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7A,0x3C,0x3D,0x3E,0x36,0x7F<\/string>\)"
md5command="e1803532d2d6489628ebc3ff6ce748f2"
md5shift="19df5527158953b6943de8fe80ad1057"
md5option="3a07ef447cb03954ea86f4644edf5cd1"
md5control="f0090cbe1a5129588b7a34de47b7a0e4"
md5fdelete="7c9ceecd624848740787d0dcedf429bb"
md5enter="610d8fb9cf309cf50e74518b5eff00a9"


# Sanity check inputs
if [[ "$#" != 2 && "$#" != 1 ]]; then
  echo "Usage: $0 desired_key [plist_file]"
  echo "See script for additional usage information"
  exit 1
fi

if [[ "$#" -eq 2 ]]; then
  target=$2
else
  target=$defaulttarget
fi

newkey=$1
case "$newkey" in
  'enter'   ) keycode="34" ;;
  'command' ) keycode="37" ;;
  'shift'   ) keycode="38" ;;
  'option'  ) keycode="3A" ;;
  'control' ) keycode="3B" ;;
  'fdelete' ) keycode="75" ;;
  *         ) echo "Usage: $0 desired_key [plist_file]"
              echo "See script for additional usage information"
              exit ;;
esac
echo "new key is $newkey, keycode $keycode (OK)"

if [[ -f "$target" ]]; then
  echo "$target exists (OK)"
else
  echo "ERROR: $target not found"
  exit 2
fi

if [[ `grep -c "$expected" $target` == 1 ]]; then
  echo "target line found (OK)"
else
  echo "problem finding target line, expected one unique line, got "`grep -c "$expected" $target`
  exit 3
fi

if grep -B 1 $expected $target | grep -q $expectedkey; then
  echo "target line's key is $expectedkey (OK)"
else
  echo "target key mismatch"
  exit 4
fi

# Sanity check platform
machine=$(system_profiler SPHardwareDataType | grep -i '^ *Machine Name.*book')
if [[ $? -eq 0 ]]; then
  echo "$machine (OK)" | sed 's/^ *//'
else
  echo WARNING: hardware might not be correct. Expecting macbook/powerbook/ibook
fi

OS=$(system_profiler SPSoftwareDataType | grep -i '^ *System Version:.*10\.4\.')
if [[ $? -eq 0 ]]; then
  echo "$OS (OK)" | sed 's/^ *//'
else
  echo WARNING: software might not be correct. Expecting Mac OS X 10.4.x.  Older versions should try uControl.  Newer versions may be incompatible.
fi

plutil $target
if [[ $? -ne 0 ]]; then
  echo "ERROR: Syntax error in original file"
  exit 6
fi
if [[ "z$(grep -A 1 $expectedkey $target | md5sum | awk '{print $1}')" == "z$(eval echo \$md5$newkey)" ]]; then
  echo NOTICE: Change has already been applied!  Quitting without changes...
  exit 0
fi

# Sanity check permissions/create backup
cp $target $target.backup 2> /dev/null
if [[ $? -eq 0 ]]; then
  echo "backup created (OK)"
else
  echo "ERROR: could not create backup file.  Perhaps you need administrator priveleges?  Try 'sudo'"
  exit 5
fi

# md5sums before
echo File checksums before:
md5sum $target $target.backup
echo

# Edit the target file
echo Editing file...
sed -i '' 's/'$expectedsed'/\1'$keycode'\2/' $target
echo

# Final checks
echo -n 'Checking syntax: '
plutil $target
if [[ $? -ne 0 ]]; then
  echo "Problem detected"
  echo "Restoring from backup"
  cp $target.backup $target
fi

echo File checksums after:
md5sum $target $target.backup

if [[ "z$(grep -A 1 $expectedkey $target | md5sum | awk '{print $1}')" == "z$(eval echo \$md5$newkey)" ]]; then
  rm /System/Library/Extensions.mkext
  rm /System/Library/Extensions.kextcache
  touch /System/Library/Extensions
  touch /System/Library/Extensions/AppleADBKeyboard.kext
  echo The edit appears to have been successful.  You should reboot to apply the changes.  Note that the first reboot may take longer than usual.
else
  echo The edit was not successful.  Most likely, there was another change already made to the target line, and this script did not attempt to make further changes.
fi
