4

I created a java frame with seesaw

(def f (frame :title "my app"))

and I would like to catch user keypress.

I tried to gather code here and there and ended with this

(ns myapp.core
  (:use seesaw.core)
  (:use seesaw.font)
  (:import [java.awt.event ActionListener KeyListener KeyEvent])
)

(defn input-listener []
(proxy [ActionListener KeyListener] []
  (actionPerformed [e])
  (keyPressed [e] (alert e "You pressed a key!"))
  (keyReleased [e])
  (keyTyped [e])))

(doto f
  (.addKeyListener (input-listener)))

but it won't work at all. I am new to clojure and since I absolutely don't know anything JAVA (and don't really want to ding into it) I am a bit lost. Is there a simple way to catch user input for keyboard shortcuts in the whole app ?

help please.

sai
  • 75
  • 7

4 Answers4

4

If you'd just like to map specific key presses to different functions in a frame, seesaw.keymap/map-key is probably what you want:

; When 'e' is pressed in frame f, call this function
(map-key f "e" (fn [_] (... do something ))

(this is all built on top of the keybinding stuff @Bill references)

Take a look at the docs for map-key for more info. As the other answers have alluded to, keyboard handling in Swing is even nastier than the rest of Swing so be ready for some pain :)

Dave Ray
  • 39,616
  • 7
  • 83
  • 82
  • Thank you, I think this is what I need but I had already tried to look at how to use the function and was lost. I tried your code but it doesn't work (event if I add the missing parenthesis at the end). I get a "unable to resolve symbol in this context". Should I import something? I get a "Could not locate seesaw/keymap__init." if I try to import seesaw.keymap. – sai Nov 15 '12 at 06:27
  • I have updated to clojure 1.4 and seesaw 1.4, and it worked with the following code (it seems you need to write the letter in caps, but that doesn't mean it grabs shift-E... looks strange) : (map-key f "E" (fn [_] (alert "You pressed E"))) – sai Nov 15 '12 at 06:57
  • Yes. Swing's key binding stuff doesn't really interpret key state at all, so "E" means the "E" key, not the character "E". You'd have to have a handler for "shift E" if you wanted that. – Dave Ray Nov 15 '12 at 15:38
  • ... and just to be clear, this is only intended for handling key bindings for stuff like hot-keys (ctrl-C, ctrl-V, etc). If you're doing something like an editor that takes general character input, @JohnJ's `:key-pressed` example is probably what you want. – Dave Ray Nov 15 '12 at 15:40
  • I am not doing an editor, just a game with actions defined by a key (like a roguelike) so I guess this may do the job ^^ – sai Nov 16 '12 at 05:26
3

Seesaw is great, but it can still be a bit tricky to find how to do what you want, particularly if (like me) you're not a Swing expert. Usually breaking into the Java API isn't needed, particularly for something this simple. Here's what worked for me:

(ns so.core
  (:use seesaw.core))

(let [f (frame :title "my app")
      handler (fn [e] (alert "pressed key!"))]
  (listen f :key-pressed handler)
  (show! f))

Unfortunately this nice Seesaw tutorial doesn't have a keypress example -- would be good to add.

JohnJ
  • 4,753
  • 2
  • 28
  • 40
  • Excellent! It works! I have indeed started with this tutorial. How could I have found myself this keybowrd input listening feature? I have looked at the API but maybe not enough? By the way, the tutorial uses Pack! Show!. How should I modify your code so it would fit there. By the way if you could give me a way to get the character typed and process it, or point me to ressource to learn how this works it would get me started enough. – sai Nov 15 '12 at 05:31
  • Q1: In this case, I read the Seesaw source for `listen`, having used a click handler in the past and figuring there would be a similar idiom for a key press. – JohnJ Nov 15 '12 at 13:31
  • 1
    Q2: you could put (pack! f) before (show!) - is that what you're asking? Q3: to see what key was pressed, you can (.getKeyCode e). – JohnJ Nov 15 '12 at 13:33
  • Thank you very much I will test a bit more with this and the key-map thing and use the more apropriate ^^ – sai Nov 16 '12 at 05:29
3

If you want to globally intercept keys in a swing application, you need a KeyEventDispatcher, which you would register through the KeyboardFocusManager. If you want to add actions based on keys to specific components (much higher level - much better), you probably want KeyBindings http://docs.oracle.com/javase/tutorial/uiswing/misc/keybinding.html

Before you learn seesaw though, you want to understand a little bit of swing. The Java Trail is a good place to start. http://docs.oracle.com/javase/tutorial/uiswing/index.html

BillRobertson42
  • 12,602
  • 4
  • 40
  • 57
0

You got an e in your call to alert that doesn't really belong there. Should work without it. Good luck with trying to use Clojure without learning Java, I don't think it's going to work out on the long run but it'd be nice if it did.

Cubic
  • 14,902
  • 5
  • 47
  • 92
  • I have deleted the 'e' but it still doesn't work. With experience I may get to deal more and more with Java but I am still struggling with the clojure syntax at the time... – sai Nov 14 '12 at 10:23