mirror of
https://github.com/gnif/LookingGlass.git
synced 2026-08-22 07:01:30 +00:00
[client] spice: move protocol into transport
This commit is contained in:
215
client/transports/SPICE/input.c
Normal file
215
client/transports/SPICE/input.c
Normal file
@@ -0,0 +1,215 @@
|
||||
/**
|
||||
* Looking Glass
|
||||
* Copyright © 2017-2026 The Looking Glass Authors
|
||||
* https://looking-glass.io
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the Free
|
||||
* Software Foundation; either version 2 of the License, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc., 59
|
||||
* Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include "input.h"
|
||||
|
||||
#include "kb.h"
|
||||
|
||||
#include "common/locking.h"
|
||||
|
||||
#include <purespice.h>
|
||||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
struct SpiceInput
|
||||
{
|
||||
LG_Lock stateLock;
|
||||
LG_Lock statusDispatch;
|
||||
|
||||
bool available;
|
||||
uint32_t statusGeneration;
|
||||
LG_InputStatusFn statusCallback;
|
||||
void * statusOpaque;
|
||||
};
|
||||
|
||||
static uint32_t nextGeneration(uint32_t generation)
|
||||
{
|
||||
if (++generation == 0)
|
||||
++generation;
|
||||
return generation;
|
||||
}
|
||||
|
||||
static bool spiceSupports(void * opaque, LG_InputSupport support)
|
||||
{
|
||||
(void)opaque;
|
||||
(void)support;
|
||||
return false;
|
||||
}
|
||||
|
||||
static void spiceSetStatusListener(void * opaque,
|
||||
LG_InputStatusFn callback, void * callbackOpaque)
|
||||
{
|
||||
SpiceInput * input = opaque;
|
||||
LG_LOCK(input->statusDispatch);
|
||||
|
||||
LG_LOCK(input->stateLock);
|
||||
input->statusCallback = callback;
|
||||
input->statusOpaque = callbackOpaque;
|
||||
const LG_InputStatus status =
|
||||
{
|
||||
.available = input->available,
|
||||
.generation = input->statusGeneration,
|
||||
};
|
||||
LG_UNLOCK(input->stateLock);
|
||||
|
||||
if (callback)
|
||||
callback(callbackOpaque, &status);
|
||||
LG_UNLOCK(input->statusDispatch);
|
||||
}
|
||||
|
||||
static bool spiceKeyDown(void * opaque, int key)
|
||||
{
|
||||
SpiceInput * input = opaque;
|
||||
const uint32_t ps2 = linux_to_ps2[key];
|
||||
|
||||
LG_LOCK(input->stateLock);
|
||||
const bool result = input->available &&
|
||||
(!ps2 || purespice_keyDown(ps2));
|
||||
LG_UNLOCK(input->stateLock);
|
||||
return result;
|
||||
}
|
||||
|
||||
static bool spiceKeyUp(void * opaque, int key)
|
||||
{
|
||||
SpiceInput * input = opaque;
|
||||
const uint32_t ps2 = linux_to_ps2[key];
|
||||
|
||||
LG_LOCK(input->stateLock);
|
||||
const bool result = !ps2 || purespice_keyUp(ps2);
|
||||
LG_UNLOCK(input->stateLock);
|
||||
return result;
|
||||
}
|
||||
|
||||
static bool spiceKeyboardLEDs(void * opaque, bool numLock, bool capsLock,
|
||||
bool scrollLock)
|
||||
{
|
||||
SpiceInput * input = opaque;
|
||||
const uint32_t modifiers =
|
||||
(scrollLock ? 1 /* SPICE_SCROLL_LOCK_MODIFIER */ : 0) |
|
||||
(numLock ? 2 /* SPICE_NUM_LOCK_MODIFIER */ : 0) |
|
||||
(capsLock ? 4 /* SPICE_CAPS_LOCK_MODIFIER */ : 0);
|
||||
|
||||
LG_LOCK(input->stateLock);
|
||||
const bool result = input->available &&
|
||||
purespice_keyModifiers(modifiers);
|
||||
LG_UNLOCK(input->stateLock);
|
||||
return result;
|
||||
}
|
||||
|
||||
static bool spiceMouseMotion(void * opaque, int32_t x, int32_t y)
|
||||
{
|
||||
SpiceInput * input = opaque;
|
||||
LG_LOCK(input->stateLock);
|
||||
const bool result = input->available && purespice_mouseMotion(x, y);
|
||||
LG_UNLOCK(input->stateLock);
|
||||
return result;
|
||||
}
|
||||
|
||||
static bool spiceMousePress(void * opaque, unsigned int button)
|
||||
{
|
||||
if (button > 7)
|
||||
return true;
|
||||
|
||||
SpiceInput * input = opaque;
|
||||
LG_LOCK(input->stateLock);
|
||||
const bool result = input->available && purespice_mousePress(button);
|
||||
LG_UNLOCK(input->stateLock);
|
||||
return result;
|
||||
}
|
||||
|
||||
static bool spiceMouseRelease(void * opaque, unsigned int button)
|
||||
{
|
||||
if (button > 7)
|
||||
return true;
|
||||
|
||||
SpiceInput * input = opaque;
|
||||
LG_LOCK(input->stateLock);
|
||||
const bool result = purespice_mouseRelease(button);
|
||||
LG_UNLOCK(input->stateLock);
|
||||
return result;
|
||||
}
|
||||
|
||||
static const LG_InputOps l_inputOps =
|
||||
{
|
||||
.name = "SPICE",
|
||||
.supports = spiceSupports,
|
||||
.setStatusListener = spiceSetStatusListener,
|
||||
.keyDown = spiceKeyDown,
|
||||
.keyUp = spiceKeyUp,
|
||||
.keyboardLEDs = spiceKeyboardLEDs,
|
||||
.mouseMotion = spiceMouseMotion,
|
||||
.mousePosition = NULL,
|
||||
.mousePress = spiceMousePress,
|
||||
.mouseRelease = spiceMouseRelease,
|
||||
.reset = NULL,
|
||||
};
|
||||
|
||||
bool spiceInput_init(SpiceInput ** input)
|
||||
{
|
||||
*input = calloc(1, sizeof(**input));
|
||||
if (!*input)
|
||||
return false;
|
||||
|
||||
LG_LOCK_INIT((*input)->stateLock);
|
||||
LG_LOCK_INIT((*input)->statusDispatch);
|
||||
return true;
|
||||
}
|
||||
|
||||
void spiceInput_free(SpiceInput ** input)
|
||||
{
|
||||
if (!input || !*input)
|
||||
return;
|
||||
|
||||
LG_LOCK_FREE((*input)->statusDispatch);
|
||||
LG_LOCK_FREE((*input)->stateLock);
|
||||
free(*input);
|
||||
*input = NULL;
|
||||
}
|
||||
|
||||
const LG_InputOps * spiceInput_getOps(void)
|
||||
{
|
||||
return &l_inputOps;
|
||||
}
|
||||
|
||||
void spiceInput_setAvailable(SpiceInput * input, bool available)
|
||||
{
|
||||
LG_LOCK(input->statusDispatch);
|
||||
LG_LOCK(input->stateLock);
|
||||
|
||||
const bool changed = input->available != available;
|
||||
if (changed)
|
||||
{
|
||||
input->available = available;
|
||||
input->statusGeneration = nextGeneration(input->statusGeneration);
|
||||
}
|
||||
|
||||
const LG_InputStatusFn callback = input->statusCallback;
|
||||
void * callbackOpaque = input->statusOpaque;
|
||||
const LG_InputStatus status =
|
||||
{
|
||||
.available = input->available,
|
||||
.generation = input->statusGeneration,
|
||||
};
|
||||
LG_UNLOCK(input->stateLock);
|
||||
|
||||
if (changed && callback)
|
||||
callback(callbackOpaque, &status);
|
||||
LG_UNLOCK(input->statusDispatch);
|
||||
}
|
||||
Reference in New Issue
Block a user