test
This commit is contained in:
parent
76997a60a1
commit
900210eeb7
4
app.go
4
app.go
@ -63,3 +63,7 @@ func (a *App) LoadGames() []models.Game {
|
|||||||
games = provider.GetConjureGameInfo()
|
games = provider.GetConjureGameInfo()
|
||||||
return games
|
return games
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (a *App) LoadImage(gameId string, imageSrc string) provider.FileBlob {
|
||||||
|
return *provider.LoadImage(gameId, imageSrc)
|
||||||
|
}
|
||||||
|
|||||||
31
frontend/src/components/GameCard.vue
Normal file
31
frontend/src/components/GameCard.vue
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
<template>
|
||||||
|
<div
|
||||||
|
:key="game.Id"
|
||||||
|
:class="[
|
||||||
|
'transition-transform transform cursor-pointer rounded-lg overflow-hidden border-4',
|
||||||
|
selected ? 'scale-110 border-blue-500' : 'scale-100 border-transparent'
|
||||||
|
]"
|
||||||
|
>
|
||||||
|
<LocalImage
|
||||||
|
:src="game.ThumbnailPath"
|
||||||
|
class="h-32 w-48 object-cover"
|
||||||
|
:alt="game.Game"
|
||||||
|
:key="game.Id"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { models } from "../../wailsjs/go/models";
|
||||||
|
import Game = models.Game;
|
||||||
|
import LocalImage from "./LocalImage.vue";
|
||||||
|
|
||||||
|
defineProps<{
|
||||||
|
game: Game
|
||||||
|
selected: boolean
|
||||||
|
}>()
|
||||||
|
</script>
|
||||||
@ -2,21 +2,12 @@
|
|||||||
<div class="relative h-[170px]">
|
<div class="relative h-[170px]">
|
||||||
<Transition :name="`carousel-${direction}`" mode="out-in">
|
<Transition :name="`carousel-${direction}`" mode="out-in">
|
||||||
<div :key="selectedTag" class="w-full py-4 px-6 flex overflow-x-auto space-x-4 items-end transition-inner">
|
<div :key="selectedTag" class="w-full py-4 px-6 flex overflow-x-auto space-x-4 items-end transition-inner">
|
||||||
<div
|
<GameCard
|
||||||
v-for="game in games"
|
v-for="game in games"
|
||||||
:key="game.Id"
|
:game="game"
|
||||||
|
:selected="game.Id === selectedGame?.Id"
|
||||||
@click="$emit('selectGame', game)"
|
@click="$emit('selectGame', game)"
|
||||||
:class="[
|
/>
|
||||||
'transition-transform transform cursor-pointer rounded-lg overflow-hidden border-4',
|
|
||||||
game.Id === selectedGame.Id ? 'scale-110 border-blue-500' : 'scale-100 border-transparent'
|
|
||||||
]"
|
|
||||||
>
|
|
||||||
<img
|
|
||||||
:src="game.ThumbnailPath"
|
|
||||||
class="h-32 w-48 object-cover"
|
|
||||||
:alt="game.Game"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
<!-- Give the whole carousel a key based on selectedTag to trigger transition -->
|
<!-- Give the whole carousel a key based on selectedTag to trigger transition -->
|
||||||
<!-- <div :key="selectedTag" class="flex gap-4 w-full transition-inner">-->
|
<!-- <div :key="selectedTag" class="flex gap-4 w-full transition-inner">-->
|
||||||
@ -36,6 +27,7 @@
|
|||||||
|
|
||||||
import { models } from "../../wailsjs/go/models";
|
import { models } from "../../wailsjs/go/models";
|
||||||
import Game = models.Game;
|
import Game = models.Game;
|
||||||
|
import GameCard from "./GameCard.vue";
|
||||||
|
|
||||||
defineProps<{
|
defineProps<{
|
||||||
games: Game[],
|
games: Game[],
|
||||||
|
|||||||
29
frontend/src/components/LocalImage.vue
Normal file
29
frontend/src/components/LocalImage.vue
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
<template>
|
||||||
|
<img
|
||||||
|
:src="blobUrl"
|
||||||
|
:alt="alt"
|
||||||
|
>
|
||||||
|
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { ref, watch } from "vue";
|
||||||
|
import { ImageManager } from "../utils/image-manager";
|
||||||
|
|
||||||
|
defineProps<{
|
||||||
|
key: string
|
||||||
|
src: string
|
||||||
|
alt: string
|
||||||
|
}>()
|
||||||
|
|
||||||
|
const blobUrl = ref<string | null>(null);
|
||||||
|
|
||||||
|
watch(() => props.imageUrl, async (newUrl) => {
|
||||||
|
blobUrl.value = await ImageManager.getBlob(key, newUrl);
|
||||||
|
}, { immediate: true });
|
||||||
|
|
||||||
|
console.log(src)
|
||||||
|
</script>
|
||||||
21
frontend/src/utils/image-manager.ts
Normal file
21
frontend/src/utils/image-manager.ts
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
import {LoadImage} from "../../wailsjs/go/main/App";
|
||||||
|
import * as path from "node:path";
|
||||||
|
|
||||||
|
export class ImageManager {
|
||||||
|
|
||||||
|
static Dictionary: {[key: string]: string} = {}
|
||||||
|
|
||||||
|
public static async getImage(gameId: string, src: string): Promise<string> {
|
||||||
|
const id = path.join(gameId, src);
|
||||||
|
if (this.Dictionary[id])
|
||||||
|
return this.Dictionary[id]
|
||||||
|
|
||||||
|
const fileBlob = await LoadImage(gameId, src);
|
||||||
|
const bytes = new Uint8Array(fileBlob.Data);
|
||||||
|
const blob = new Blob([bytes], {type: fileBlob.MimeType });
|
||||||
|
const url = URL.createObjectURL(blob);
|
||||||
|
this.Dictionary[id] = url
|
||||||
|
return url;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
3
frontend/wailsjs/go/main/App.d.ts
vendored
3
frontend/wailsjs/go/main/App.d.ts
vendored
@ -1,7 +1,10 @@
|
|||||||
// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL
|
// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL
|
||||||
// This file is automatically generated. DO NOT EDIT
|
// This file is automatically generated. DO NOT EDIT
|
||||||
import {models} from '../models';
|
import {models} from '../models';
|
||||||
|
import {provider} from '../models';
|
||||||
|
|
||||||
export function LoadGames():Promise<Array<models.Game>>;
|
export function LoadGames():Promise<Array<models.Game>>;
|
||||||
|
|
||||||
|
export function LoadImage(arg1:string,arg2:string):Promise<provider.FileBlob>;
|
||||||
|
|
||||||
export function StartGame(arg1:string):Promise<void>;
|
export function StartGame(arg1:string):Promise<void>;
|
||||||
|
|||||||
@ -6,6 +6,10 @@ export function LoadGames() {
|
|||||||
return window['go']['main']['App']['LoadGames']();
|
return window['go']['main']['App']['LoadGames']();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function LoadImage(arg1, arg2) {
|
||||||
|
return window['go']['main']['App']['LoadImage'](arg1, arg2);
|
||||||
|
}
|
||||||
|
|
||||||
export function StartGame(arg1) {
|
export function StartGame(arg1) {
|
||||||
return window['go']['main']['App']['StartGame'](arg1);
|
return window['go']['main']['App']['StartGame'](arg1);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -45,3 +45,24 @@ export namespace models {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export namespace provider {
|
||||||
|
|
||||||
|
export class FileBlob {
|
||||||
|
Name: string;
|
||||||
|
MimeType: string;
|
||||||
|
Data: number[];
|
||||||
|
|
||||||
|
static createFrom(source: any = {}) {
|
||||||
|
return new FileBlob(source);
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor(source: any = {}) {
|
||||||
|
if ('string' === typeof source) source = JSON.parse(source);
|
||||||
|
this.Name = source["Name"];
|
||||||
|
this.MimeType = source["MimeType"];
|
||||||
|
this.Data = source["Data"];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|||||||
0
frontend/wailsjs/runtime/package.json
Normal file → Executable file
0
frontend/wailsjs/runtime/package.json
Normal file → Executable file
0
frontend/wailsjs/runtime/runtime.d.ts
vendored
Normal file → Executable file
0
frontend/wailsjs/runtime/runtime.d.ts
vendored
Normal file → Executable file
0
frontend/wailsjs/runtime/runtime.js
Normal file → Executable file
0
frontend/wailsjs/runtime/runtime.js
Normal file → Executable file
1
go.mod
1
go.mod
@ -5,6 +5,7 @@ go 1.22.0
|
|||||||
toolchain go1.23.5
|
toolchain go1.23.5
|
||||||
|
|
||||||
require (
|
require (
|
||||||
|
github.com/karalabe/hid v1.0.0
|
||||||
github.com/wailsapp/wails/v2 v2.9.2
|
github.com/wailsapp/wails/v2 v2.9.2
|
||||||
gopkg.in/yaml.v3 v3.0.1
|
gopkg.in/yaml.v3 v3.0.1
|
||||||
)
|
)
|
||||||
|
|||||||
2
go.sum
2
go.sum
@ -11,6 +11,8 @@ github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
|
|||||||
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||||
github.com/jchv/go-winloader v0.0.0-20210711035445-715c2860da7e h1:Q3+PugElBCf4PFpxhErSzU3/PY5sFL5Z6rfv4AbGAck=
|
github.com/jchv/go-winloader v0.0.0-20210711035445-715c2860da7e h1:Q3+PugElBCf4PFpxhErSzU3/PY5sFL5Z6rfv4AbGAck=
|
||||||
github.com/jchv/go-winloader v0.0.0-20210711035445-715c2860da7e/go.mod h1:alcuEEnZsY1WQsagKhZDsoPCRoOijYqhZvPwLG0kzVs=
|
github.com/jchv/go-winloader v0.0.0-20210711035445-715c2860da7e/go.mod h1:alcuEEnZsY1WQsagKhZDsoPCRoOijYqhZvPwLG0kzVs=
|
||||||
|
github.com/karalabe/hid v1.0.0 h1:+/CIMNXhSU/zIJgnIvBD2nKHxS/bnRHhhs9xBryLpPo=
|
||||||
|
github.com/karalabe/hid v1.0.0/go.mod h1:Vr51f8rUOLYrfrWDFlV12GGQgM5AT8sVh+2fY4MPeu8=
|
||||||
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
|
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
|
||||||
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
|
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
|
||||||
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
|
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
|
||||||
|
|||||||
@ -1,10 +1,9 @@
|
|||||||
package inputs
|
package inputs
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/binary"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
|
||||||
"time"
|
"github.com/karalabe/hid"
|
||||||
)
|
)
|
||||||
|
|
||||||
type JoystickEvent struct {
|
type JoystickEvent struct {
|
||||||
@ -21,29 +20,84 @@ const (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func Start() {
|
func Start() {
|
||||||
// Open the joystick device file
|
return
|
||||||
file, err := os.Open("/dev/input/js0")
|
fmt.Println("Opening devices")
|
||||||
if err != nil {
|
const vendorID = 0x0079
|
||||||
fmt.Println("Error opening joystick:", err)
|
const productID = 0x0006
|
||||||
|
|
||||||
|
// Enumerate all matching devices
|
||||||
|
devices := hid.Enumerate(vendorID, productID)
|
||||||
|
if len(devices) == 0 {
|
||||||
|
fmt.Printf("Device with VID:PID %04X:%04X not found", vendorID, productID)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
defer file.Close()
|
|
||||||
|
|
||||||
// Continuously read joystick events
|
for _, d := range devices {
|
||||||
|
fmt.Printf("Found: %s - VID:%04X PID:%04X\n", d.Product, d.VendorID, d.ProductID)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Open the first matching device
|
||||||
|
device, err := devices[0].Open()
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("Failed to open device: %v", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer device.Close()
|
||||||
|
|
||||||
|
fmt.Println("Reading data... Press Ctrl+C to exit")
|
||||||
|
|
||||||
|
buf := make([]byte, 32) // Adjust size if needed
|
||||||
for {
|
for {
|
||||||
var e JoystickEvent
|
_, err := device.Read(buf)
|
||||||
err := binary.Read(file, binary.LittleEndian, &e)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println("Error reading joystick event:", err)
|
fmt.Printf("Read error: %v", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle the event
|
// For debugging: print raw data
|
||||||
handleJoystickEvent(e)
|
// fmt.Printf("Raw: % X\n", buf[:n])
|
||||||
|
|
||||||
// Sleep to avoid flooding output
|
// Example: decode joystick + button state
|
||||||
time.Sleep(10 * time.Millisecond)
|
x := buf[0] // Horizontal axis (0–255)
|
||||||
|
y := buf[1] // Vertical axis (0–255)
|
||||||
|
buttons := buf[6] // Buttons as bitfield
|
||||||
|
|
||||||
|
// fmt.Printf("Joystick X: %d, Y: %d, Buttons: %08b\n", x, y, buttons)
|
||||||
|
|
||||||
|
if buttons != 0 {
|
||||||
|
fmt.Printf("Button was pressed! %d\n", buttons)
|
||||||
|
}
|
||||||
|
|
||||||
|
if x != 127 || y != 127 {
|
||||||
|
fmt.Printf("Joystick moved! %d - %d\n", x, y)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fmt.Println("Out")
|
||||||
|
|
||||||
|
// Open the joystick device file
|
||||||
|
// file, err := os.Open("/dev/input/js0")
|
||||||
|
// if err != nil {
|
||||||
|
// fmt.Println("Error opening joystick:", err)
|
||||||
|
// return
|
||||||
|
// }
|
||||||
|
// defer file.Close()
|
||||||
|
|
||||||
|
// // Continuously read joystick events
|
||||||
|
// for {
|
||||||
|
// var e JoystickEvent
|
||||||
|
// err := binary.Read(file, binary.LittleEndian, &e)
|
||||||
|
// if err != nil {
|
||||||
|
// fmt.Println("Error reading joystick event:", err)
|
||||||
|
// return
|
||||||
|
// }
|
||||||
|
|
||||||
|
// // Handle the event
|
||||||
|
// handleJoystickEvent(e)
|
||||||
|
|
||||||
|
// // Sleep to avoid flooding output
|
||||||
|
// time.Sleep(10 * time.Millisecond)
|
||||||
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
// handleJoystickEvent processes joystick events.
|
// handleJoystickEvent processes joystick events.
|
||||||
|
|||||||
53
lib/provider/file-provider.go
Normal file
53
lib/provider/file-provider.go
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
package provider
|
||||||
|
|
||||||
|
import (
|
||||||
|
"conjure-os/lib/config"
|
||||||
|
"mime"
|
||||||
|
"net/http"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
)
|
||||||
|
|
||||||
|
func LoadImage(gameId string, imageSrc string) *FileBlob {
|
||||||
|
imagePath := filepath.Join(config.GetDefaultConjureGamesDirectory(), gameId, imageSrc)
|
||||||
|
blob, err := GetFileBlob(imagePath)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return blob
|
||||||
|
}
|
||||||
|
|
||||||
|
type FileBlob struct {
|
||||||
|
Name string
|
||||||
|
MimeType string
|
||||||
|
Data []byte
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetFileBlob(path string) (*FileBlob, error) {
|
||||||
|
data, err := os.ReadFile(path)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Try to guess MIME type from content
|
||||||
|
mimeType := http.DetectContentType(data)
|
||||||
|
|
||||||
|
// Fallback to extension-based detection
|
||||||
|
if mimeType == "application/octet-stream" {
|
||||||
|
ext := filepath.Ext(path)
|
||||||
|
if ext != "" {
|
||||||
|
if t := mime.TypeByExtension(ext); t != "" {
|
||||||
|
mimeType = t
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
name := filepath.Base(path)
|
||||||
|
|
||||||
|
return &FileBlob{
|
||||||
|
Name: name,
|
||||||
|
MimeType: mimeType,
|
||||||
|
Data: data,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
@ -206,8 +206,6 @@ func GetConjureGameInfo() []models.Game {
|
|||||||
metadata, err := io.ReadAll(rc)
|
metadata, err := io.ReadAll(rc)
|
||||||
game := parseGameInfo([]byte(escapeBackslashes(string(metadata))))
|
game := parseGameInfo([]byte(escapeBackslashes(string(metadata))))
|
||||||
fmt.Println(game.ThumbnailPath)
|
fmt.Println(game.ThumbnailPath)
|
||||||
game.ThumbnailPath = filepath.Join(conjBase, game.ThumbnailPath)
|
|
||||||
game.ImagePath = filepath.Join(conjBase, game.ImagePath)
|
|
||||||
games = append(games, game)
|
games = append(games, game)
|
||||||
check(err)
|
check(err)
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user