30
$\begingroup$

I want to use this to add a keyboard shortcut to an undo function I wrote. The basic problem is the following:

I have a command, let's say x=1, and I want to run the command with a keyboard shortcut. Is there a way to do it?

Editing the KeyEventTranslation.tr file is what I tried.

Adding

Item[KeyEvent["z",Modifiers->{Command}],Evaluate[x=1]],

does not work.

Item[
 KeyEvent["z", Modifiers -> {Command}], 
  FrontEndExecute[{FrontEnd`NotebookWrite[FrontEnd`InputNotebook[],"x=1"]}]]

adds the text x=1 where the cursor is, but it still needs to be evaluated and I need to be at the right place with the cursor.

Are there other ways?

This might be related, but I couldn't get anything out of it so far.

$\endgroup$

1 Answer 1

27
$\begingroup$

Here are four approaches to setting up keyboard shortcuts. The last is the best!

AddMenuCommands

First examples using notebook manipulation, (as you tried):

This example adds a command to the Insert menu, with a key combination Control+U (normally the underline command). This addition just lasts for the session, but could be added to an init file.

FrontEndExecute[
 FrontEnd`AddMenuCommands["DuplicatePreviousOutput",
  {Delimiter, MenuItem["Evaluate x = 1",
    FrontEnd`KernelExecute[
     nb = SelectedNotebook[];
     SelectionMove[nb, After, Cell]; 
     NotebookWrite[nb, Cell[BoxData[RowBox[{"x", "=", "1"}]], "Input"]];
     SelectionMove[nb, Previous, Cell];
     SelectionEvaluate[nb]],
    MenuKey["u", Modifiers -> {"Control"}],
    System`MenuEvaluator -> Automatic]}]]

Note, you can find the box format like so:

ToBoxes[Hold[x = 1]]

Out = RowBox[{"Hold", "[", RowBox[{"x", "=", "1"}], "]"}]

This could also be done invisibly like this:

FrontEndExecute[
 FrontEnd`AddMenuCommands["DuplicatePreviousOutput",
  {Delimiter, MenuItem["Evaluate x = 1",
    FrontEnd`KernelExecute[
     nb = CreateDocument[Null, Visible -> False, WindowSelected -> True];
     NotebookWrite[nb, Cell[BoxData[RowBox[{"x", "=", "1"}]], "Input"]];
     SelectionMove[nb, Previous, Cell];
     SelectionEvaluate[nb];
     NotebookClose[nb]],
    MenuKey["u", Modifiers -> {"Control"}],
    System`MenuEvaluator -> Automatic]}]]

A quicker version just uses ToExpression, (not Evaluate, as you first tried):

FrontEndExecute[
 FrontEnd`AddMenuCommands["DuplicatePreviousOutput",
  {Delimiter, MenuItem["Evaluate x = 1",
    FrontEnd`KernelExecute[ToExpression["x=1;"]],
    MenuKey["u", Modifiers -> {"Control"}],
    System`MenuEvaluator -> Automatic]}]]

KeyEventTranslations

The notebook manipulation can be implemented in KeyEventTranslations.tr like so:

Item[KeyEvent["u", Modifiers -> {Control}], FrontEndExecute[
  FrontEnd`SelectionMove[FrontEnd`InputNotebook[], After, Cell];
  FrontEnd`NotebookWrite[FrontEnd`InputNotebook[], 
    Cell[BoxData[RowBox[{"x", "=", "1"}]], "Input"]];
  FrontEnd`SelectionMove[FrontEnd`InputNotebook[], Previous, Cell];
  FrontEnd`SelectionEvaluate[FrontEnd`InputNotebook[]]]]

NotebookEventActions

Another approach for adding a keyboard shortcut is this:

function[] := x = 1

SetOptions[SelectedNotebook[],
 NotebookEventActions -> {"DownArrowKeyDown" :> function[]}]

Setting notebook event actions to command or control key combinations does not appear to be possible. A shifted key assignment can be made, e.g. Shift+O (just capital "o"):

NotebookEventActions -> {{"KeyDown", "O"} :> ...

You can replace SelectedNotebook[] with $FrontEnd (note 'Details') - that adds the assignment to your front end init file. (To undo, you would need to edit the init file to remove the event assignment.)

MenuSetup

Finally -- and this is probably the most obvious -- place x = 1; in a file called assign.m and call it from a menu item specified in MenuSetup.tr with:

Item["Evaluate x = 1",
 KernelExecute[Get["assign.m", Path -> "C:\\Users\\chrisd\\Documents"]]]],
 MenuKey["u", Modifiers->{"Control"}], MenuEvaluator->Automatic]

Alternatively, use ToExpression:

Item["Evaluate x = 1", KernelExecute[ToExpression["x=1;"]],
 MenuKey["u", Modifiers -> {"Control"}], MenuEvaluator -> Automatic]
$\endgroup$
6
  • $\begingroup$ Very nice. That definitely works. Perfect would be to not add any text to the notebook. I like that there is no need to edit any system files. $\endgroup$
    – jens_bo
    Commented Dec 12, 2012 at 12:40
  • $\begingroup$ @jenson_bo - I added a second AddMenuCommands variation which doesn't leave any text in the input notebook. $\endgroup$ Commented Dec 12, 2012 at 13:43
  • $\begingroup$ Great answer, I tried the invisible option, it works, but since I am using the notebooks name in the assigned function creating a new document seems to be a problem. I will try the last option later. Thanks. Once the keyboard shortcuts work in a nice way, I think my layman's undo/version control is presentable - but of course can be improved even more. $\endgroup$
    – jens_bo
    Commented Dec 12, 2012 at 14:30
  • 1
    $\begingroup$ @jenson_bo - In the first version, you could delete the created cell like so: NotebookWrite[nb, Cell[BoxData[RowBox[{RowBox[{"x", "=", "1"}], ";"}]], "Input"]]; SelectionMove[nb, Previous, Cell]; SelectionEvaluate[nb]; SelectionMove[nb, Previous, Cell]; NotebookDelete[nb] $\endgroup$ Commented Dec 12, 2012 at 14:48
  • $\begingroup$ @ Chris Degnen - SelectionMove[nb, Previous, Cell]; NotebookDelete[nb] That does the trick I think. :) $\endgroup$
    – jens_bo
    Commented Dec 12, 2012 at 14:55

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.