---
layout: ../Site.layout.js
---
# A minimal GUI keyboard display in [McCLIM](https://mcclim.common-lisp.dev/main.html) common lisp interface manager

<img src="../nicclim-v2-accelerators.png"><img src="../keyboard-defaults.png">

```
(defparameter *approximate-keyboard*
  '(((1) (2) (3) (4) (5) (6) (7)  (8)   (9)   (0))
    ((q) (w) (e) (r) (t) (y) (u)  (i)   (o)   (p))
    ((a) (s) (d) (f) (g) (h) (j)  (k)   (l)  (|;|))
    ((z) (x) (c) (v) (b) (n) (m) (|,|) (|.|) (|/|))))
```

In at least some cases of laptop keyboard, this is pretty close to what you've got alphanumerically; I expect one's fingers hang around some of these keys. It's going to be a little ugly but I wanted to do a quick keystrokes (i.e. shortcuts/hotkeys) display for my [NicCLIM map editor](/lispgames/trying-nicclim), which in its upcoming version 2 now has lots of keyboard accelerators as I guess we'll see in another  moment.

I guess you're reasonably set up so the next two lines make sense. Otherwise: [my lisp intro](/fundamental/installing-lisp-etc/), [McCLIM's git README](https://codeberg.org/McCLIM/McCLIM).

```
(require :mcclim)
(in-package :clim-user)
```

## An `application-frame` with that keyboard.

I figure it should go in a slot of the frame.

```
(define-application-frame key-frame ()
  ((keyboard :initarg :keyboard))
  (:pane :application :display-function 'display-keyboard)
  (:default-initargs
   :keyboard  '(((1) (2) (3) (4) (5) (6) (7)  (8)   (9)   (0))
		((q) (w) (e) (r) (t) (y) (u)  (i)   (o)   (p))
		((a) (s) (d) (f) (g) (h) (j)  (k)   (l)  (|;|))
		((z) (x) (c) (v) (b) (n) (m) (|,|) (|.|) (|/|)))))
```

## The `:display-function` `'display-keyboard`

```
(defun display-keyboard
    (frame pane)
  (with-slots
	(keyboard)
      frame
    (formatting-table
	(pane)
      (loop :for row :in keyboard :do
	(formatting-row
	    (pane)
	  (loop
	    :for cell :in row :do
	      (formatting-cell
		  (pane)
		(updating-output
		    (pane)
		  (surrounding-output-with-border
		      (pane)
		    (with-text-style
			(pane
			 (make-text-style :sans-serif :roman :tiny))
		      (loop 
			:for symbol :in cell
			:for hack := nil :then (fresh-line pane) :do
			  (present symbol 'symbol
				   :stream pane))))))))))))
```

## Look at that

<img src="../keyboard-defaults.png">

```
(find-application-frame 'key-frame)
```

<img src="../keyboard-full-screenshot.png">

Could be worse for the defaults.

## Changing the key text

So we absolutely do not want to deface the intuitive keyboard layout list. What I *have* is a list of keyboard accelerator associated commands. Since each keyboard key is unique, I guess we can just use `loop`..`nsubst`.

My new [nicclim](https://lispy-gopher-show.itch.io/nicclim) shortcuts (listen, I program experimentally)

```
(defparameter *v2-nicclim-shortcuts*
  '(((b) (c-s-b execute list))
    ((q) (c-s-q funcall))
    ((w) (c-s-w apply))
    ((e) (c-s-e gets))
    ((r) (c-s-r setsgets))
    ((t) (c-s-t change player))
    ((a) (c-s-a extract player))
    ((s) (c-s-s doas))
    ((d) (c-s-d doas list))
    ((c) (c-s-c rect union))
    ((z) (c-s-z rect intersection))
    ((x) (c-s-x rect difference))
    ((f) (c-s-f cur1 rotatef))
    ((v) (c-s-v note location))))
```


# Open the same frame with these changes [`nsubst`](http://www.lispworks.com/reference/HyperSpec/Body/f_substc.htm)ituted

<img src="../nicclim-v2-accelerators.png">

```
(find-application-frame
 'key-frame
 :keyboard
 (loop
   :with new-keyboard := (copy-list
			  *approximate-keyboard*)
   :for (old new) :in *v2-nicclim-shortcuts*
   :do
      (nsubst new old new-keyboard :test 'equal)
   :finally
      (return new-keyboard)))			
```

<img src="../nicclim-v2-accelerators-full-screen.png">

# Conclusion

I can't say we did anything profoundly deep, but it worked like I thought it would- first, the realistically laid out list datastructure (my friend [notptr](https://social.cyberia9.org/notes/abyc9k5qmhae058d) says they normally write their game maps like this in the first place, so at least someone does it), then using a keyboard arguement with [common lisp's `loop`](https://www.lispworks.com/documentation/HyperSpec/Body/m_loop.htm) and `nsubst` to add [keyboard accelerator](https://www.lispworks.com/documentation/lw80/clim/clim-ch11-2.htm) descriptions.

The [common lisp interface manager spec](http://bauhh.dyndns.org:8000/clim-spec/index.html)'s [dynamic table resizing](https://www.lispworks.com/documentation/lwu41/climuser/GUID_281.HTM#HEADING281-0) did what I hoped it would do. I am not contending I should win any particular awards for graphic design. Maybe you will.

If you want to *take the next step* with McCLIM because this simple example only whet your voracious appetite, the next thing to do is to make the table cells [sensitive-inferiors](https://www.lispworks.com/documentation/lw80/clim/clim-ch6-3.htm#CLIM) (when choosing a command for example).

# Fin.

Let's [get on the mastodon](https://gamerplus.org/@screwlisp/115105693171271215), as per usual please.

Oh, if you didn't attend live/listen already, the sbcl-powered biggest-ever cosmic string simulation done by the Tufts Supercomputer for their astrophysics department (interview with Ken Olum) really answers this question: "who actually uses common lisp these days?"  https://communitymedia.video/w/9kysH4ZwVuP4J4erZozqFT