fork of PCE focusing on macplus, supporting DaynaPort SCSI network emulation
1/*****************************************************************************
2 * pce *
3 *****************************************************************************/
4
5/*****************************************************************************
6 * File name: src/drivers/char/char-mouse.c *
7 * Created: 2011-10-15 by Hampa Hug <hampa@hampa.ch> *
8 * Copyright: (C) 2011-2019 Hampa Hug <hampa@hampa.ch> *
9 *****************************************************************************/
10
11/*****************************************************************************
12 * This program is free software. You can redistribute it and / or modify it *
13 * under the terms of the GNU General Public License version 2 as published *
14 * by the Free Software Foundation. *
15 * *
16 * This program is distributed in the hope that it will be useful, but *
17 * WITHOUT ANY WARRANTY, without even the implied warranty of *
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General *
19 * Public License for more details. *
20 *****************************************************************************/
21
22
23#include <stdlib.h>
24#include <stdio.h>
25#include <string.h>
26
27#include <drivers/options.h>
28#include <drivers/char/char.h>
29#include <drivers/char/char-mouse.h>
30
31
32#define MOUSE_MAX 8
33
34#define MOUSE_MS 0
35#define MOUSE_MSYS 1
36
37
38static unsigned mouse_cnt = 0;
39static char_mouse_t *mouse[MOUSE_MAX];
40
41
42static
43void chr_mouse_close (char_drv_t *cdrv)
44{
45 unsigned i, n;
46 char_mouse_t *drv;
47
48 drv = cdrv->ext;
49
50 n = 0;
51
52 for (i = 0; i < mouse_cnt; i++) {
53 if (mouse[i] != drv) {
54 mouse[n++] = mouse[i];
55 }
56 }
57
58 mouse_cnt = n;
59
60 free (drv);
61}
62
63static
64unsigned chr_mouse_get_buf_cnt (const char_mouse_t *drv)
65{
66 unsigned cnt;
67
68 cnt = (CHAR_MOUSE_BUF + drv->buf_hd - drv->buf_tl) % CHAR_MOUSE_BUF;
69
70 return (CHAR_MOUSE_BUF - cnt);
71}
72
73static
74void chr_mouse_add_val (char_mouse_t *drv, unsigned char val)
75{
76 drv->buf[drv->buf_hd] = val;
77 drv->buf_hd = (drv->buf_hd + 1) % CHAR_MOUSE_BUF;
78}
79
80static
81unsigned chr_mouse_get_val (int *val, int min, int max)
82{
83 unsigned ret;
84 int tmp;
85
86 tmp = *val;
87
88 if (tmp < min) {
89 tmp = min;
90 }
91 else if (tmp > max) {
92 tmp = max;
93 }
94
95 *val -= tmp;
96
97 if (tmp < 0) {
98 ret = -tmp;
99 ret = ~ret + 1;
100 }
101 else {
102 ret = tmp;
103 }
104
105 return (ret);
106}
107
108static
109void chr_mouse_add_packet_ms (char_mouse_t *drv)
110{
111 unsigned x, y, v;
112
113 if (chr_mouse_get_buf_cnt (drv) < 3) {
114 return;
115 }
116
117 x = chr_mouse_get_val (&drv->dx, -127, 127);
118 y = chr_mouse_get_val (&drv->dy, -127, 127);
119
120 v = 0x40;
121 v |= (drv->button & 0x01) ? 0x20 : 0x00;
122 v |= (drv->button & 0x02) ? 0x10 : 0x00;
123 v |= (y >> 4) & 0x0c;
124 v |= (x >> 6) & 0x03;
125
126 chr_mouse_add_val (drv, v);
127 chr_mouse_add_val (drv, x & 0x3f);
128 chr_mouse_add_val (drv, y & 0x3f);
129}
130
131static
132void chr_mouse_add_packet_msys (char_mouse_t *drv)
133{
134 unsigned i, v;
135
136 if (chr_mouse_get_buf_cnt (drv) < 5) {
137 return;
138 }
139
140 v = 0x80;
141 v |= (drv->button & 0x01) ? 0x00 : 0x04;
142 v |= (drv->button & 0x02) ? 0x00 : 0x01;
143 v |= (drv->button & 0x04) ? 0x00 : 0x02;
144
145 chr_mouse_add_val (drv, v);
146
147 for (i = 0; i < 2; i++) {
148 v = chr_mouse_get_val (&drv->dx, -127, 127);
149 chr_mouse_add_val (drv, v);
150
151 v = chr_mouse_get_val (&drv->dy, -127, 127);
152 chr_mouse_add_val (drv, ~v + 1);
153 }
154}
155
156static
157void chr_mouse_add_packet (char_mouse_t *drv)
158{
159 switch (drv->protocol) {
160 case MOUSE_MS:
161 chr_mouse_add_packet_ms (drv);
162 break;
163
164 case MOUSE_MSYS:
165 chr_mouse_add_packet_msys (drv);
166 break;
167 }
168}
169
170static
171void chr_mouse_set_drv (char_mouse_t *drv, int dx, int dy, unsigned button)
172{
173 int tx, ty;
174 unsigned tb;
175
176 tb = drv->button;
177
178 dx = drv->scale_x[0] * dx + drv->scale_x[2];
179 tx = dx;
180 dx = dx / drv->scale_x[1];
181 drv->scale_x[2] = tx - drv->scale_x[1] * dx;
182
183 dy = drv->scale_y[0] * dy + drv->scale_y[2];
184 ty = dy;
185 dy = dy / drv->scale_y[1];
186 drv->scale_y[2] = ty - drv->scale_y[1] * dy;
187
188 drv->dx += dx;
189 drv->dy += dy;
190 drv->button = button;
191
192 if ((tb ^ button) & 3) {
193 chr_mouse_add_packet (drv);
194 }
195}
196
197static
198unsigned chr_mouse_read (char_drv_t *cdrv, void *buf, unsigned cnt)
199{
200 unsigned i, n;
201 unsigned char *tmp;
202 char_mouse_t *drv;
203
204 drv = cdrv->ext;
205 tmp = buf;
206
207 if (drv->protocol == MOUSE_MS) {
208 if ((drv->dtr == 0) || (drv->rts == 0)) {
209 return (0);
210 }
211 }
212
213 if (drv->buf_hd == drv->buf_tl) {
214 if ((drv->dx != 0) || (drv->dy != 0)) {
215 chr_mouse_add_packet (drv);
216 }
217 }
218
219 if (drv->buf_hd == drv->buf_tl) {
220 return (0);
221 }
222
223 n = (drv->buf_hd - drv->buf_tl + CHAR_MOUSE_BUF) % CHAR_MOUSE_BUF;
224
225 if (n > cnt) {
226 n = cnt;
227 }
228
229 for (i = 0; i < n; i++) {
230 tmp[i] = drv->buf[drv->buf_tl];
231 drv->buf_tl = (drv->buf_tl + 1) % CHAR_MOUSE_BUF;
232 }
233
234 return (n);
235}
236
237static
238unsigned chr_mouse_write (char_drv_t *cdrv, const void *buf, unsigned cnt)
239{
240 return (cnt);
241}
242
243static
244int chr_mouse_get_ctl (char_drv_t *cdrv, unsigned *ctl)
245{
246 *ctl = PCE_CHAR_DSR | PCE_CHAR_CTS | PCE_CHAR_CD;
247
248 return (0);
249}
250
251static
252int chr_mouse_set_ctl (char_drv_t *cdrv, unsigned ctl)
253{
254 int dtr, rts;
255 char_mouse_t *drv;
256
257 drv = cdrv->ext;
258
259 dtr = (ctl & PCE_CHAR_DTR) != 0;
260 rts = (ctl & PCE_CHAR_RTS) != 0;
261
262 if (drv->protocol == MOUSE_MS) {
263 if (rts && dtr) {
264 if ((drv->dtr == 0) || (drv->rts == 0)) {
265 drv->dx = 0;
266 drv->dy = 0;
267 drv->scale_x[2] = 0;
268 drv->scale_y[2] = 0;
269
270 drv->buf_hd = 1;
271 drv->buf_tl = 0;
272 drv->buf[0] = 'M';
273 }
274 }
275 }
276
277 drv->dtr = dtr;
278 drv->rts = rts;
279
280 return (0);
281}
282
283static
284int chr_mouse_set_params (char_drv_t *cdrv, unsigned long bps, unsigned bpc, unsigned parity, unsigned stop)
285{
286 return (0);
287}
288
289static
290int chr_mouse_init (char_mouse_t *drv, const char *name)
291{
292 char *proto;
293
294 chr_init (&drv->cdrv, drv);
295
296 drv->cdrv.close = chr_mouse_close;
297 drv->cdrv.read = chr_mouse_read;
298 drv->cdrv.write = chr_mouse_write;
299 drv->cdrv.get_ctl = chr_mouse_get_ctl;
300 drv->cdrv.set_ctl = chr_mouse_set_ctl;
301 drv->cdrv.set_params = chr_mouse_set_params;
302
303 drv->protocol = MOUSE_MS;
304
305 drv->buf_hd = 0;
306 drv->buf_tl = 0;
307
308 drv->dtr = 0;
309 drv->rts = 0;
310
311 drv->dx = 0;
312 drv->dy = 0;
313 drv->button = 0;
314
315 proto = drv_get_option (name, "protocol");
316
317 if (proto != NULL) {
318 if (strcmp (proto, "microsoft") == 0) {
319 drv->protocol = MOUSE_MS;
320 }
321 else if (strcmp (proto, "msys") == 0) {
322 drv->protocol = MOUSE_MSYS;
323 }
324 else {
325 free (proto);
326 return (1);
327 }
328
329 free (proto);
330 }
331
332 drv->scale_x[0] = drv_get_option_sint (name, "xmul", 1);
333 drv->scale_x[1] = drv_get_option_sint (name, "xdiv", 1);
334 drv->scale_x[2] = 0;
335
336 if (drv->scale_x[1] == 0) {
337 drv->scale_x[1] = 1;
338 }
339
340 drv->scale_y[0] = drv_get_option_sint (name, "ymul", 1);
341 drv->scale_y[1] = drv_get_option_sint (name, "ydiv", 1);
342 drv->scale_y[2] = 0;
343
344 if (drv->scale_y[1] == 0) {
345 drv->scale_y[1] = 1;
346 }
347
348 if ((mouse_cnt + 1) < MOUSE_MAX) {
349 mouse[mouse_cnt++] = drv;
350 }
351
352 return (0);
353}
354
355void chr_mouse_set (int dx, int dy, unsigned button)
356{
357 unsigned i;
358
359 for (i = 0; i < mouse_cnt; i++) {
360 chr_mouse_set_drv (mouse[i], dx, dy, button);
361 }
362}
363
364char_drv_t *chr_mouse_open (const char *name)
365{
366 char_mouse_t *drv;
367
368 drv = malloc (sizeof (char_mouse_t));
369
370 if (drv == NULL) {
371 return (NULL);
372 }
373
374 if (chr_mouse_init (drv, name)) {
375 free (drv);
376 return (NULL);
377 }
378
379 return (&drv->cdrv);
380}