]> asedeno.scripts.mit.edu Git - PuTTY.git/blob - sercfg.c
Add a keyboard shortcut for the "serial" protocol to the GUI.
[PuTTY.git] / sercfg.c
1 /*
2  * sercfg.c - the serial-port specific parts of the PuTTY
3  * configuration box. Centralised as cross-platform code because
4  * more than one platform will want to use it, but not part of the
5  * main configuration. The expectation is that each platform's
6  * local config function will call out to ser_setup_config_box() if
7  * it needs to set up the standard serial stuff. (Of course, it can
8  * then apply local tweaks after ser_setup_config_box() returns, if
9  * it needs to.)
10  */
11
12 #include <assert.h>
13 #include <stdlib.h>
14
15 #include "putty.h"
16 #include "dialog.h"
17 #include "storage.h"
18
19 static void serial_parity_handler(union control *ctrl, void *dlg,
20                                   void *data, int event)
21 {
22     static const struct {
23         const char *name;
24         int val;
25     } parities[] = {
26         {"None", SER_PAR_NONE},
27         {"Odd", SER_PAR_ODD},
28         {"Even", SER_PAR_EVEN},
29         {"Mark", SER_PAR_MARK},
30         {"Space", SER_PAR_SPACE},
31     };
32     int mask = ctrl->listbox.context.i;
33     int i, j;
34     Config *cfg = (Config *)data;
35
36     if (event == EVENT_REFRESH) {
37         int oldparity = cfg->serparity;/* preserve past reentrant calls */
38         dlg_update_start(ctrl, dlg);
39         dlg_listbox_clear(ctrl, dlg);
40         for (i = 0; i < lenof(parities); i++)  {
41             if (mask & (1 << i))
42                 dlg_listbox_addwithid(ctrl, dlg, parities[i].name,
43                                       parities[i].val);
44         }
45         for (i = j = 0; i < lenof(parities); i++) {
46             if (mask & (1 << i)) {
47                 if (oldparity == parities[i].val) {
48                     dlg_listbox_select(ctrl, dlg, j);
49                     break;
50                 }
51                 j++;
52             }
53         }
54         if (i == lenof(parities)) {    /* an unsupported setting was chosen */
55             dlg_listbox_select(ctrl, dlg, 0);
56             oldparity = SER_PAR_NONE;
57         }
58         dlg_update_done(ctrl, dlg);
59         cfg->serparity = oldparity;    /* restore */
60     } else if (event == EVENT_SELCHANGE) {
61         int i = dlg_listbox_index(ctrl, dlg);
62         if (i < 0)
63             i = SER_PAR_NONE;
64         else
65             i = dlg_listbox_getid(ctrl, dlg, i);
66         cfg->serparity = i;
67     }
68 }
69
70 static void serial_flow_handler(union control *ctrl, void *dlg,
71                                 void *data, int event)
72 {
73     static const struct {
74         const char *name;
75         int val;
76     } flows[] = {
77         {"None", SER_FLOW_NONE},
78         {"XON/XOFF", SER_FLOW_XONXOFF},
79         {"RTS/CTS", SER_FLOW_RTSCTS},
80         {"DSR/DTR", SER_FLOW_DSRDTR},
81     };
82     int mask = ctrl->listbox.context.i;
83     int i, j;
84     Config *cfg = (Config *)data;
85
86     if (event == EVENT_REFRESH) {
87         int oldflow = cfg->serflow;    /* preserve past reentrant calls */
88         dlg_update_start(ctrl, dlg);
89         dlg_listbox_clear(ctrl, dlg);
90         for (i = 0; i < lenof(flows); i++)  {
91             if (mask & (1 << i))
92                 dlg_listbox_addwithid(ctrl, dlg, flows[i].name, flows[i].val);
93         }
94         for (i = j = 0; i < lenof(flows); i++) {
95             if (mask & (1 << i)) {
96                 if (oldflow == flows[i].val) {
97                     dlg_listbox_select(ctrl, dlg, j);
98                     break;
99                 }
100                 j++;
101             }
102         }
103         if (i == lenof(flows)) {       /* an unsupported setting was chosen */
104             dlg_listbox_select(ctrl, dlg, 0);
105             oldflow = SER_FLOW_NONE;
106         }
107         dlg_update_done(ctrl, dlg);
108         cfg->serflow = oldflow;        /* restore */
109     } else if (event == EVENT_SELCHANGE) {
110         int i = dlg_listbox_index(ctrl, dlg);
111         if (i < 0)
112             i = SER_FLOW_NONE;
113         else
114             i = dlg_listbox_getid(ctrl, dlg, i);
115         cfg->serflow = i;
116     }
117 }
118
119 void ser_setup_config_box(struct controlbox *b, int midsession,
120                           int parity_mask, int flow_mask)
121 {
122     struct controlset *s;
123     union control *c;
124
125     if (!midsession) {
126         int i;
127         extern void config_protocolbuttons_handler(union control *, void *,
128                                                    void *, int);
129
130         /*
131          * Add the serial back end to the protocols list at the
132          * top of the config box.
133          */
134         s = ctrl_getset(b, "Session", "hostport",
135                         "Specify the destination you want to connect to");
136
137         for (i = 0; i < s->ncontrols; i++) {
138             c = s->ctrls[i];
139             if (c->generic.type == CTRL_RADIO &&
140                 c->generic.handler == config_protocolbuttons_handler) {
141                 c->radio.nbuttons++;
142                 c->radio.ncolumns++;
143                 c->radio.buttons =
144                     sresize(c->radio.buttons, c->radio.nbuttons, char *);
145                 c->radio.buttons[c->radio.nbuttons-1] =
146                     dupstr("Serial");
147                 c->radio.buttondata =
148                     sresize(c->radio.buttondata, c->radio.nbuttons, intorptr);
149                 c->radio.buttondata[c->radio.nbuttons-1] = I(PROT_SERIAL);
150                 if (c->radio.shortcuts) {
151                     c->radio.shortcuts =
152                         sresize(c->radio.shortcuts, c->radio.nbuttons, char);
153                     c->radio.shortcuts[c->radio.nbuttons-1] = 'r';
154                 }
155             }
156         }
157     }
158
159     /*
160      * Entirely new Connection/Serial panel for serial port
161      * configuration.
162      */
163     ctrl_settitle(b, "Connection/Serial",
164                   "Options controlling local serial lines");
165
166     if (!midsession) {
167         /*
168          * We don't permit switching to a different serial port in
169          * midflight, although we do allow all other
170          * reconfiguration.
171          */
172         s = ctrl_getset(b, "Connection/Serial", "serline",
173                         "Select a serial line");
174         ctrl_editbox(s, "Serial line to connect to", 'l', 40,
175                      HELPCTX(serial_line),
176                      dlg_stdeditbox_handler, I(offsetof(Config,serline)),
177                      I(sizeof(((Config *)0)->serline)));
178     }
179
180     s = ctrl_getset(b, "Connection/Serial", "sercfg", "Configure the serial line");
181     ctrl_editbox(s, "Speed (baud)", 's', 40,
182                  HELPCTX(serial_speed),
183                  dlg_stdeditbox_handler, I(offsetof(Config,serspeed)), I(-1));
184     ctrl_editbox(s, "Data bits", 'b', 40,
185                  HELPCTX(serial_databits),
186                  dlg_stdeditbox_handler,I(offsetof(Config,serdatabits)),I(-1));
187     /*
188      * Stop bits come in units of one half.
189      */
190     ctrl_editbox(s, "Stop bits", 't', 40,
191                  HELPCTX(serial_stopbits),
192                  dlg_stdeditbox_handler,I(offsetof(Config,serstopbits)),I(-2));
193     ctrl_droplist(s, "Parity", 'p', 40,
194                   HELPCTX(serial_parity),
195                   serial_parity_handler, I(parity_mask));
196     ctrl_droplist(s, "Flow control", 'f', 40,
197                   HELPCTX(serial_flow),
198                   serial_flow_handler, I(flow_mask));
199 }