30

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.

jens_bo
  • 1,804
  • 17
  • 16

1 Answers1

27

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]
Chris Degnen
  • 30,927
  • 2
  • 54
  • 108
  • 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. – jens_bo Dec 12 '12 at 12:40
  • @jenson_bo - I added a second AddMenuCommands variation which doesn't leave any text in the input notebook. – Chris Degnen Dec 12 '12 at 13:43
  • 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. – jens_bo Dec 12 '12 at 14:30
  • 1
    @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] – Chris Degnen Dec 12 '12 at 14:48
  • @ Chris Degnen - SelectionMove[nb, Previous, Cell]; NotebookDelete[nb] That does the trick I think. :) – jens_bo Dec 12 '12 at 14:55
  • I have not tried this yet but there is also https://mathematica.stackexchange.com/questions/16165/how-can-i-set-a-keyboard-shortcut-to-run-a-command for adding a menu item – userrandrand Apr 16 '23 at 11:14